From 1a72d2c246e3861a3b90d6172cb2f51466dbd5f8 Mon Sep 17 00:00:00 2001 From: Brian Searls Date: Mon, 22 Jun 2026 17:56:07 +0000 Subject: [PATCH] =?UTF-8?q?Ban=20source=20comments=20=E2=80=94=20dsl/extde?= =?UTF-8?q?ps=20.dag=20(pure=20deletion)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Strip all // line and /* */ block comments from dsl/extdeps/**/*.dag via the shared single-authority string-literal-aware stripper (scripts/strip_dag_comments.py), preserving //-in-string/URL/char literals. Deletion-only, no logic changes. DESIGN §6: the mark on the carrier (the model/data) is the authority; a source comment is the parallel-ledger doc to delete (git history is the backup). §2: no dual representation. extdeps cited-authority anchors are read structurally from the extdeps_external_authority_anchor data node, not the comment, so anchor citation comments are safe to delete. Verified green by execution: dual-root compile-clean (gunbc compile --source-root src/v2 --source-root dsl --target rust) yields only the 2 pre-existing baseline negative-fixture errors (layering_scan plant.dag), no regressions. Co-Authored-By: Claude Opus 4.8 (1M context) --- dsl/extdeps/access/aws_iam.dag | 49 ++-- dsl/extdeps/access/posix.dag | 40 +--- dsl/extdeps/access/rbac.dag | 32 +-- dsl/extdeps/access/zanzibar.dag | 30 --- dsl/extdeps/audit/cloudevents.dag | 23 -- dsl/extdeps/bmc.dag | 5 - dsl/extdeps/bmc/http.dag | 31 +-- dsl/extdeps/bmc/openbmc.dag | 30 --- dsl/extdeps/bmc/redfish.dag | 13 -- dsl/extdeps/bmc/types.dag | 33 --- dsl/extdeps/boards/asrock_rack.dag | 12 - dsl/extdeps/boot/emit.dag | 9 - dsl/extdeps/boot/framebuffer.dag | 7 - dsl/extdeps/boot/freestanding_payload.dag | 8 - dsl/extdeps/boot/freestanding_witness.dag | 5 - dsl/extdeps/boot/linux_x86_boot.dag | 12 - dsl/extdeps/browser/browser.dag | 43 +--- dsl/extdeps/cache/buildbuddy.dag | 7 +- dsl/extdeps/cache/cache.dag | 11 +- dsl/extdeps/cache/cargo.dag | 8 +- dsl/extdeps/cache/catalog_io.dag | 4 - dsl/extdeps/cache/catalog_placement.dag | 4 - dsl/extdeps/cache/github_actions.dag | 8 +- dsl/extdeps/cache/key_completeness.dag | 26 --- dsl/extdeps/cache/rustup.dag | 6 +- dsl/extdeps/cache/sccache.dag | 9 +- dsl/extdeps/cache/types.dag | 35 --- dsl/extdeps/clock/clock.dag | 16 -- dsl/extdeps/cloud/cloud.dag | 33 --- dsl/extdeps/cloud/gcp/errors.dag | 8 - dsl/extdeps/cloud/gcp/gcp.dag | 75 +----- dsl/extdeps/cloud/gcp/iam.dag | 36 +-- dsl/extdeps/cloud/gcp/mock_corpus.dag | 45 ---- dsl/extdeps/cloud/gcp/secret_manager.dag | 44 +--- dsl/extdeps/cloud/gcp/sts.dag | 56 +---- dsl/extdeps/cloud/hetzner.dag | 12 - dsl/extdeps/communication/medium.dag | 67 ------ .../container/oci/ctrl_session_witness.dag | 11 - dsl/extdeps/container/oci/descriptor.dag | 5 - dsl/extdeps/container/oci/image_config.dag | 6 - dsl/extdeps/container/oci/linux.dag | 5 - dsl/extdeps/container/oci/manifest.dag | 5 - dsl/extdeps/container/oci/media_types.dag | 5 - dsl/extdeps/container/oci/runtime_config.dag | 5 - dsl/extdeps/container/oci/types.dag | 13 -- dsl/extdeps/cpu.dag | 6 - dsl/extdeps/cpu/ampere.dag | 10 - dsl/extdeps/cpu/types.dag | 21 +- dsl/extdeps/cron/cron.dag | 16 -- dsl/extdeps/cron/mock_corpus.dag | 24 -- dsl/extdeps/cron/schedule_model.dag | 61 ----- dsl/extdeps/diagnostic/edac.dag | 9 - dsl/extdeps/diagnostic/ipmi.dag | 11 - dsl/extdeps/diagnostic/mock_corpus.dag | 31 --- dsl/extdeps/diagnostic/ssh.dag | 11 - dsl/extdeps/docker/docker.dag | 43 +--- dsl/extdeps/external_authority.dag | 16 -- dsl/extdeps/filesystem/filesystem_io.dag | 32 +-- dsl/extdeps/filesystem/mock_corpus.dag | 25 -- dsl/extdeps/filesystem/ntfs.dag | 26 +-- dsl/extdeps/filesystem/posix.dag | 29 +-- dsl/extdeps/formats/elf/encode.dag | 5 - .../formats/elf/hello_static_witness.dag | 14 -- dsl/extdeps/formats/elf/primitives.dag | 15 -- dsl/extdeps/formats/elf/relocation.dag | 10 - dsl/extdeps/formats/elf/sections.dag | 7 - dsl/extdeps/formats/elf/segments.dag | 4 - dsl/extdeps/formats/elf/types.dag | 5 - dsl/extdeps/formats/yaml.dag | 23 -- dsl/extdeps/git/git.dag | 58 +---- dsl/extdeps/git/gitignore.dag | 12 - dsl/extdeps/git/gitignore_render.dag | 6 - dsl/extdeps/git/mock_corpus.dag | 24 -- dsl/extdeps/git/object_store.dag | 46 ---- dsl/extdeps/git/versioning.dag | 29 --- dsl/extdeps/github/actions.dag | 154 +------------ dsl/extdeps/github/auth.dag | 10 - dsl/extdeps/github/ci.dag | 37 --- dsl/extdeps/github/errors.dag | 5 - dsl/extdeps/github/expressions.dag | 152 +----------- dsl/extdeps/github/gists.dag | 23 +- dsl/extdeps/github/github.dag | 28 --- dsl/extdeps/github/log_annotations.dag | 20 +- dsl/extdeps/github/mock_corpus.dag | 23 -- dsl/extdeps/github/pulls.dag | 46 +--- dsl/extdeps/gunbc/gunbc.dag | 30 +-- dsl/extdeps/hardware.dag | 14 -- dsl/extdeps/http/server.dag | 45 ---- dsl/extdeps/languages/bash/program.dag | 86 +------ dsl/extdeps/languages/dag/emit.dag | 17 -- dsl/extdeps/languages/dag/syntax.dag | 43 ---- dsl/extdeps/languages/dag/types.dag | 11 - dsl/extdeps/languages/go/emit.dag | 46 ---- dsl/extdeps/languages/go/module.dag | 151 +----------- dsl/extdeps/languages/go/primitives.dag | 114 +-------- dsl/extdeps/languages/go/syntax.dag | 14 -- dsl/extdeps/languages/go/types.dag | 83 +------ dsl/extdeps/languages/markdown.dag | 205 +++------------- dsl/extdeps/languages/python/emit.dag | 52 ----- dsl/extdeps/languages/python/primitives.dag | 186 --------------- dsl/extdeps/languages/python/syntax.dag | 22 +- dsl/extdeps/languages/python/types.dag | 72 ------ dsl/extdeps/languages/rust/emit.dag | 104 ++------- dsl/extdeps/languages/rust/primitives.dag | 218 +----------------- dsl/extdeps/languages/rust/syntax.dag | 18 -- dsl/extdeps/languages/rust/types.dag | 144 +----------- dsl/extdeps/llm/anthropic.dag | 133 +---------- dsl/extdeps/llm/anthropic_errors.dag | 7 - dsl/extdeps/llm/anthropic_rest.dag | 18 +- dsl/extdeps/llm/cli.dag | 35 --- dsl/extdeps/llm/llm.dag | 14 -- dsl/extdeps/llm/mock_corpus.dag | 31 --- dsl/extdeps/llm/openai.dag | 108 --------- dsl/extdeps/llm/openai_errors.dag | 5 - dsl/extdeps/llm/openai_rest.dag | 14 +- dsl/extdeps/memory.dag | 7 - dsl/extdeps/memory/jedec.dag | 15 -- dsl/extdeps/memory/sk_hynix.dag | 27 +-- dsl/extdeps/memory/types.dag | 117 +--------- .../object_storage/content_addressed.dag | 21 -- dsl/extdeps/object_storage/object_storage.dag | 26 --- dsl/extdeps/os/macos.dag | 8 +- dsl/extdeps/os/os.dag | 3 - dsl/extdeps/os/ubuntu.dag | 4 - dsl/extdeps/os/windows.dag | 4 - dsl/extdeps/package_managers/apt.dag | 48 +--- dsl/extdeps/package_managers/brew.dag | 43 +--- dsl/extdeps/realization/cache_purity.dag | 40 +--- dsl/extdeps/realization/hermetic_fixture.dag | 45 +--- dsl/extdeps/realization/parse_table_memo.dag | 11 +- dsl/extdeps/realization/resolved_graph.dag | 15 +- dsl/extdeps/realization/v1_handler.dag | 13 -- dsl/extdeps/render/ansi.dag | 13 -- dsl/extdeps/render/ascii_glyph.dag | 7 - dsl/extdeps/render/emoji_glyph.dag | 6 - dsl/extdeps/render/glyphs.dag | 22 +- dsl/extdeps/render/terminal.dag | 8 - dsl/extdeps/render/tier_glyphs.dag | 5 - dsl/extdeps/render/unicode_glyph.dag | 9 - dsl/extdeps/runtime/abi/aapcs64.dag | 17 -- dsl/extdeps/runtime/abi/sysv_amd64.dag | 17 -- dsl/extdeps/runtime/api/darwin.dag | 11 - dsl/extdeps/runtime/api/windows.dag | 23 -- .../runtime/architecture/aarch64_linux.dag | 11 - .../runtime/architecture/x86_64_linux.dag | 11 - dsl/extdeps/runtime/local.dag | 2 - dsl/extdeps/runtime/syscalls/linux.dag | 7 - dsl/extdeps/rust/cargo.dag | 67 ------ dsl/extdeps/rust/cargo_build.dag | 23 +- dsl/extdeps/rust/rustup.dag | 39 ---- dsl/extdeps/rust/version.dag | 23 -- dsl/extdeps/shell/credentials.dag | 17 -- dsl/extdeps/shell/gnu_coreutils.dag | 43 ---- dsl/extdeps/shell/mock_corpus.dag | 32 --- dsl/extdeps/shell/shell.dag | 35 +-- dsl/extdeps/sql/migration.dag | 30 +-- dsl/extdeps/test/http_pilot.dag | 12 +- dsl/extdeps/test/mock_corpus.dag | 23 -- .../toolchain/architecture_profile.dag | 15 +- dsl/extdeps/toolchain/types.dag | 11 - dsl/extdeps/tools/tools.dag | 56 ----- dsl/extdeps/transports/fidelity.dag | 26 --- dsl/extdeps/transports/file.dag | 17 +- dsl/extdeps/transports/rest.dag | 29 +-- dsl/extdeps/transports/shell.dag | 34 +-- dsl/extdeps/transports/sql.dag | 36 +-- dsl/extdeps/uri.dag | 21 -- dsl/extdeps/vendor.dag | 18 -- dsl/extdeps/vendor/amd.dag | 2 - dsl/extdeps/vendor/ampere.dag | 2 - dsl/extdeps/vendor/apple.dag | 2 - dsl/extdeps/vendor/arm.dag | 2 - dsl/extdeps/vendor/intel.dag | 2 - dsl/extdeps/vendor/nvidia.dag | 2 - dsl/extdeps/vendor/qualcomm.dag | 2 - dsl/extdeps/vendor/sk_hynix.dag | 2 - dsl/extdeps/version.dag | 28 --- dsl/extdeps/version/pep440.dag | 70 +----- dsl/extdeps/version/semver.dag | 24 +- 179 files changed, 239 insertions(+), 5236 deletions(-) diff --git a/dsl/extdeps/access/aws_iam.dag b/dsl/extdeps/access/aws_iam.dag index 940d755b2c2..f78f213ca6e 100644 --- a/dsl/extdeps/access/aws_iam.dag +++ b/dsl/extdeps/access/aws_iam.dag @@ -1,23 +1,9 @@ -// extdeps/access/aws_iam.dag -- "What is AWS IAM (policy language)?" -// -// AWS Identity and Access Management JSON policy documents: a list of statements, each granting -// or denying actions on resources for principals, optionally conditioned. Faithful model of the -// policy grammar, keeping its real element names. -// -// Source: AWS IAM JSON policy grammar, policy language version "2012-10-17". -// https://docs.aws.amazon.com/IAM/latest/UserGuide/reference_policies_grammar.html -// -// One of several access-control systems in extdeps/access; the std abstraction is derived from -// their commonality and validated against each (DESIGN §3), not re-coined from one. - module extdeps.access.aws_iam import std.types { NonEmptyStr } import extdeps.external_authority { ExternalAuthority } import extdeps.uri { Uri, Https } -// External-authority anchor (promotes the Source citation above to the structured carrier -// that v2.lens.extdeps_external_authority gates on — DESIGN §3). data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { uri: Uri { scheme: Https @@ -29,35 +15,30 @@ type Effect = Allow | Deny -// The Principal element (resource-based policies): "*" (anyone) or specific AWS/service/federated -// identities. (IAM also has the dual NotPrincipal; modeled as the negated form when present.) type Principal - = AnyPrincipal // "Principal": "*" - | AwsPrincipal { arns: List } // "AWS": [arn ...] - | ServicePrincipal { services: List } // "Service": [...] - | FederatedPrincipal { providers: List } // "Federated": [...] - | CanonicalUserPrincipal { ids: List } // "CanonicalUser": [...] + = AnyPrincipal + | AwsPrincipal { arns: List } + | ServicePrincipal { services: List } + | FederatedPrincipal { providers: List } + | CanonicalUserPrincipal { ids: List } -// One Condition entry: operator -> key -> values, e.g. StringEquals { "aws:username": ["alice"] }. type ConditionEntry { - operator: NonEmptyStr // e.g. "StringEquals", "IpAddress", "DateGreaterThan", "Bool" - key: NonEmptyStr // e.g. "aws:SourceIp", "s3:prefix", "aws:username" + operator: NonEmptyStr + key: NonEmptyStr values: List } -// A statement. Exactly one of action/not_action and resource/not_resource is used in real IAM; -// here `actions`/`resources` carry the positive form and `*` is a legal token. type Statement { - sid: NonEmptyStr? // optional "Sid" + sid: NonEmptyStr? effect: Effect - principal: Principal? // present in resource-based policies - actions: List // "Action": ["s3:GetObject", "*"] - resources: List // "Resource": [arn ...] - conditions: List // "Condition" block (empty = unconditional) + principal: Principal? + actions: List + resources: List + conditions: List } type PolicyDocument { - version: NonEmptyStr // "2012-10-17" - id: NonEmptyStr? // optional "Id" - statements: List // "Statement": [...] + version: NonEmptyStr + id: NonEmptyStr? + statements: List } diff --git a/dsl/extdeps/access/posix.dag b/dsl/extdeps/access/posix.dag index 829c6f19580..3e95434463a 100644 --- a/dsl/extdeps/access/posix.dag +++ b/dsl/extdeps/access/posix.dag @@ -1,23 +1,8 @@ -// extdeps/access/posix.dag -- "What are POSIX file permissions?" -// -// The classic discretionary file-permission model: read/write/execute bits for three classes -// (owner / group / other), plus the setuid / setgid / sticky special bits, over a file owned by -// a numeric user id and group id. Faithful model of the mode bits. -// -// Source: POSIX.1-2017 (IEEE Std 1003.1-2017), file mode bits (S_IRWXU/G/O, S_ISUID/ISGID/ISVTX); -// `chmod` permission model. -// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_stat.h.html -// -// One of several access-control systems in extdeps/access; the std abstraction is derived from -// their commonality and validated against each (DESIGN §3), not re-coined from one. - module extdeps.access.posix import extdeps.external_authority { ExternalAuthority } import extdeps.uri { Uri, Https } -// External-authority anchor (promotes the Source citation above to the structured carrier -// that v2.lens.extdeps_external_authority gates on — DESIGN §3). data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { uri: Uri { scheme: Https @@ -25,27 +10,24 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// The three permission bits applied per class (e.g. S_IRUSR / S_IWUSR / S_IXUSR for the owner). type PermissionBits { - read: Bool // r - write: Bool // w - execute: Bool // x (search, for directories) + read: Bool + write: Bool + execute: Bool } -// A file's mode: the three classes plus the special bits. type FileMode { - owner: PermissionBits // user class (S_IRWXU) - group: PermissionBits // group class (S_IRWXG) - other: PermissionBits // other class (S_IRWXO) - setuid: Bool // S_ISUID — execute as the file's owner - setgid: Bool // S_ISGID — execute as the file's group / dir group inheritance - sticky: Bool // S_ISVTX — restricted deletion (e.g. /tmp) + owner: PermissionBits + group: PermissionBits + other: PermissionBits + setuid: Bool + setgid: Bool + sticky: Bool } -// The owning identities the mode's classes resolve against. type FileOwnership { - uid: Int // owning user id - gid: Int // owning group id + uid: Int + gid: Int } type FilePermissions { diff --git a/dsl/extdeps/access/rbac.dag b/dsl/extdeps/access/rbac.dag index 1594639e50e..ca5683dde6c 100644 --- a/dsl/extdeps/access/rbac.dag +++ b/dsl/extdeps/access/rbac.dag @@ -1,24 +1,9 @@ -// extdeps/access/rbac.dag -- "What is (NIST) Role-Based Access Control?" -// -// Permissions are assigned to roles, roles to users; a senior role inherits a junior role's -// permissions (role hierarchy); a session activates a subset of a user's roles. Faithful model -// of Core + Hierarchical RBAC, keeping the standard's relation names (UA, PA, RH, PRMS = OPS×OBS). -// -// Source: ANSI INCITS 359-2004, "Role Based Access Control" (Ferraiolo, Sandhu, Gavrila, Kuhn, -// Chandramouli) — the NIST RBAC standard. -// https://csrc.nist.gov/projects/role-based-access-control -// -// One of several access-control systems in extdeps/access; the std abstraction is derived from -// their commonality and validated against each (DESIGN §3), not re-coined from one. - module extdeps.access.rbac import std.types { NonEmptyStr } import extdeps.external_authority { ExternalAuthority } import extdeps.uri { Uri, Https } -// External-authority anchor (promotes the Source citation above to the structured carrier -// that v2.lens.extdeps_external_authority gates on — DESIGN §3). data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { uri: Uri { scheme: Https @@ -26,42 +11,35 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// PRMS ⊆ OPS × OBS — a permission is an operation on an object. type Permission { - operation: NonEmptyStr // OPS, e.g. "read", "write", "approve" - object: NonEmptyStr // OBS, e.g. a resource name + operation: NonEmptyStr + object: NonEmptyStr } -// UA ⊆ USERS × ROLES — a user is assigned a role. type UserAssignment { user: NonEmptyStr role: NonEmptyStr } -// PA ⊆ PRMS × ROLES — a permission is assigned to a role. type PermissionAssignment { permission: Permission role: NonEmptyStr } -// RH ⊆ ROLES × ROLES (a partial order): `senior` inherits the permissions of `junior`. type RoleInheritance { senior: NonEmptyStr junior: NonEmptyStr } -// SESSIONS / session_roles — a session activates a subset of a user's authorized roles. type Session { user: NonEmptyStr active_roles: List } -// A full Core+Hierarchical RBAC policy. (Constrained RBAC adds SSD/DSD separation-of-duty -// constraints — omitted here; this is the assignment core the std abstraction is derived from.) type RbacPolicy { users: List roles: List - user_assignments: List // UA - permission_assignments: List // PA - role_hierarchy: List // RH + user_assignments: List + permission_assignments: List + role_hierarchy: List } diff --git a/dsl/extdeps/access/zanzibar.dag b/dsl/extdeps/access/zanzibar.dag index b6c8489308d..5cce0062bcf 100644 --- a/dsl/extdeps/access/zanzibar.dag +++ b/dsl/extdeps/access/zanzibar.dag @@ -1,25 +1,9 @@ -// extdeps/access/zanzibar.dag -- "What is Zanzibar?" -// -// Google's global authorization system: a relation-tuple data model plus a per-namespace -// userset-rewrite configuration. Faithful model of the data model + config language in the -// paper (§2), keeping its real names. -// -// Source: Ruoming Pang, Ramón Cáceres, Mike Burrows, et al., "Zanzibar: Google's Consistent, -// Global Authorization System," 2019 USENIX Annual Technical Conference (USENIX ATC '19). -// https://www.usenix.org/conference/atc19/presentation/pang -// -// One of several access-control systems modeled in extdeps/access so the std/ access -// abstraction can be DERIVED from their commonality and validated against each (DESIGN §3), -// not re-coined from any single one. - module extdeps.access.zanzibar import std.types { NonEmptyStr } import extdeps.external_authority { ExternalAuthority } import extdeps.uri { Uri, Https } -// External-authority anchor (promotes the Source citation above to the structured carrier -// that v2.lens.extdeps_external_authority gates on — DESIGN §3). data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { uri: Uri { scheme: Https @@ -27,36 +11,26 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// ⟨object⟩ ::= ⟨namespace⟩ ':' ⟨object id⟩ (e.g. "doc:readme") type Object { namespace: NonEmptyStr id: NonEmptyStr } -// ⟨userset⟩ ::= ⟨object⟩ '#' ⟨relation⟩ (e.g. "group:eng#member") type Userset { object: Object relation: NonEmptyStr } -// ⟨user⟩ ::= ⟨user id⟩ | ⟨userset⟩ type User = UserId { id: NonEmptyStr } | UsersetUser { userset: Userset } -// ⟨tuple⟩ ::= ⟨object⟩ '#' ⟨relation⟩ '@' ⟨user⟩ (e.g. "doc:readme#viewer@group:eng#member") type RelationTuple { object: Object relation: NonEmptyStr user: User } -// Userset rewrite rules (§2.3) — a namespace relation's config. Leaf rules: -// This -- `_this`: tuples stored directly for this object#relation -// ComputedUserset -- another relation on the SAME object (e.g. editor implies viewer) -// TupleToUserset -- follow `tupleset` to other objects, then `computed` relation there -// (e.g. "viewer of the parent folder" — inheritance) -// combined by Union / Intersection / Exclusion. type UsersetRewrite = This | ComputedUserset { relation: NonEmptyStr } @@ -70,19 +44,15 @@ type RelationConfig { rewrite: UsersetRewrite } -// A namespace configuration: its relations and their rewrite rules (§2.3). type NamespaceConfig { namespace: NonEmptyStr relations: List } -// Zookie (§2.2): opaque consistency token (a snapshot timestamp) for read-after-write. type Zookie { token: NonEmptyStr } -// The Check decision (§2.4.1): is `user` related to `object` via `relation`, evaluated at a -// consistency snapshot? Modeled as the request shape (the boolean answer is the dependent fact). type CheckRequest { object: Object relation: NonEmptyStr diff --git a/dsl/extdeps/audit/cloudevents.dag b/dsl/extdeps/audit/cloudevents.dag index b6f75662a4e..9ea3a50cf67 100644 --- a/dsl/extdeps/audit/cloudevents.dag +++ b/dsl/extdeps/audit/cloudevents.dag @@ -1,22 +1,7 @@ -// extdeps/audit/cloudevents.dag -- CloudEvents audit emission target surface. -// -// Specs: -// CloudEvents 1.0.2 core event attributes -// https://github.com/cloudevents/spec/blob/v1.0.2/cloudevents/spec.md -// RFC 3339 timestamp profile -// https://www.rfc-editor.org/rfc/rfc3339 -// -// Ctrl-Migration Phase 3 authority for emitted audit event facts. The target -// describes stable event records; it does not decide storage backend, queueing, -// retention, or alerting policy. - module extdeps.audit.cloudevents import std.types { NonEmptyStr, Timestamp } -// CloudEvents core attribute carriers. They intentionally stay separate from -// ctrl audit convenience fields so emitted audit records preserve the external -// wire vocabulary until a generated emitter owns the final serialization. type CloudEventId = NonEmptyStr where brand("CloudEventId") type CloudEventSource = NonEmptyStr where brand("CloudEventSource") type CloudEventSpecVersion = NonEmptyStr where brand("CloudEventSpecVersion") @@ -25,17 +10,11 @@ type CloudEventSubject = NonEmptyStr where brand("CloudEventSubject") type CloudEventExtensionName = NonEmptyStr where brand("CloudEventExtensionName") type CloudEventExtensionValue = NonEmptyStr where brand("CloudEventExtensionValue") -// Coproduct dissolution classification: -// GREEN (terminal). Actor source changes authorization and attribution -// semantics; collapsing to a string would lose the external audit dimension. type AuditActorKind = HumanActor | ServiceActor | SystemActor -// Coproduct dissolution classification: -// GREEN (terminal). Outcome is part of the externally reported audit fact -// and drives different downstream compliance interpretations. type AuditOutcome = AuditSucceeded | AuditDenied @@ -63,8 +42,6 @@ type AuditEventRecord { fields: List } -// STAGED. Ctrl subsystem projections emit into this target only after parity -// tests prove the event stream matches the existing TypeScript implementation. type AuditEventEmissionTarget { stream_name: NonEmptyStr events: List diff --git a/dsl/extdeps/bmc.dag b/dsl/extdeps/bmc.dag index f7080ae8664..584bdc70db2 100644 --- a/dsl/extdeps/bmc.dag +++ b/dsl/extdeps/bmc.dag @@ -1,8 +1,3 @@ -// extdeps/bmc.dag — BMC telemetry projections over Redfish resource shapes. -// -// Types: extdeps.bmc.types. Per-firmware cited facts: extdeps.bmc.. -// Redfish projections: extdeps.bmc.redfish. - module extdeps.bmc import extdeps.bmc.types { BmcGroundedHostObservations, BmcTelemetrySnapshot } diff --git a/dsl/extdeps/bmc/http.dag b/dsl/extdeps/bmc/http.dag index 9d157d271c2..b16fcf0f35a 100644 --- a/dsl/extdeps/bmc/http.dag +++ b/dsl/extdeps/bmc/http.dag @@ -1,19 +1,3 @@ -// extdeps/bmc/http.dag — DMTF Redfish REST transport (curl argv bindings). -// -// Anchor: https://www.dmtf.org/standards/redfish -// -// Interface shapes and grounding projections live in extdeps/bmc/{types,redfish}.dag -// (git.dag pattern: types + projections co-located; transport in this file). -// -// Service name is 2-segment (`redfish.Http`) so it is callable from a fn — a 3-segment -// `diagnostic.redfish.Http` could not be referenced as a call path. -// -// 🟡 dissolved — feature:diagnostic-redfish-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); the published corpus (extdeps.diagnostic.mock_corpus) governs -// WHICH redfish.Http ops are hermetically realizable, and the fixture store owns the payloads (§3). -// forbidden: reintroducing mock_response constants for Hermetic dispatch on these shapes. - module extdeps.bmc.http import std.types { NonEmptyStr } @@ -29,12 +13,7 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } service redfish.Http { - // Authenticated read of the system resource (power state, manufacturer, etc.) — the - // minimal "first contact" that proves the BMC is reachable AND the credentials work. - // Read-only / safe. `-k` accepts the BMC's self-signed cert (standard for OOB mgmt). - // NOTE: the password rides the curl argv here, acceptable ONLY because first contact - // uses the PUBLISHED factory default; a rotated Secret must use GetSystemWithNetrc - // (password never on argv) once rotation has happened. + operation GetSystem { input { bmc_host: NonEmptyStr, username: NonEmptyStr, password: NonEmptyStr } output { body: String from "stdout", success: Bool from "exit_success" } @@ -48,8 +27,6 @@ service redfish.Http { } } - // Authenticated read via netrc file — REQUIRED for rotated BMC secrets (password must - // not appear on curl argv). netrc_file path comes from BMC_NETRC_FILE (0600 file). operation GetSystemWithNetrc { input { bmc_host: NonEmptyStr, netrc_file: NonEmptyStr } output { body: String from "stdout", success: Bool from "exit_success" } @@ -63,8 +40,6 @@ service redfish.Http { } } - // Chassis sensor collection — OpenBMC ALTRAD8UD exposes power/temp under Sensors/{name} - // (Chassis Power/Thermal are empty on Redfish 1.15 for this board). operation GetChassisSensors { input { bmc_host: NonEmptyStr, chassis_id: NonEmptyStr, netrc_file: NonEmptyStr } output { body: String from "stdout", success: Bool from "exit_success" } @@ -78,8 +53,6 @@ service redfish.Http { } } - // Chassis Power — PowerControl members (PowerConsumedWatts, PowerLimitWatts). - // Shape authority: extdeps/bmc/types.dag (RedfishPowerSubsystem). operation GetPower { input { bmc_host: NonEmptyStr, username: NonEmptyStr, password: NonEmptyStr } output { body: String from "stdout", success: Bool from "exit_success" } @@ -93,8 +66,6 @@ service redfish.Http { } } - // Chassis Thermal — temperature sensor readings. - // Shape authority: extdeps/bmc/types.dag (RedfishThermalSubsystem). operation GetThermal { input { bmc_host: NonEmptyStr, username: NonEmptyStr, password: NonEmptyStr } output { body: String from "stdout", success: Bool from "exit_success" } diff --git a/dsl/extdeps/bmc/openbmc.dag b/dsl/extdeps/bmc/openbmc.dag index 3e30623abf9..68e9f600fee 100644 --- a/dsl/extdeps/bmc/openbmc.dag +++ b/dsl/extdeps/bmc/openbmc.dag @@ -1,18 +1,3 @@ -// extdeps/bmc/openbmc.dag — OpenBMC firmware family: cited defaults (single authority). -// -// Anchor: https://github.com/openbmc/openbmc (the Linux Foundation OpenBMC project) -// -// OpenBMC ships a stock root account with the published default password `0penBmc` -// (that is a zero, then "penBmc"). Cited witness: ASRock Rack ALTRAD8UD-1L2T User -// Manual p.47 — "the default login information for the IPMI web interface is: -// Username: root Password: 0penBmc". This is a WORLD-KNOWN published default, so -// it is allowed as a cited source literal here (not a held secret); a real deployment -// rotates it on first contact (rotation is a workflow policy, not modeled here). -// -// This file is the ONE home for the OpenBMC factory credential: every board that ships -// OpenBMC derives it from here (DESIGN §2 horizontal — one fact, every board derives; -// §3 single authority — never re-stated per board row). - module extdeps.bmc.openbmc import std.bmc { BmcFirmwareFamily, OpenBmc, BmcProtocol, Redfish, Ipmi } @@ -29,34 +14,19 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// The published OpenBMC factory login (see anchor above). Public, world-known value — -// cited as a source literal precisely because it is NOT a secret; it is rotated on first -// contact (rotation is a workflow policy, not modeled here). data openbmc_factory_login: FactoryLogin = FactoryLogin { username: "root", published_password: "0penBmc", } -// OpenBMC exposes BOTH a DMTF Redfish service and a legacy IPMI/RMCP+ service. These -// are distinct, separately-cited interfaces (DESIGN §3 — exclusive, not aliases). data openbmc_supported_protocols: List = [Redfish, Ipmi] -// 🟡 dispatch — dissolution trigger: WHEN a second BmcFirmwareFamily variant lands -// (e.g. AMI MegaRAC), lift this firmware→login / firmware→protocols dispatch OUT of this -// per-family file into a non-family hub (extdeps/bmc/bmc.dag), mirroring the std/os.dag -// projection ↔ extdeps/os/os.dag dispatch split (DESIGN §3 "dispatch lives in extdeps/, -// not std/"). At one variant, lifting now would model ahead of a second instance (§6). -// The header's "ONE home" claim is about the credential itself, which stays here. -// -// firmware → published factory login. Closed match; fail-closed on a new family -// until its own cited file lands. fn bmc_firmware_factory_login(family: BmcFirmwareFamily) -> FactoryLogin { match family { OpenBmc => openbmc_factory_login } } -// firmware → the management protocols it speaks. fn bmc_firmware_supported_protocols(family: BmcFirmwareFamily) -> List { match family { OpenBmc => openbmc_supported_protocols diff --git a/dsl/extdeps/bmc/redfish.dag b/dsl/extdeps/bmc/redfish.dag index 55100f5edd8..fdedc2f1d88 100644 --- a/dsl/extdeps/bmc/redfish.dag +++ b/dsl/extdeps/bmc/redfish.dag @@ -1,10 +1,3 @@ -// extdeps/bmc/redfish.dag — Redfish telemetry projections and host-grounding seam. -// -// Pure folds over extdeps/bmc/types shapes. Transport that fetches the raw JSON lives -// in extdeps/bmc/http.dag; JSON parse → these records is a peripheral handler (dissolve-on: -// v2.extdeps.formats.json parse fold consumable from dsl/). Until then, grounding -// witnesses exercise the projection with structured fixture rows (DESIGN §5). - module extdeps.bmc.redfish import extdeps.bmc.types { @@ -76,8 +69,6 @@ fn redfish_system_inventory( } } -// Sum PowerControl.PowerConsumedWatts across members. Absent when no control reports a -// reading (host off / sensors unavailable) — fail-closed, not a fabricated 0 W. fn redfish_power_consumed_total_watts(controls: List) -> Watt? { fold( controls, @@ -94,7 +85,6 @@ fn redfish_power_consumed_total_watts(controls: List) -> Wa ) } -// Sum power sensor readings (power_PWR_* on OpenBMC ALTRAD8UD). Absent when none report. fn redfish_sensors_power_total_watts(sensors: List) -> Watt? { fold( sensors, @@ -147,8 +137,6 @@ fn redfish_primary_power_control(power: RedfishPowerSubsystem) -> RedfishPowerCo ) } -// Project a telemetry snapshot to the host observations record ctrl consumes instead of -// hand-typed fleet rows. fn bmc_ground_host_observations(snapshot: BmcTelemetrySnapshot) -> BmcGroundedHostObservations { BmcGroundedHostObservations { processor_model: snapshot.system.processor.model, @@ -158,7 +146,6 @@ fn bmc_ground_host_observations(snapshot: BmcTelemetrySnapshot) -> BmcGroundedHo } } -// Convenience: total RAM bytes from system inventory alone. fn redfish_system_total_memory_bytes(inv: RedfishSystemInventory) -> ByteSize { inv.memory.total_memory_bytes } diff --git a/dsl/extdeps/bmc/types.dag b/dsl/extdeps/bmc/types.dag index 7abd0de5787..6bb77b1bcd2 100644 --- a/dsl/extdeps/bmc/types.dag +++ b/dsl/extdeps/bmc/types.dag @@ -1,13 +1,3 @@ -// extdeps/bmc/types.dag — DMTF Redfish BMC telemetry resource shapes. -// -// Anchor: DMTF Redfish Schema — ComputerSystem, Power, Thermal resources -// https://www.dmtf.org/standards/redfish -// -// These are the cited interface shapes for what a BMC firmware stack returns over -// Redfish REST. Transport (curl argv) lives in extdeps/bmc/http.dag; parsing raw -// JSON into these records is a separate realization handler (§3 shape / transport / -// policy). This module owns ONLY the structural facts Redfish names. - module extdeps.bmc.types import std.measure { @@ -21,13 +11,8 @@ import std.measure { } import std.types { NonEmptyStr, Int, List } -// ComputerSystem.PowerState — host power state as reported by the BMC (not host OS). type RedfishPowerState = On | Off | PoweringOn | PoweringOff -// ProcessorSummary on ComputerSystem — the BMC's view of installed processors. -// DMTF fields are NOT conflated: Count = installed processors (sockets); CoreCount = -// total cores across them; LogicalProcessorCount = hardware threads when reported. -// processor_count is a DMTF cardinal (socket count), not a unit-bearing scalar. type RedfishProcessorSummary { model: NonEmptyStr processor_count: Int @@ -35,12 +20,10 @@ type RedfishProcessorSummary { logical_processor_count: HardwareThreadCount? } -// MemorySummary on ComputerSystem — total installed RAM as the BMC inventories it. type RedfishMemorySummary { total_memory_bytes: ByteSize } -// ComputerSystem resource — system inventory read from /redfish/v1/Systems/{id}. type RedfishSystemInventory { model: NonEmptyStr manufacturer: NonEmptyStr? @@ -50,10 +33,6 @@ type RedfishSystemInventory { power_state: RedfishPowerState } -// PowerControl on Chassis Power — the Energy axis in hardware_selection's -// Cost = Time|Space|Energy pattern maps `power: Watt` (rate of energy transfer). -// Redfish names these fields *Watts*; they ground on std.measure `Watt` (Power -// dimension), not a separate Energy carrier (joule is not minted in measure.dag yet). type RedfishPowerControl { member_id: NonEmptyStr name: NonEmptyStr? @@ -61,29 +40,20 @@ type RedfishPowerControl { power_limit_watts: Watt? } -// Chassis Power resource — one or more PowerControl members (PSU rails, total, …). type RedfishPowerSubsystem { controls: List } -// Temperature member on Chassis Thermal. type RedfishTemperatureReading { member_id: NonEmptyStr name: NonEmptyStr? reading_celsius: Celsius? } -// Chassis Thermal resource. type RedfishThermalSubsystem { temperatures: List } -// OpenBMC on ALTRAD8UD-1L2T (Redfish 1.15): Chassis Power/Thermal collections are EMPTY; -// per-sensor docs live under /redfish/v1/Chassis/{chassis_id}/Sensors/{name} with -// {Reading, ReadingUnits}. Verified live on srv2 2026-06-20 (operator probe). -// -// DECOMPOSITION CHECKPOINT (DESIGN.md §2): 🟢 PRIMITIVE -// Coproduct over sensor families — illegal states (Power+Celsius, FanTach+Watts) unrepresentable. type RedfishSensorReading = PowerSensor { name: NonEmptyStr, watts: Watt? } | TemperatureSensor { name: NonEmptyStr, celsius: Celsius? } @@ -94,7 +64,6 @@ type RedfishChassisSensorCollection { sensors: List } -// Aggregate telemetry bundle for one BMC poll — the shape ctrl/gunbc grounding consumes. type BmcTelemetrySnapshot { system: RedfishSystemInventory power: RedfishPowerSubsystem? @@ -102,8 +71,6 @@ type BmcTelemetrySnapshot { sensors: RedfishChassisSensorCollection? } -// Observed host facts projected from a BMC telemetry snapshot — replaces hand-typed -// CPU model / core-count / RAM / wall-power rows for operator fleet hosts (srv1/srv2). type BmcGroundedHostObservations { processor_model: NonEmptyStr processor_core_count: HardwareThreadCount diff --git a/dsl/extdeps/boards/asrock_rack.dag b/dsl/extdeps/boards/asrock_rack.dag index 198eb9c9461..8ec8856d2d4 100644 --- a/dsl/extdeps/boards/asrock_rack.dag +++ b/dsl/extdeps/boards/asrock_rack.dag @@ -1,12 +1,3 @@ -// extdeps/boards/asrock_rack.dag — ASRock Rack baseboard catalog (cited facts). -// -// Anchor: ASRock Rack ALTRAD8UD-1L2T User Manual -// https://download.asrock.com/Manual/ALTRAD8UD-1L2T.pdf -// Single-socket Ampera Altra/Altra Max (LGA4926) server board. Its BMC runs OpenBMC -// (manual p.47), so the board does NOT restate any default login — it points at the -// OpenBmc firmware family, whose cited factory credential lives in extdeps/bmc/openbmc.dag -// (DESIGN §3 single authority; the board derives, never duplicates). - module extdeps.boards.asrock_rack import std.baseboard { @@ -16,14 +7,11 @@ import std.baseboard { import std.bmc { OpenBmc } import std.types { NonEmptyStr } -// Manufacturer (AsrockRack) is not stored here — it derives from `model` via -// std.baseboard.baseboard_manufacturer (DESIGN §2, one fact derived). data asrock_altrad8ud_1l2t_catalog: BaseboardCatalogRow = BaseboardCatalogRow { model: AsrockRackAltrad8ud1l2t, model_label: "ASRock Rack ALTRAD8UD-1L2T", bmc_firmware: OpenBmc, } -// Redfish member ids on OpenBMC for this board (live-verified srv2 2026-06-20). data asrock_altrad8ud_redfish_system_id: NonEmptyStr = "system" data asrock_altrad8ud_redfish_chassis_id: NonEmptyStr = "ALTRAD8UD_1L2T" diff --git a/dsl/extdeps/boot/emit.dag b/dsl/extdeps/boot/emit.dag index 7ca420a624b..a9f1e469526 100644 --- a/dsl/extdeps/boot/emit.dag +++ b/dsl/extdeps/boot/emit.dag @@ -1,9 +1,3 @@ -// extdeps/boot/emit.dag — freestanding ELF-64 ET_EXEC emit (Slice-0.5). -// -// Scope: single PT_LOAD R+X freestanding payload via landed encode.dag inverse. -// Anchor: gABI ch4/ch5 (Ehdr + Phdr); Linux x86-64 ET_EXEC load base 0x400000. -// Payload: minimal VGA text-mode pixel writer (movabs + movw + hlt). - module extdeps.boot.emit import extdeps.boot.framebuffer { vga_text_mode_base } @@ -34,10 +28,8 @@ import extdeps.formats.elf.types { Elf64Ehdr, ElfIdent, byte_at_in_bounds } import std.exec_format { EntryPoint } import std.types { NonEmptyStr } -// Slice-0.5 content label — structural digest defers to hash primitive when dsl bootstrap exports it. data pixel_writer_payload_digest_label: NonEmptyStr = "freestanding-elf64-slice-0.5" -// Linux x86-64 static ET_EXEC default load address. data freestanding_load_vaddr: Int = 4194304 data freestanding_phoff: Int = 64 @@ -46,7 +38,6 @@ data freestanding_code_file_offset: Int = 120 data freestanding_page_align: Int = 4096 -// x86-64: movabs rax, vga_text_mode_base; movw $0x0f48, (%rax); hlt data pixel_writer_code_bytes: List = [ 72, 184, 0, 128, 11, 0, 0, 0, 0, 0, 102, 199, 0, 72, 15, diff --git a/dsl/extdeps/boot/framebuffer.dag b/dsl/extdeps/boot/framebuffer.dag index 4f68ee8c0ae..480c9a059b0 100644 --- a/dsl/extdeps/boot/framebuffer.dag +++ b/dsl/extdeps/boot/framebuffer.dag @@ -1,10 +1,3 @@ -// extdeps/boot/framebuffer.dag — VGA text-mode hardware facts for Slice-0.5 emit. -// -// Anchor: IBM PC VGA text mode buffer at 0xB8000 (hardware fact). -// FramebufferSurface / FramebufferWrite types deferred to Slice-1 boot QA -// (consumer lands with QEMU stage witnesses; see boot-sketches 3ed85a12fb). - module extdeps.boot.framebuffer -// Slice-0.5 default VGA text mode base (IBM PC hardware fact). data vga_text_mode_base: Int = 753664 diff --git a/dsl/extdeps/boot/freestanding_payload.dag b/dsl/extdeps/boot/freestanding_payload.dag index 4bfe9bbd725..6680e457564 100644 --- a/dsl/extdeps/boot/freestanding_payload.dag +++ b/dsl/extdeps/boot/freestanding_payload.dag @@ -1,8 +1,3 @@ -// extdeps/boot/freestanding_payload.dag — freestanding init/payload reference (Slice-0 / 0.5). -// -// Slice-0: HollowPrebuiltInit boot vehicle (not emit proof) — separate coproduct arm. -// Slice-0.5: EmittedPayload from OUR ELF encode + exec-contract pipeline. - module extdeps.boot.freestanding_payload import std.exec_format { EntryPoint } @@ -12,6 +7,3 @@ type FreestandingPayloadRef = EmittedPayload { digest: NonEmptyStr, entry: EntryPoint } | PrebuiltPayload { digest: NonEmptyStr, entry: EntryPoint } | HollowPrebuiltInit { digest: NonEmptyStr, entry: EntryPoint } - -// 🟡 feature:hollow-prebuilt-init — Slice-0 boot vehicle; not an emit proof. -// dissolve-on: delete HollowPrebuiltInit when all boot paths consume EmittedPayload (Slice-0.5+). diff --git a/dsl/extdeps/boot/freestanding_witness.dag b/dsl/extdeps/boot/freestanding_witness.dag index b3346e79419..d1301e41957 100644 --- a/dsl/extdeps/boot/freestanding_witness.dag +++ b/dsl/extdeps/boot/freestanding_witness.dag @@ -1,8 +1,3 @@ -// extdeps/boot/freestanding_witness.dag — Slice-0.5 freestanding ELF emit witnesses. -// -// Green-by-execution via `gunbc run --source-root dsl --entry ... --claim-run`. -// 🟡 consumer:dsl-rooted-claim-run-gate — not CI-enrolled until dsl corpus gate lands. - module extdeps.boot.freestanding_witness import extdeps.boot.emit { diff --git a/dsl/extdeps/boot/linux_x86_boot.dag b/dsl/extdeps/boot/linux_x86_boot.dag index c421346b759..41eca31b852 100644 --- a/dsl/extdeps/boot/linux_x86_boot.dag +++ b/dsl/extdeps/boot/linux_x86_boot.dag @@ -1,8 +1,3 @@ -// extdeps/boot/linux_x86_boot.dag — Linux x86 direct-kernel boot image (Slice-0). -// -// Anchor: Documentation/arch/x86/boot.rst (Linux kernel boot protocol). -// Concept attach: x86_64_linux ArchitectureProfile + ELF EntryPoint. - module extdeps.boot.linux_x86_boot import extdeps.boot.freestanding_payload { @@ -23,13 +18,6 @@ type BootImageOutcome = BootImageAccepted { value: LinuxX86BootImage } | BootImageRejected { reason: BootImageRejectReason } -// Coproduct ledger — **🟢 GREEN** -// `HollowInitNotEmitProof` is the terminal reject arm (produced when init is -// `HollowPrebuiltInit`). **🟡 YELLOW (scaffold)** — `BootImageRejectUnspecified` -// reserved for v2 loader ≥2-arms constraint; never produced by -// `accept_linux_x86_boot_image` until a second real reject reason lands. -// dissolve-on: delete `BootImageRejectUnspecified` when a second reject reason -// is modeled (e.g. invalid kernel placement) or unary-sum loader closes. type BootImageRejectReason = HollowInitNotEmitProof | BootImageRejectUnspecified diff --git a/dsl/extdeps/browser/browser.dag b/dsl/extdeps/browser/browser.dag index 78a6a05e580..648ba9d24fb 100644 --- a/dsl/extdeps/browser/browser.dag +++ b/dsl/extdeps/browser/browser.dag @@ -1,23 +1,7 @@ -// extdeps/browser/browser.dag -- Playwright browser automation transport. -// -// Models headless/headed browser interaction for web automation. -// Primary consumer: chatgpt_reviewer.dag (ChatGPT Pro browser automation). -// -// Transport: Playwright (Node.js) — the interpreter dispatches operations -// to a persistent browser context via the Playwright API. -// -// This is the most complex transport in the system: it manages a stateful -// browser session with navigation, DOM queries, file uploads, and text -// extraction. The operations are designed to be composable — higher-level -// workflows (like chatgpt_reviewer.dag) compose these into multi-step -// interactions. - module extdeps.browser import std.types { FilePath } -// -- Browser lifecycle ------------------------------------------------ - type BrowserConfig { headless: Bool = false profile_path: FilePath @@ -25,22 +9,10 @@ type BrowserConfig { viewport_height: Int = 900 } -// Opaque handles — the interpreter manages the actual Playwright objects. -// These are passed between operations but never inspected by .dag code. -// Branded-String form lets shell transport interpolate the handle via argv -// while the type system keeps them disjoint from raw String. type BrowserContext = String where brand("BrowserContext") type Page = String where brand("Page") type Element = String where brand("Element") -// -- Services --------------------------------------------------------- - -// Browser operations dispatch via shell to a Playwright runner. -// The runner manages a persistent browser context and executes -// actions as JSON commands. This keeps the transport within what -// the compiler supports today (shell). A native playwright transport -// can replace this later without changing the .dag interface. - service browser.Context { operation Launch { input { headless: String = "false", profile_path: FilePath } @@ -56,21 +28,16 @@ service browser.Context { } service browser.Page { - // The current shell transport addresses a single implicit page owned by the - // persistent runner session. No argv slot carries a page handle today, so - // these operations stay page-singleton until the transport can surface a - // `Page` carrier without breaking callers that rely on that assumption. + operation Goto { - // Keep browser locations as raw String as a current modeling choice: - // std.types.Url narrows to `^https?://`, but browser navigation and - // observation legitimately include locations such as `about:blank`. + input { url: String, wait_until: String = "domcontentloaded" } output { final_url: String from "stdout" } transport shell { argv: ["playwright-runner", "goto", "{url}", "--wait-until", "{wait_until}"] } } operation CurrentUrl { - // Same rationale as `Goto`: browser-native locations are valid outputs. + input {} output { url: String from "stdout" } transport shell { argv: ["playwright-runner", "url"] } @@ -132,9 +99,7 @@ service browser.Page { } service browser.Element { - // The runner's element-facing commands are selector-addressed today rather - // than handle-addressed. Keep selectors explicit until the transport can - // produce and consume `Element` carriers end-to-end. + operation IsVisible { input { selector: String } output { visible: String from "stdout" } diff --git a/dsl/extdeps/cache/buildbuddy.dag b/dsl/extdeps/cache/buildbuddy.dag index ca7a7b1ba71..193463807fa 100644 --- a/dsl/extdeps/cache/buildbuddy.dag +++ b/dsl/extdeps/cache/buildbuddy.dag @@ -1,7 +1,3 @@ -// extdeps/cache/buildbuddy.dag — BuildBuddy remote CAS cache catalog (cited facts). -// -// Spec: https://www.buildbuddy.io/docs/remote-cache - module extdeps.cache.buildbuddy import extdeps.cache.types { CacheInterfaceCatalogFacts, ContentAddressed } @@ -30,8 +26,7 @@ data buildbuddy_cas_facts: CacheInterfaceCatalogFacts = { backing_surface: "buildbuddy-remote-cas" transport_encoding: CasContentEncoding key_derivation: { - // OUR content-addressed cache: inputs DERIVED from invalidation_triggers (no - // ToolchainChange ⟹ just the upsert subject content). Nothing to author. + key_inputs: ContentAddressed overwritable: false prefix_fallback_allowed: false diff --git a/dsl/extdeps/cache/cache.dag b/dsl/extdeps/cache/cache.dag index 870bd1cdf02..522ac72673d 100644 --- a/dsl/extdeps/cache/cache.dag +++ b/dsl/extdeps/cache/cache.dag @@ -1,6 +1,3 @@ -// extdeps/cache/cache.dag — Cache catalog dispatch hub (per-vendor modules under extdeps/cache/*). -// Product → cited catalog row + transport projection (§3: dispatch lives in extdeps/, not std/). - module extdeps.cache.cache import extdeps.cache.buildbuddy { buildbuddy_cas_facts, buildbuddy_cas_id } @@ -50,7 +47,6 @@ fn cited_cache_interface_facts(product: CacheInterfaceProduct) -> CacheInterface } } -// Planner-facing projection: flatten catalog io/placement into std CacheInterfaceFacts. fn cache_interface_facts_from_catalog(row: CacheInterfaceCatalogFacts) -> CacheInterfaceFacts { CacheInterfaceFacts { identity: row.identity @@ -62,10 +58,7 @@ fn cache_interface_facts_from_catalog(row: CacheInterfaceCatalogFacts) -> CacheI CargoFingerprintEncoding => CasContentEncoding } vendor_transport_encoding_collapsed: catalog_transport_encoding_collapsed_in_std_projection(encoding: row.transport_encoding) - // inputs_considered() resolves the single authority: DERIVED for content-addressed - // rows, CITED for external ones (catalog_inputs_considered). The agnostic projection - // keeps only the derived "vendor axes omitted" flag — it carries no authorable inputs - // list of its own (the §3 fork that PR #5423 false-greened cannot reappear here). + key_derivation: { vendor_only_key_inputs_omitted: catalog_has_vendor_only_key_inputs(inputs: catalog_inputs_considered(kd: row.key_derivation)) overwritable: row.key_derivation.overwritable @@ -149,8 +142,6 @@ data sccache_local_projected: CacheInterfaceFacts = cache_interface_facts_from_c data parse_table_memo_projected: CacheInterfaceFacts = cache_interface_facts_from_catalog(parse_table_memo) data cargo_target_dir_projected: CacheInterfaceFacts = cache_interface_facts_from_catalog(cargo_target_dir) -// Default probe order: in-process memo → runner target dir → host sccache/resolved-graph -// → toolchain store → remote CAS (BuildBuddy) → GHA actions cache. data cache_layer_default_order: List = [ parse_table_memo_id, cargo_target_dir_id, diff --git a/dsl/extdeps/cache/cargo.dag b/dsl/extdeps/cache/cargo.dag index 09b79baf90c..41acc6fdac7 100644 --- a/dsl/extdeps/cache/cargo.dag +++ b/dsl/extdeps/cache/cargo.dag @@ -1,7 +1,3 @@ -// extdeps/cache/cargo.dag — Cargo target-directory cache catalog (cited facts). -// -// Spec: https://doc.rust-lang.org/cargo/guide/build-cache.html - module extdeps.cache.cargo import extdeps.cache.types { @@ -38,9 +34,7 @@ data cargo_target_dir_facts: CacheInterfaceCatalogFacts = { backing_surface: "cargo-target-directory" transport_encoding: CargoFingerprintEncoding key_derivation: { - // EXTERNAL vendor cache: cargo computes its own fingerprint, so the inputs are a CITED - // observation of what it keys (§3 "model what the API returns"), not something we - // construct. key_completeness validates this citation (ToolchainChange ⟹ a toolchain axis). + key_inputs: NativeInternal { cited_inputs: [RustcInvocation, FilePaths, ToolchainSpec] } overwritable: true prefix_fallback_allowed: false diff --git a/dsl/extdeps/cache/catalog_io.dag b/dsl/extdeps/cache/catalog_io.dag index 47d632406e6..7fb2727cbd3 100644 --- a/dsl/extdeps/cache/catalog_io.dag +++ b/dsl/extdeps/cache/catalog_io.dag @@ -1,7 +1,3 @@ -// extdeps/cache/catalog_io.dag — cache catalog IO semantics arm (lookup/write/miss). -// Split from placement so AtomicityModel and CacheWriteSemantics variants do not -// share a module namespace (homonymous WriteThenCommit / WriteThenRename). - module extdeps.cache.catalog_io import std.cache_interface { diff --git a/dsl/extdeps/cache/catalog_placement.dag b/dsl/extdeps/cache/catalog_placement.dag index 2d0ec3eb9bf..7a1368b1e79 100644 --- a/dsl/extdeps/cache/catalog_placement.dag +++ b/dsl/extdeps/cache/catalog_placement.dag @@ -1,7 +1,3 @@ -// extdeps/cache/catalog_placement.dag — cache catalog placement/eviction arm. -// Split from IO semantics so AtomicityModel and CacheWriteSemantics variants do not -// share a module namespace (homonymous WriteThenCommit / WriteThenRename). - module extdeps.cache.catalog_placement import std.cache_interface { diff --git a/dsl/extdeps/cache/github_actions.dag b/dsl/extdeps/cache/github_actions.dag index 77f4d02f2d4..ccfbc81ebcb 100644 --- a/dsl/extdeps/cache/github_actions.dag +++ b/dsl/extdeps/cache/github_actions.dag @@ -1,7 +1,3 @@ -// extdeps/cache/github_actions.dag — GitHub Actions cache catalog (cited facts). -// -// Spec: https://docs.github.com/en/actions/using-workflows/caching-dependencies-to-speed-up-workflows - module extdeps.cache.github_actions import extdeps.cache.types { CacheInterfaceCatalogFacts, HandAuthored } @@ -33,9 +29,7 @@ data gha_actions_cache_facts: CacheInterfaceCatalogFacts = { backing_surface: "github-actions-cache-api" transport_encoding: OpaqueStringEncoding key_derivation: { - // HAND-AUTHORED key string (GHA cache key): invalidation is the author bumping the key, - // so its components are CITED/authored, not derived — exempt from key_completeness. The - // §6 genuinely-unstructurable carve-out, made explicit by the HandAuthored variant. + key_inputs: HandAuthored { cited_inputs: [UpsertSubject, FilePaths] } overwritable: true prefix_fallback_allowed: true diff --git a/dsl/extdeps/cache/key_completeness.dag b/dsl/extdeps/cache/key_completeness.dag index 470c5a8a600..b28d2bb2ba3 100644 --- a/dsl/extdeps/cache/key_completeness.dag +++ b/dsl/extdeps/cache/key_completeness.dag @@ -1,21 +1,3 @@ -// extdeps/cache/key_completeness.dag — cited-key citation-completeness lens (§5/§6). -// -// CONSTRUCTION-NOT-VALIDATION (the PR #5423 → #5425 shift): for OUR caches the key-input -// set is DERIVED from the model (CatalogKeyInputs.ContentAddressed has no inputs field — -// content_addressed_inputs computes it), so a content-addressed cache cannot under-key by -// construction; there is nothing here to validate. This lens therefore exists ONLY for the -// genuinely-unstructurable residue: EXTERNAL vendor caches whose key the vendor computes -// (NativeInternal), where inputs_considered is a CITED observation of a system we do not -// control. Validating a CITATION's internal consistency is the legitimate lens use (§6): -// if we cite that the vendor invalidates on toolchain change (ToolchainChange ∈ -// invalidation_triggers) we must also cite a toolchain axis among its keyed inputs, else -// our citation is self-contradictory — we'd be claiming a toolchain-sensitive key that -// omits the toolchain (the §5 stale-pass shape, in the citation rather than our realizer). -// -// HandAuthored keys are exempt (invalidation is the author bumping the string, not an input -// set); ContentAddressed keys are exempt (derived — see above). So this lens fires on -// NativeInternal rows only. It is a pure reader over the live extdeps.cache.cache catalog. - module extdeps.cache.key_completeness import extdeps.cache.types { @@ -38,10 +20,6 @@ import std.lens_verdict { import std.types { Bool } import std.list { List } -// The citation-completeness invariant. Fires on NativeInternal (cited vendor) rows only: -// a cited key that the vendor invalidates on toolchain change MUST cite a toolchain axis -// (RustcInvocation/ToolchainSpec) among its inputs. ContentAddressed is derived (exempt), -// HandAuthored is authored (exempt) — neither has an authorable inputs list to mis-cite. fn cache_key_derivation_complete(facts: CatalogKeyDerivationFacts) -> Bool { match facts.key_inputs { ContentAddressed => true @@ -55,8 +33,6 @@ fn cache_key_derivation_complete(facts: CatalogKeyDerivationFacts) -> Bool { } } -// Verdict projection (std.lens_verdict): rich diagnostic on violation. `module_name` -// is the locus supplied by the caller (the cache row's home). fn cache_key_completeness_verdict(facts: CatalogKeyDerivationFacts, module_name: String) -> LensVerdict { if cache_key_derivation_complete(facts: facts) { Holds @@ -70,8 +46,6 @@ fn cache_key_completeness_verdict(facts: CatalogKeyDerivationFacts, module_name: } } -// Roster fold — the live gate. Every catalog row must satisfy citation-completeness -// (vacuously true for our derived/authored rows; the real check is on cited vendor rows). fn cache_catalog_key_completeness_holds(catalog: List) -> Bool { all(catalog, row => cache_key_derivation_complete(facts: row.key_derivation)) } diff --git a/dsl/extdeps/cache/rustup.dag b/dsl/extdeps/cache/rustup.dag index 1c491d10dcc..47b9055ca02 100644 --- a/dsl/extdeps/cache/rustup.dag +++ b/dsl/extdeps/cache/rustup.dag @@ -1,7 +1,3 @@ -// extdeps/cache/rustup.dag — rustup toolchain store cache catalog (cited facts). -// -// Spec: https://rust-lang.github.io/rustup/overrides.html - module extdeps.cache.rustup import extdeps.cache.types { CacheInterfaceCatalogFacts, NativeInternal, ToolchainSpec } @@ -31,7 +27,7 @@ data rustup_toolchain_store_facts: CacheInterfaceCatalogFacts = { backing_surface: "rustup-toolchains-dir" transport_encoding: OpaqueStringEncoding key_derivation: { - // EXTERNAL vendor cache: rustup keys the toolchain triple itself — CITED, not derived. + key_inputs: NativeInternal { cited_inputs: [ToolchainSpec] } overwritable: false prefix_fallback_allowed: false diff --git a/dsl/extdeps/cache/sccache.dag b/dsl/extdeps/cache/sccache.dag index 85e609aa6ad..c5b37ae1197 100644 --- a/dsl/extdeps/cache/sccache.dag +++ b/dsl/extdeps/cache/sccache.dag @@ -1,7 +1,3 @@ -// extdeps/cache/sccache.dag — sccache local-disk cache catalog (cited facts). -// -// Spec: https://github.com/mozilla/sccache/blob/main/docs/Configuration.md - module extdeps.cache.sccache import extdeps.cache.types { @@ -35,8 +31,7 @@ data sccache_local_facts: CacheInterfaceCatalogFacts = { backing_surface: "sccache-local-disk" transport_encoding: SccacheInternalEncoding key_derivation: { - // EXTERNAL vendor cache: sccache computes its own hash over the rustc invocation + - // toolchain — CITED observation, not derived. key_completeness validates the citation. + key_inputs: NativeInternal { cited_inputs: [RustcInvocation, ToolchainSpec] } overwritable: true prefix_fallback_allowed: false @@ -52,7 +47,7 @@ data sccache_local_facts: CacheInterfaceCatalogFacts = { placement: { value_shape: RawBytes locality: PerHostFilesystem - // sccache max cache size is operator-configured (sccache.conf), not a fixed substrate fact. + eviction: Lru atomicity: WriteThenRename auth: FilesystemPerms diff --git a/dsl/extdeps/cache/types.dag b/dsl/extdeps/cache/types.dag index 0fc911c4c64..c0560e0194f 100644 --- a/dsl/extdeps/cache/types.dag +++ b/dsl/extdeps/cache/types.dag @@ -1,9 +1,3 @@ -// extdeps/cache/types.dag — cited cache catalog types (vendor extensions to std shape). -// -// std.cache_interface owns the agnostic interface shape; vendor-specific encoding -// variants, input surfaces, and transport keys live here (§3 — dispatch lives in -// extdeps/, not std/). - module extdeps.cache.types import extdeps.cache.catalog_io { CacheInterfaceCatalogIoSemantics } @@ -34,14 +28,12 @@ import std.cache_interface { import std.types { ContentHash, NonEmptyStr, Bool } import std.list { List } -// Vendor-specific §1.4 input surfaces (rustc/cargo/rustup toolchain axes). type CatalogInputSurface = UpsertSubject | FilePaths | RustcInvocation | ToolchainSpec -// Vendor-specific §1.2 transport encodings (sccache/cargo realization handlers). type CatalogProviderKeyEncoding = OpaqueStringEncoding | CasContentEncoding @@ -59,21 +51,6 @@ type CatalogBackendCacheKey { key: CatalogProviderKey } -// Cache key inputs — single authority for WHAT the key content-addresses, replacing the -// forked pair (a hand-authored `classification` tag + a hand-authored `inputs_considered` -// list that had to be kept in agreement, the §3 fork PR #5423 false-greened). The variant -// IS the key-derivation class, and it determines the inputs BY CONSTRUCTION: -// - ContentAddressed — OUR caches: we author the key (content-address by value), so the -// inputs are DERIVED from invalidation_triggers (`content_addressed_inputs`). There is -// NO authorable inputs field — declaring an input you don't key, or keying one you don't -// declare, is UNWRITABLE (the §0 model↔realization fork dissolved at the model side). -// - NativeInternal — EXTERNAL vendor caches (cargo/rustup/sccache): the vendor computes -// its own internal hash, so the inputs are a CITED observation of what it keys (§3 -// "model what the API returns"), not something we construct. Cited, anchored. -// - HandAuthored — an authored key string (gha_actions_cache): invalidation is the author -// bumping the string; its components are likewise cited, not derived. -// NativeInternal/HandAuthored are the §6 genuinely-unstructurable carve-out, made explicit -// in the TYPE: a citation we validate (key_completeness lens), not a construction we own. type CatalogKeyInputs = ContentAddressed | NativeInternal { cited_inputs: List } @@ -97,13 +74,6 @@ fn invalidation_triggers_on_toolchain_change(triggers: List }) } -// Inputs a content-addressed-by-value cache keys, DERIVED from its invalidation triggers: -// always the upsert subject's content; plus the transform (ToolchainSpec) iff it promises to -// invalidate on toolchain change. DependencyChange needs no extra axis — for a CAV cache the -// dependencies are PART of the subject content (the resolved closure), so UpsertSubject -// already covers them; ManualPurge/TtlExpiry are not content inputs. This is the realizer's -// keyed-axis set expressed at the model layer (resolved_graph_cache.rs folds the same set; -// the two are unified at v2/realize — see CatalogKeyInputs header / DESIGN model↔realization). fn content_addressed_inputs(triggers: List) -> List { if invalidation_triggers_on_toolchain_change(triggers: triggers) { [UpsertSubject, ToolchainSpec] @@ -112,8 +82,6 @@ fn content_addressed_inputs(triggers: List) -> List List { match kd.key_inputs { ContentAddressed => content_addressed_inputs(triggers: kd.invalidation_triggers) @@ -122,8 +90,6 @@ fn catalog_inputs_considered(kd: CatalogKeyDerivationFacts) -> List KeyDerivationClass { match kd.key_inputs { ContentAddressed => ContentAddressedByValue @@ -132,7 +98,6 @@ fn catalog_key_derivation_classification(kd: CatalogKeyDerivationFacts) -> KeyDe } } -// Cited vendor + realization catalog row (full enum surface for extdeps dispatch). type CacheInterfaceCatalogFacts { identity: CacheInterfaceId backing_surface: StorageSurface diff --git a/dsl/extdeps/clock/clock.dag b/dsl/extdeps/clock/clock.dag index 1355abb2093..395c792f91c 100644 --- a/dsl/extdeps/clock/clock.dag +++ b/dsl/extdeps/clock/clock.dag @@ -1,18 +1,3 @@ -// extdeps/clock/clock.dag -- Wall-clock observation (POSIX date utility). -// -// Spec: POSIX.1 date utility — https://pubs.opengroup.org/onlinepubs/9699919799/utilities/date.html -// -// Host-effect peer of extdeps/filesystem/filesystem_io.dag: a read-only service -// whose operations the v1 interpreter dispatches live via the `shell` transport. -// `Clock.Now()` returns ISO 8601 Timestamp for DAG consumers. `Clock.UnixSecs()` -// returns epoch seconds for fixture `recorded_at` / freshness (bootstrap wet -// path — cannot route through the fixture seam without circular lookup). -// -// 🟡 dissolved — feature:clock-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch -// --fixture-store (recorded wet via --record); forbidden: reintroducing mock_response -// constants for Hermetic dispatch on this shape. - module extdeps.clock import std.types { Timestamp } @@ -29,7 +14,6 @@ service Clock { } } - // Epoch-second observation for fixture infrastructure (recorded_at / freshness). operation UnixSecs { input {} output { unix_secs: String from "stdout" } diff --git a/dsl/extdeps/cloud/cloud.dag b/dsl/extdeps/cloud/cloud.dag index ada6a7e3c2f..3100feb3ae8 100644 --- a/dsl/extdeps/cloud/cloud.dag +++ b/dsl/extdeps/cloud/cloud.dag @@ -1,21 +1,7 @@ -// extdeps/cloud/core.dag -- "What is a cloud provider?" -// -// Universal concepts shared across GCP, AWS, and Azure. -// Types only -- concrete values live in provider-specific core.dag files. -// -// Consumers: -// extdeps/cloud/gcp/core.dag -- GCP-specific identity, endpoints -// extdeps/cloud/aws/core.dag -- AWS-specific ARNs, SigV4 -// extdeps/cloud/azure/core.dag -- Azure-specific tenants, subscriptions - module extdeps.cloud.cloud import std.types { AuthScheme } -// Coproduct dissolution classification (DESIGN.md §2 decompress->map->reduce): -// 🟡 partial enumeration — kills the anemic String leaf for cited in-repo SigV4 signers. -// AWS publishes more regions/services than modeled here; extend variants when a cited row -// needs one outside this set (dissolution-trigger: grow on first cited out-of-set need). type AwsRegion = UsEast1 | UsEast2 @@ -26,8 +12,6 @@ type AwsRegion | ApSoutheast1 | ApNortheast1 -// 🟡 partial enumeration — kills the anemic String leaf for cited in-repo SigV4 signers. -// dissolution-trigger: extend variants when a cited row needs a service outside this set. type AwsService = S3 | Iam @@ -68,57 +52,40 @@ fn aws_service_wire_label(service: AwsService) -> String { } } -// -- Service endpoints --------------------------------------------- - type ServiceEndpoint { base_url: String version: String regional: Bool } -// -- Rate limiting ------------------------------------------------- - type RateLimitPolicy { requests_per_minute: Int burst: Int? scope: String } -// -- Cloud auth (Layer 2) ------------------------------------------ -// Composes protocol-level AuthScheme from std/ with provider-specific -// schemes. Provider services project the subset they actually use. -// AWS: SigV4. GCP: OidcToken. Azure: Bearer (already in std/). - type CloudAuthScheme = Protocol { scheme: AuthScheme } | SigV4 { region: AwsRegion, service: AwsService } | OidcToken { audience: String } -// -- Credentials --------------------------------------------------- - type CloudCredential { scheme: CloudAuthScheme scopes: List? expires_seconds: Int? } -// -- Idempotency --------------------------------------------------- - type IdempotencyToken { header: String format: String } -// -- Quotas -------------------------------------------------------- - type CloudQuota { resource: String limit: Int scope: String } -// -- Regions ------------------------------------------------------- - type CloudRegion { provider: String name: String diff --git a/dsl/extdeps/cloud/gcp/errors.dag b/dsl/extdeps/cloud/gcp/errors.dag index fbc220b07cc..321ba466242 100644 --- a/dsl/extdeps/cloud/gcp/errors.dag +++ b/dsl/extdeps/cloud/gcp/errors.dag @@ -1,11 +1,3 @@ -// extdeps/cloud/gcp/errors.dag -- GCP API error envelope shapes. -// -// Two distinct upstream wire shapes are modeled here, one per spec: -// GcpErrorShape -- Google APIs canonical RPC-status envelope -// (https://cloud.google.com/apis/design/errors#http_mapping) -// GcpOAuth2ErrorShape -- RFC 6749 §5.2 OAuth2 token-endpoint error -// (https://datatracker.ietf.org/doc/html/rfc6749#section-5.2) - module extdeps.cloud.gcp.errors type GcpErrorDetails { diff --git a/dsl/extdeps/cloud/gcp/gcp.dag b/dsl/extdeps/cloud/gcp/gcp.dag index 2e42d600fbf..b9d0d13ddb2 100644 --- a/dsl/extdeps/cloud/gcp/gcp.dag +++ b/dsl/extdeps/cloud/gcp/gcp.dag @@ -1,32 +1,12 @@ -// extdeps/cloud/gcp/gcp.dag -- "What is GCP?" -// -// GCP identity model: projects, service accounts, OAuth2 scopes, -// Workload Identity Federation, API endpoint patterns, regions, -// and the transport bindings of GCP auth operations. OAuth2 token refresh -// is modeled once (oauth2.Google.Refresh, REST -- the canonical handler); -// gcloud-CLI shell ops are a distinct surface, not a duplicate of it. -// -// Complements extdeps/api/gcp_ops.dag (which covers retries, -// propagation delays, and operational constraints). -// -// Consumers: -// extdeps/cloud/gcp/{storage,pubsub,iam,secret_manager,cloud_run,sts}.dag -// gunbc/auth/patterns.dag -- credential chain - module extdeps.cloud.gcp.gcp import extdeps.cloud.cloud { ServiceEndpoint } import std.types { FilePath, NonEmptyStr, Secret, HttpMethod, AuthScheme } import extdeps.cloud.gcp.errors { GcpErrorShape, GcpOAuth2ErrorShape } -// -- Grounded identifier refinements -------------------------------- -// Cite: cloud.google.com/resource-manager/docs/creating-managing-projects -// GcpProjectId: restore `where pattern("^[a-z][a-z0-9-]{4,28}[a-z0-9]$")` post-Q-Regex. type GcpProjectId = String where non_empty -// ServiceAccountEmail: restore `where pattern("^[a-z][a-z0-9-]*@[a-z0-9-]+\\.iam\\.gserviceaccount\\.com$")` post-Q-Regex. -type ServiceAccountEmail = String -// -- Projects ------------------------------------------------------ +type ServiceAccountEmail = String type GcpProject { project_id: GcpProjectId @@ -34,8 +14,6 @@ type GcpProject { name: String } -// -- Service accounts ---------------------------------------------- - type GcpServiceAccount { email: ServiceAccountEmail unique_id: String @@ -43,13 +21,6 @@ type GcpServiceAccount { disabled: Bool } -// -- Credential acquisition (GCP-specific flows) ------------------- -// Provider-neutral flows live in std.credentials; Workload Identity Federation, -// interactive gcloud OAuth, and local OAuth2 access-token strategies are grounded here. -// Token refresh is one interface shape (oauth2.Google.Refresh below); ADC file-read and -// gcloud CLI print-access-token are N peripheral handlers composed in gunbc.auth.credentials -// — not forked re-implementations of the endpoint (DESIGN.md §3). - type GcpOAuth2AccessTokenStrategy = AdcRefresh { adc_path: FilePath? } | GcloudCli @@ -63,8 +34,6 @@ type GcpCredentialFlow | InteractiveAuth { scopes: List } | OAuth2AccessToken { strategy: GcpOAuth2AccessTokenStrategy } -// -- OAuth2 scopes ------------------------------------------------- - type OAuth2Scope { scope: String description: String @@ -78,8 +47,6 @@ data common_scopes: List = [ { scope: "https://www.googleapis.com/auth/secretmanager", description: "Secret Manager access" } ] -// -- Workload Identity Federation ---------------------------------- - type WifPool { name: String project: String @@ -94,9 +61,6 @@ type WifProvider { attribute_mapping: Map? } -// -- API endpoints ------------------------------------------------- -// Pattern: {service}.googleapis.com/{version} - type GcpService = GcpStorage | GcpIam @@ -131,8 +95,6 @@ data api_endpoints: List = [ { service: GcpSts, base_url: "https://sts.googleapis.com/v1", version: "v1" } ] -// -- Regions ------------------------------------------------------- - type GcpRegion { name: String zones: List @@ -148,13 +110,6 @@ data regions: List = [ { name: "eu", zones: [], multi_region: true } ] -// -- Service: GCP auth operations (shell + REST transport) ------- - -// 🟡 dissolved — feature:gcp-cloud-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); the published corpus (extdeps.cloud.gcp.mock_corpus) now governs -// WHICH gcloud.Auth ops are hermetically realizable, and the fixture store owns the payloads (§3). -// forbidden: reintroducing mock_response constants for Hermetic dispatch on these shapes. service gcloud.Auth { operation Login { input {} @@ -174,7 +129,7 @@ service gcloud.Auth { refresh_token: Secret } readonly - // Parses JSON: extracts client_id, client_secret, refresh_token + transport file { op: READ, path: "\{path\}" } } } @@ -186,17 +141,6 @@ type GoogleOAuth2Refresh200Body { scope: String? } -// OAuth2 token refresh: ONE interface shape (this service), N transport handlers elsewhere. -// REST is the cited upstream contract (RFC 6749 §6); gcloud.Auth.ReadADC (file) supplies -// refresh inputs; shell.GCloud.AuthPrintAccessToken (shell) is an alternate acquisition path. -// Materializers: gunbc.auth.credentials.gcp_oauth_access_token(strategy) dispatches -// GcpOAuth2AccessTokenStrategy to leaf handlers below. -// -// 🟡 dissolved — feature:gcp-cloud-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); the published corpus (extdeps.cloud.gcp.mock_corpus) now governs -// WHICH oauth2.Google ops are hermetically realizable, and the fixture store owns the payloads (§3). -// forbidden: reintroducing mock_response constants for Hermetic dispatch on these shapes. service oauth2.Google { config { endpoint: "https://oauth2.googleapis.com" } @@ -210,8 +154,7 @@ service oauth2.Google { access_token: Secret from "access_token" expires_in: Int from "expires_in" } - // Derivation unknown: POST /token has no path key. - // Idempotency is spec-declared per RFC 6749 §6 for a given refresh_token. + idempotent transport rest { method: POST, path: "/token" } response { @@ -223,18 +166,6 @@ service oauth2.Google { } } -// NOTE: the OAuth2 token-refresh endpoint is GCP's REST API, modeled faithfully -// by `oauth2.Google.Refresh` above. A former `shell.OAuth2.RefreshToken` op -// re-implemented that same endpoint with hand-rolled curl + form-encoding -- a -// business bridge masquerading as a distinct dependency, with a known JSON/encoding -// defect its own comment flagged. Removed: there is exactly one model of the -// refresh endpoint, and `curl` is a transport, not a second handler we owe here. - -// 🟡 dissolved — feature:gcp-cloud-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); the published corpus (extdeps.cloud.gcp.mock_corpus) now governs -// WHICH shell.GCloud ops are hermetically realizable, and the fixture store owns the payloads (§3). -// forbidden: reintroducing mock_response constants for Hermetic dispatch on these shapes. service shell.GCloud { operation AuthPrintAccessToken { input {} diff --git a/dsl/extdeps/cloud/gcp/iam.dag b/dsl/extdeps/cloud/gcp/iam.dag index 76b92aff3c1..045fc2fd463 100644 --- a/dsl/extdeps/cloud/gcp/iam.dag +++ b/dsl/extdeps/cloud/gcp/iam.dag @@ -1,20 +1,9 @@ -// extdeps/cloud/gcp/iam.dag -- "What is GCP IAM?" -// -// IAM resource model: roles, bindings, policies, impersonation -// chains, token lifetimes. -// -// Consumers: -// gunbc/auth/patterns.dag -- credential_chain pattern -// gunbc/auth/patterns.dag -- credential_chain pattern - module extdeps.cloud.gcp.iam import extdeps.cloud.gcp.gcp { GcpServiceAccount, GcpProject, GcpProjectId, ServiceAccountEmail } import extdeps.cloud.gcp.errors { GcpErrorShape } import std.types { HttpMethod, AuthScheme } -// -- Roles --------------------------------------------------------- - type GcpRole { name: String title: String @@ -33,8 +22,6 @@ data common_roles: List = [ { name: "roles/run.invoker", title: "Cloud Run Invoker", permissions: null, predefined: true } ] -// -- Bindings & policies ------------------------------------------- - type IamCondition { title: String expression: String @@ -53,16 +40,12 @@ type GcpPolicy { version: Int } -// -- Impersonation ------------------------------------------------- - type ImpersonationChain { source: String target: String delegates: List } -// -- Token lifetimes ----------------------------------------------- - type TokenLifetime { default_seconds: Int max_seconds: Int @@ -78,21 +61,14 @@ type GcpGenerateAccessToken200Body { expire_time: String from "expireTime" } -// -- Service: REST transport wiring ------------------------------ - -// 🟡 dissolved — feature:gcp-cloud-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); the published corpus (extdeps.cloud.gcp.mock_corpus) now governs -// WHICH gcp.IAM ops are hermetically realizable, and the fixture store owns the payloads (§3). -// forbidden: reintroducing mock_response constants for Hermetic dispatch on these shapes. service gcp.IAM { config { endpoint: "https://iamcredentials.googleapis.com" auth: Bearer auth_input: access_token - // GCP IAM Credentials rate limits: 60 requests/min per service account + rate_limit: { requests: 60, per: minute, scope: iam_credentials } - // Retry on quota exceeded and server errors with exponential backoff + retry: { max_attempts: 3, backoff: exponential, retry_on: [429, 500, 503] } } @@ -106,8 +82,7 @@ service gcp.IAM { access_token: Secret from "accessToken" expire_time: String from "expireTime" } - // Derivation unknown: POST derives CreateEffect (fail-closed). - // Idempotency is declared per Google API semantics for generateAccessToken. + idempotent transport rest { method: POST, path: "/v1/projects/-/serviceAccounts/\{target_sa\}:generateAccessToken" } response { @@ -121,11 +96,6 @@ service gcp.IAM { } } -// 🟡 dissolved — feature:gcp-cloud-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); the published corpus (extdeps.cloud.gcp.mock_corpus) now governs -// WHICH gcp.ResourceManager ops are hermetically realizable, and the fixture store owns the payloads (§3). -// forbidden: reintroducing mock_response constants for Hermetic dispatch on these shapes. service gcp.ResourceManager { config { endpoint: "https://cloudresourcemanager.googleapis.com", auth: Bearer, auth_input: access_token } diff --git a/dsl/extdeps/cloud/gcp/mock_corpus.dag b/dsl/extdeps/cloud/gcp/mock_corpus.dag index 582c6b86eae..a4a3fc5a55f 100644 --- a/dsl/extdeps/cloud/gcp/mock_corpus.dag +++ b/dsl/extdeps/cloud/gcp/mock_corpus.dag @@ -1,27 +1,7 @@ -// dsl/extdeps/cloud/gcp/mock_corpus.dag -// Scope: the GCP cloud layer's PUBLISHED mock corpus as a closed, declared structural fact. -// Anchor: DESIGN.md §3 (single authority) / §6 (model-just-in-time, mark the carrier). -// -// SINGLE authority for WHICH gcloud.Auth / oauth2.Google / shell.GCloud / gcp.IAM / -// gcp.ResourceManager / gcp.SecretManager / gcp.STS / github.OIDC / gcp.Metadata operations -// are hermetically realizable. Read by BOTH the compile-time M2 mock_totality_lens -// (src/v2/lens/mock_totality.dag, via the per-layer witness) AND the v1 runtime's -// eval_service_call (the M4 hermetic-realization fold) — one model, not two. The v1 runtime -// loads the dsl/ tree via the M4.1 whole-tree corpus load (#5236), so no per-service -// co-location import is required. Modeled on the M4.0 filesystem pilot -// (dsl/extdeps/filesystem/mock_corpus.dag, #5188). -// -// Rows inhabit std.hermetic_replay.PublishedMockCase (all 4 fields: service, operation, -// operation_key, case_id). The operation set authority remains the respective service decls in -// dsl/extdeps/cloud/gcp/{gcp,iam,secret_manager,sts}.dag; per-case payloads live in the -// Phase-2 RecordedFixture store ONLY — rows carry the (operation_key, case_id) structural key. - module extdeps.cloud.gcp.mock_corpus import std.hermetic_replay { PublishedMockCase } -// -- gcloud.Auth --------------------------------------------------- - data gcloud_auth_mock_case_login: PublishedMockCase = PublishedMockCase { operation_key: "gcloud.Auth.Login", service: "gcloud.Auth", @@ -36,8 +16,6 @@ data gcloud_auth_mock_case_read_adc: PublishedMockCase = PublishedMockCase { case_id: 0 } -// -- oauth2.Google ------------------------------------------------- - data oauth2_google_mock_case_refresh: PublishedMockCase = PublishedMockCase { operation_key: "oauth2.Google.Refresh", service: "oauth2.Google", @@ -45,8 +23,6 @@ data oauth2_google_mock_case_refresh: PublishedMockCase = PublishedMockCase { case_id: 0 } -// -- shell.GCloud -------------------------------------------------- - data shell_gcloud_mock_case_auth_print_access_token: PublishedMockCase = PublishedMockCase { operation_key: "shell.GCloud.AuthPrintAccessToken", service: "shell.GCloud", @@ -54,8 +30,6 @@ data shell_gcloud_mock_case_auth_print_access_token: PublishedMockCase = Publish case_id: 0 } -// -- gcp.IAM ------------------------------------------------------- - data gcp_iam_mock_case_generate_access_token: PublishedMockCase = PublishedMockCase { operation_key: "gcp.IAM.GenerateAccessToken", service: "gcp.IAM", @@ -63,8 +37,6 @@ data gcp_iam_mock_case_generate_access_token: PublishedMockCase = PublishedMockC case_id: 0 } -// -- gcp.ResourceManager ------------------------------------------- - data gcp_resource_manager_mock_case_get_iam_policy: PublishedMockCase = PublishedMockCase { operation_key: "gcp.ResourceManager.GetIamPolicy", service: "gcp.ResourceManager", @@ -79,8 +51,6 @@ data gcp_resource_manager_mock_case_set_iam_policy: PublishedMockCase = Publishe case_id: 0 } -// -- gcp.SecretManager --------------------------------------------- - data gcp_secret_manager_mock_case_access_version: PublishedMockCase = PublishedMockCase { operation_key: "gcp.SecretManager.AccessVersion", service: "gcp.SecretManager", @@ -102,8 +72,6 @@ data gcp_secret_manager_mock_case_add_version: PublishedMockCase = PublishedMock case_id: 0 } -// -- gcp.STS ------------------------------------------------------- - data gcp_sts_mock_case_exchange: PublishedMockCase = PublishedMockCase { operation_key: "gcp.STS.Exchange", service: "gcp.STS", @@ -111,8 +79,6 @@ data gcp_sts_mock_case_exchange: PublishedMockCase = PublishedMockCase { case_id: 0 } -// -- github.OIDC --------------------------------------------------- - data github_oidc_mock_case_get_token: PublishedMockCase = PublishedMockCase { operation_key: "github.OIDC.GetToken", service: "github.OIDC", @@ -120,8 +86,6 @@ data github_oidc_mock_case_get_token: PublishedMockCase = PublishedMockCase { case_id: 0 } -// -- gcp.Metadata -------------------------------------------------- - data gcp_metadata_mock_case_get_identity_token: PublishedMockCase = PublishedMockCase { operation_key: "gcp.Metadata.GetIdentityToken", service: "gcp.Metadata", @@ -129,15 +93,6 @@ data gcp_metadata_mock_case_get_identity_token: PublishedMockCase = PublishedMoc case_id: 0 } -// 🟡 gated — feature:gcp-cloud-mock-corpus-from-service-decl — bind node://adhoc-743f3949-b3b -// dissolve-on-arrival: project this corpus directly from the service operation sets in -// dsl/extdeps/cloud/gcp/{gcp,iam,secret_manager,sts}.dag (the SINGLE authority for WHICH -// operations exist), joined with the Phase-2 RecordedFixture store (the authority for WHICH -// recorded cases exist per operation), once a v2 lens can read a service decl's operation nodes -// and the fixture store's keys; this declared list then deletes in the same PR. forbidden: a row -// carrying a response VALUE — that would fork the payload authority, now owned by the fixture -// store (§3); rows mirror the (operation_key, case_id) structural key ONLY, and grow when a -// published operation/case is added upstream. data gcp_published_mock_corpus: List = [ gcloud_auth_mock_case_login, gcloud_auth_mock_case_read_adc, diff --git a/dsl/extdeps/cloud/gcp/secret_manager.dag b/dsl/extdeps/cloud/gcp/secret_manager.dag index d6f7dd49f25..37d0845b43b 100644 --- a/dsl/extdeps/cloud/gcp/secret_manager.dag +++ b/dsl/extdeps/cloud/gcp/secret_manager.dag @@ -1,14 +1,3 @@ -// extdeps/cloud/gcp/secret_manager.dag -- "What is GCP Secret Manager?" -// -// Secret Manager resource model: secrets, versions, replication, -// rotation, access policies. -// -// Complements extdeps/secrets/gcp_secret_manager.dag (which covers -// behavioral specs for coordination/access patterns). -// -// Consumers: -// gunbc/auth/patterns.dag -- credential-chain secret access - module extdeps.cloud.gcp.secret_manager import extdeps.cloud.gcp.gcp { GcpProject, GcpProjectId } @@ -16,8 +5,6 @@ import extdeps.cloud.gcp.errors { GcpErrorShape } import std.types { HttpMethod, AuthScheme, Bytes, Secret } import std.encoding { utf8_decode_bytes } -// -- Replication --------------------------------------------------- - type SmReplica { location: String } @@ -26,8 +13,6 @@ type SmReplication = Automatic | UserManaged { replicas: List } -// -- Secrets ------------------------------------------------------- - type GcpSecret { name: String project: String @@ -36,8 +21,6 @@ type GcpSecret { create_time: String } -// -- Versions ------------------------------------------------------ - type SmVersionState = SmEnabled | SmDisabled | SmDestroyed type GcpSecretVersion { @@ -46,51 +29,31 @@ type GcpSecretVersion { create_time: String } -// -- Payload ------------------------------------------------------- - type SecretPayload { data: Bytes } -// -- Rotation ------------------------------------------------------ - type SmRotationSchedule { next_rotation_time: String? rotation_period_seconds: Int? } -// -- Constants ----------------------------------------------------- - data max_secret_size_bytes: Int = 65536 data max_versions: Int = 1000 -// RFC 3629 UTF-8 decode of Secret Manager access payload bytes → Secret. -// REST AccessVersion returns decoded payload bytes from the wire `data` field; -// text secrets (tokens, passwords) cross this boundary before the Secret carrier. fn utf8_secret_from_access_payload(payload: Bytes) -> Secret { utf8_decode_bytes(payload: payload) as Secret } -// -- Service: REST transport wiring ------------------------------ -// -// Secret Manager access is modeled once here (REST — the cited upstream API). -// Local gcloud dev paths compose shell.GCloud.AuthPrintAccessToken (auth handler) -// with AccessVersion — not a forked shell.GCloud.SecretManagerAccessVersion op. - -// 🟡 dissolved — feature:gcp-cloud-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); the published corpus (extdeps.cloud.gcp.mock_corpus) now governs -// WHICH gcp.SecretManager ops are hermetically realizable, and the fixture store owns the payloads (§3). -// forbidden: reintroducing mock_response constants for Hermetic dispatch on these shapes. service gcp.SecretManager { config { endpoint: "https://secretmanager.googleapis.com" auth: Bearer auth_input: access_token - // GCP Secret Manager rate limits: 1000 requests/min per project + rate_limit: { requests: 1000, per: minute, scope: secret_manager } - // Retry on quota exceeded and server errors with exponential backoff + retry: { max_attempts: 3, backoff: exponential, retry_on: [429, 500, 503] } } @@ -134,8 +97,7 @@ service gcp.SecretManager { operation AddVersion { input { access_token: Secret, secret_name: String, payload: Bytes } output { name: String } - // Derivation unknown: POST derives CreateEffect (fail-closed). - // Idempotency is declared per Google API semantics for addVersion. + idempotent transport rest { method: POST, path: "/v1/\{secret_name\}:addVersion" } response { diff --git a/dsl/extdeps/cloud/gcp/sts.dag b/dsl/extdeps/cloud/gcp/sts.dag index bf0b3837880..d76ac56a823 100644 --- a/dsl/extdeps/cloud/gcp/sts.dag +++ b/dsl/extdeps/cloud/gcp/sts.dag @@ -1,31 +1,13 @@ -// extdeps/cloud/gcp/sts.dag -- "What is GCP Security Token Service?" -// -// STS token exchange model: grant types, subject token types, -// token responses. Used for Workload Identity Federation. -// -// Consumers: -// gunbc/auth/patterns.dag -- credential_chain pattern -// gunbc/auth/patterns.dag -- credential_chain pattern - module extdeps.cloud.gcp.sts import std.types { Url, HttpMethod, AuthScheme } import extdeps.cloud.gcp.errors { GcpErrorShape, GcpOAuth2ErrorShape } import extdeps.github.errors { GitHubErrorShape } -// -- Token types --------------------------------------------------- - type SubjectTokenType = Jwt | StsAccessToken | IdToken | Saml2 type RequestedTokenType = RequestAccessToken | RequestIdToken -// -- Grant type ---------------------------------------------------- - -// StsGrantType: single value "urn:ietf:params:oauth:grant-type:token-exchange" -// Modeled as String since there is only one grant type for STS. - -// -- Token exchange response --------------------------------------- - type StsTokenResponse { access_token: String issued_token_type: String @@ -42,8 +24,6 @@ type MetadataRuntime {} data metadata_runtime: MetadataRuntime = {} -// -- Constants ----------------------------------------------------- - data sts_endpoint: Url = "https://sts.googleapis.com/v1/token" data default_grant_type: String = "urn:ietf:params:oauth:grant-type:token-exchange" @@ -52,19 +32,12 @@ data jwt_subject_token_type: String = "urn:ietf:params:oauth:token-type:jwt" data access_token_type: String = "urn:ietf:params:oauth:token-type:access_token" -// -- Service: REST transport wiring ------------------------------ - -// 🟡 dissolved — feature:gcp-cloud-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); the published corpus (extdeps.cloud.gcp.mock_corpus) now governs -// WHICH gcp.STS ops are hermetically realizable, and the fixture store owns the payloads (§3). -// forbidden: reintroducing mock_response constants for Hermetic dispatch on these shapes. service gcp.STS { config { endpoint: "https://sts.googleapis.com" - // GCP STS rate limits: token exchange has high limits (1000/min) + rate_limit: { requests: 1000, per: minute, scope: sts } - // Retry on quota exceeded and server errors with exponential backoff + retry: { max_attempts: 3, backoff: exponential, retry_on: [429, 500, 503] } } @@ -77,10 +50,7 @@ service gcp.STS { access_token: Secret from "access_token" expires_in: Int from "expires_in" } - // Body includes grant_type and token_type fields -- the compiler - // generates the full OAuth2 token exchange request from these inputs. - // Derivation unknown: POST /v1/token has no path key. - // Idempotency is spec-declared per RFC 8693 for a given subject_token. + idempotent transport rest { method: POST, path: "/v1/token" } response { @@ -94,20 +64,7 @@ service gcp.STS { } } -// OIDC token providers -- these are not GCP services but are used -// to acquire subject tokens for the STS exchange. - -// 🟡 dissolved — feature:gcp-cloud-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); the published corpus (extdeps.cloud.gcp.mock_corpus) now governs -// WHICH github.OIDC ops are hermetically realizable, and the fixture store owns the payloads (§3). -// forbidden: reintroducing mock_response constants for Hermetic dispatch on these shapes. service github.OIDC { - // Endpoint and auth token come from per-job env vars on GitHub Actions - // (ACTIONS_ID_TOKEN_REQUEST_URL / ACTIONS_ID_TOKEN_REQUEST_TOKEN). - // Both are wired as explicit data-flow inputs by github_oidc() in - // gunbc/auth/patterns.dag so that skip propagation handles the - // "not on GitHub Actions" case without any runtime Rust. operation GetToken { input { @@ -127,18 +84,13 @@ service github.OIDC { } } -// 🟡 dissolved — feature:gcp-cloud-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); the published corpus (extdeps.cloud.gcp.mock_corpus) now governs -// WHICH gcp.Metadata ops are hermetically realizable, and the fixture store owns the payloads (§3). -// forbidden: reintroducing mock_response constants for Hermetic dispatch on these shapes. service gcp.Metadata { config { endpoint: "http://metadata.google.internal" } operation GetIdentityToken { input { audience: NonEmptyStr } output { subject_token: Secret } - // Response body IS the token (not JSON), parsed as raw string. + readonly transport rest { method: GET, path: "/computeMetadata/v1/instance/service-accounts/default/identity?audience=\{audience\}" } response { diff --git a/dsl/extdeps/cloud/hetzner.dag b/dsl/extdeps/cloud/hetzner.dag index 93357a6de84..709922043df 100644 --- a/dsl/extdeps/cloud/hetzner.dag +++ b/dsl/extdeps/cloud/hetzner.dag @@ -1,13 +1,3 @@ -// extdeps/cloud/hetzner.dag — Hetzner Cloud facts (vendor catalog authority). -// -// Anchor: https://docs.hetzner.com/cloud/servers/overview -// -// Spec: https://docs.hetzner.com/cloud/servers/overview (CAX server-type table) -// Pricing: https://docs.hetzner.com/general/infrastructure-and-availability/price-adjustment/ -// (GE-D9256; Germany/Finland CAX rows effective 2026-04-01, ex-VAT) -// -// Consumers: product.compute_fabric supply rows (cross-provider isolation witnesses). - module extdeps.cloud.hetzner import extdeps.toolchain.types { Architecture } @@ -46,8 +36,6 @@ type HetznerCloudServerCatalogRow { cpu_architecture: Architecture } -// CAX41 — 16 Ampere® vCPU, 32 GiB RAM, 320 GB SSD (hetzner.com/cloud cost-optimized). -// Hourly €0.0505 / monthly cap €31.49 — docs price-adjustment Germany/Finland 2026-04-01. data cax41_catalog: HetznerCloudServerCatalogRow = HetznerCloudServerCatalogRow { server_type: Cax41, vcpus: hardware_thread_count(16), diff --git a/dsl/extdeps/communication/medium.dag b/dsl/extdeps/communication/medium.dag index 05bbc12358a..c23e62a547e 100644 --- a/dsl/extdeps/communication/medium.dag +++ b/dsl/extdeps/communication/medium.dag @@ -1,53 +1,3 @@ -// extdeps/communication/medium.dag — a recorded means of communication (cited). -// -// Anchor: https://en.wikipedia.org/wiki/Means_of_communication -// -// In the cited "means of communication" framework, a *medium* is the carrier by -// which a sender conveys an idea to a receiver. The framework sorts means by -// transfer type — verbal (speech, telephony), written, screen-oriented, and -// records-transport — and cross-cuts those with natural (speech, gesture: no -// encode step) vs technical (writing, printing, digital: an explicit -// encode -> carry -> decode). -// -// THIS module models one SPECIFIC means: the *recorded / encoded* medium — an -// idea encoded into a carried representation `R`, recovered by a decode whose -// information-preservation is the `fidelity` axis (Lossless | Lossy). That decode -// round-trip is exactly what distinguishes a technical/recorded medium from a -// natural one (speech has no Lossless/Lossy decode of a stored `R`). So `Medium` -// is NOT the framework's universal carrier concept — it is a cited realization of -// one branch of it. That is why it lives in extdeps and not std (§3: the agnostic -// concept stays central; a specific cited realization migrates outward, citing its -// source). The genuinely agnostic carrier (a `Carrier` with no decode/fidelity, -// which this recorded medium would extend) is not modeled yet — no consumer needs -// it; mint it in std only when one does, not by re-coining it here. -// -// Pure model only — no pipeline fold, no Node/RuntimeValue (dsl/std has neither; -// this dsl-tree extdeps module stays equally substrate-free so src/v2 can import it -// cross-tree, exactly as it imports dsl/std). -// -// Layer split (§3): -// extdeps/communication/medium.dag — Medium + DecodeFidelity (this file) -// dsl/std/encoding.dag — byte-sequence character interpretation lattice -// dsl/std/fidelity.dag — TransportClass cost/hermetic axis (unrelated) -// v2/extdeps/languages/fidelity.dag — per-feature FidelityDisposition -// v2/std/text.dag — Unicode text carriers -// -// NAME DISCIPLINE (§3 — SIGNED OFF eager-boar-790 2026-06-18): -// Types stay `Medium` + `DecodeFidelity`. `Surface`/`Vehicle` rejected -// (collision / non-standard naming). Do NOT use `Carrier` for THIS type -// (overloaded: collection backing, text, classification axis, fact-bearing Node — -// and reserved above for the future agnostic carrier). Do NOT use bare `Fidelity` -// — collides with extdeps FidelityDisposition AND dsl/std/fidelity.dag -// TransportClass axis. Do not nickname as TextMedium / ByteMedium / StorageMedium -// (`product.compute_fabric.StorageMedium` is an unrelated product axis). -// Operator retains pre-merge veto. -// -// FidelityDisposition compose-up (NOT a re-coin): per-feature -// `FidelityDisposition` rows (v2/extdeps/languages/fidelity.dag) compose -// UP into medium-level `DecodeFidelity` via a future reduce at the medium-decode -// boundary. This module owns the reduced medium-axis verdict (Lossless | Lossy); -// feature-level dispositions remain in extdeps until that reduce lands. - module extdeps.communication.medium import extdeps.external_authority { ExternalAuthority } @@ -60,25 +10,8 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// Whether decoding from a medium back to semantic values loses information. -// -// DECOMPOSITION CHECKPOINT (DESIGN.md §2): 🟢 PRIMITIVE -// Two mutually exclusive decode policies. Consumers `match` on the variant — no -// substrate `is_*` Bool lift (predicate dissolution). type DecodeFidelity = Lossless | Lossy -// An idea carried in an external medium. -// -// Field ledger (§2 decompress — each field must be genuinely atomic): -// carried: R — the represented value in this medium instance. Typed by `` so -// text (R=String), verdicts (R=ProbeVerdict), values, binaries, … share one -// carrier without a text-flavored `form: String` discriminator (that would be -// redundant when R=String and would bias non-text media toward stringly encoding). -// fidelity: DecodeFidelity — whether decode from this medium back to semantic -// values preserves information for this instance. -// -// DECOMPOSITION CHECKPOINT (DESIGN.md §2): 🟢 PRIMITIVE -// Two atomic axes (carried value + decode policy); no third "kind" field at this layer. type Medium { carried: R fidelity: DecodeFidelity diff --git a/dsl/extdeps/container/oci/ctrl_session_witness.dag b/dsl/extdeps/container/oci/ctrl_session_witness.dag index d23b8ffc1f8..d89fd649897 100644 --- a/dsl/extdeps/container/oci/ctrl_session_witness.dag +++ b/dsl/extdeps/container/oci/ctrl_session_witness.dag @@ -1,11 +1,3 @@ -// extdeps/container/oci/ctrl_session_witness.dag — decode ctrl-session:latest OCI facts (arm64). -// -// Fixture: ctrl-session:latest exported 2026-06-14 (docker save → blobs/sha256/*). -// Anchors: image-spec manifest.md + config.md; runtime-spec config.md + config-linux.md. -// -// Witnesses: green-by-execution via `gunbc run --source-root dsl --entry ... --claim-run`. -// 🟡 consumer:dsl-rooted-claim-run-gate — not CI-enrolled until dsl corpus gate lands. - module extdeps.container.oci.ctrl_session_witness import extdeps.container.oci.descriptor { @@ -96,9 +88,6 @@ data ctrl_session_layer0_digest: ContentHash = "sha256:402614bd39aaec1e4bdcf25aa data ctrl_session_layer0_size: Int = 28122307 -// Slice-0 fixture encodes manifest layer[0] + matching rootfs diff_ids[0] only -// (full ctrl-session export has 33 layers; not all inlined in this witness). - data ctrl_session_first_diff_id: ContentHash = "sha256:5e34d05421f9491747bc11c68b1a7f5029b0aefb18eb9166935ac52be45fb299" data ctrl_session_manifest: ImageManifest = { diff --git a/dsl/extdeps/container/oci/descriptor.dag b/dsl/extdeps/container/oci/descriptor.dag index e7dcfa967a1..b9d1cc138d6 100644 --- a/dsl/extdeps/container/oci/descriptor.dag +++ b/dsl/extdeps/container/oci/descriptor.dag @@ -1,8 +1,3 @@ -// extdeps/container/oci/descriptor.dag — OCI Content Descriptor (image-spec descriptor.md). -// -// Spec: https://github.com/opencontainers/image-spec/blob/main/descriptor.md -// Version: image-spec v1.1.0 - module extdeps.container.oci.descriptor import extdeps.container.oci.types { OciMediaType } diff --git a/dsl/extdeps/container/oci/image_config.dag b/dsl/extdeps/container/oci/image_config.dag index bb2d399fbf4..a094cd4d456 100644 --- a/dsl/extdeps/container/oci/image_config.dag +++ b/dsl/extdeps/container/oci/image_config.dag @@ -1,8 +1,3 @@ -// extdeps/container/oci/image_config.dag — OCI Image Configuration (image-spec config.md). -// -// Spec: https://github.com/opencontainers/image-spec/blob/main/config.md -// Version: image-spec 1.1.0 - module extdeps.container.oci.image_config import extdeps.container.oci.types { @@ -33,7 +28,6 @@ type ImageConfiguration { rootfs: ImageRootfs } -// dissolve-on: delete ImageConfigRejectUnspecified when a second real reject reason lands. type ImageConfigRejectReason = EmptyDiffIds | ImageConfigRejectUnspecified diff --git a/dsl/extdeps/container/oci/linux.dag b/dsl/extdeps/container/oci/linux.dag index 387bb1034a1..9a18e6bbddf 100644 --- a/dsl/extdeps/container/oci/linux.dag +++ b/dsl/extdeps/container/oci/linux.dag @@ -1,8 +1,3 @@ -// extdeps/container/oci/linux.dag — Linux platform config (runtime-spec config-linux.md). -// -// Spec: https://github.com/opencontainers/runtime-spec/blob/main/config-linux.md -// Version: runtime-spec v1.2.0 - module extdeps.container.oci.linux import std.types { Bool, FilePath } diff --git a/dsl/extdeps/container/oci/manifest.dag b/dsl/extdeps/container/oci/manifest.dag index 5abb0b8b8dc..7de88c7e037 100644 --- a/dsl/extdeps/container/oci/manifest.dag +++ b/dsl/extdeps/container/oci/manifest.dag @@ -1,8 +1,3 @@ -// extdeps/container/oci/manifest.dag — OCI Image Manifest (image-spec manifest.md). -// -// Spec: https://github.com/opencontainers/image-spec/blob/main/manifest.md -// Version: image-spec v1.1.0 - module extdeps.container.oci.manifest import extdeps.container.oci.descriptor { diff --git a/dsl/extdeps/container/oci/media_types.dag b/dsl/extdeps/container/oci/media_types.dag index 7a4a605741d..2d6eda1efe4 100644 --- a/dsl/extdeps/container/oci/media_types.dag +++ b/dsl/extdeps/container/oci/media_types.dag @@ -1,8 +1,3 @@ -// extdeps/container/oci/media_types.dag — OCI Image/Media type constants. -// -// Spec: https://github.com/opencontainers/image-spec/blob/main/media-types.md -// Version: image-spec v1.1.0 (schemaVersion 2) - module extdeps.container.oci.media_types import extdeps.container.oci.types { diff --git a/dsl/extdeps/container/oci/runtime_config.dag b/dsl/extdeps/container/oci/runtime_config.dag index 6b15b8e3230..b393b332a8e 100644 --- a/dsl/extdeps/container/oci/runtime_config.dag +++ b/dsl/extdeps/container/oci/runtime_config.dag @@ -1,8 +1,3 @@ -// extdeps/container/oci/runtime_config.dag — OCI Runtime bundle config (runtime-spec config.md). -// -// Spec: https://github.com/opencontainers/runtime-spec/blob/main/config.md -// Version: runtime-spec v1.2.0 - module extdeps.container.oci.runtime_config import extdeps.container.oci.linux { diff --git a/dsl/extdeps/container/oci/types.dag b/dsl/extdeps/container/oci/types.dag index 8a8e57042e0..07c2a2830d1 100644 --- a/dsl/extdeps/container/oci/types.dag +++ b/dsl/extdeps/container/oci/types.dag @@ -1,8 +1,3 @@ -// extdeps/container/oci/types.dag — shared OCI grounded types (image-spec + runtime-spec). -// -// Wire strings from JSON ingress are parsed into std facts at the boundary; -// egress re-encodes via the paired label functions. Reuse std types — do not re-mint. - module extdeps.container.oci.types import extdeps.toolchain.types { @@ -20,8 +15,6 @@ import extdeps.toolchain.types { } import std.types { ContentHash, FilePath, NonEmptyStr, Port, SemVer, String } -// OCI image-spec GOARCH vocabulary (image-spec config.md `architecture` field). -// Uses extdeps.toolchain.types.Architecture — decode/label functions own the wire boundary. data goarch_amd64_wire: String = "amd64" data goarch_arm64_wire: String = "arm64" data goarch_386_wire: String = "386" @@ -94,7 +87,6 @@ fn image_config_goos_label(os: Os) -> ImageConfigGoosLabel { } } -// Container exposed port (image-spec config.md `ExposedPorts` map keys). type ContainerPortProtocol = Tcp | Udp type ContainerExposedPort { @@ -102,7 +94,6 @@ type ContainerExposedPort { protocol: ContainerPortProtocol } -// Runtime bundle mount kind (runtime-spec config.md `mounts[].type`). type RuntimeMountKind = RuntimeMountBind | RuntimeMountTmpfs @@ -133,8 +124,6 @@ fn runtime_mount_kind_label(kind: RuntimeMountKind) -> String { } } -// Runtime mount source (runtime-spec config.md `mounts[].source`). -// Bind mounts name a host pathname; tmpfs/proc/sys carry a symbolic wire label or omit. type RuntimeMountSource = MountBindSource { host_path: FilePath } | MountSymbolicSource { label: NonEmptyStr } @@ -146,10 +135,8 @@ fn runtime_mount_source_label(source: RuntimeMountSource) -> String { } } -// OCI runtime bundle version (runtime-spec config.md `ociVersion`). type OciRuntimeVersion = SemVer -// OCI media type (image-spec media-types.md). Known registry rows + open escape for extensions. type OciMediaType = OciImageManifestV1 | OciImageConfigV1 diff --git a/dsl/extdeps/cpu.dag b/dsl/extdeps/cpu.dag index 37eb830b928..4faaabdcc9e 100644 --- a/dsl/extdeps/cpu.dag +++ b/dsl/extdeps/cpu.dag @@ -1,9 +1,3 @@ -// extdeps/cpu.dag — CPU concept projections over a vendor-agnostic catalog row. -// -// Types: extdeps.cpu.types. Per-vendor catalog data: extdeps.cpu.. -// This owns only the general CPU concept; it does not enumerate any one -// vendor's parts, so it does NOT dispatch on owned SKUs. - module extdeps.cpu import extdeps.cpu.types { Architecture, CpuFacts } diff --git a/dsl/extdeps/cpu/ampere.dag b/dsl/extdeps/cpu/ampere.dag index c5e3bcb9e4a..2b0f08de5a2 100644 --- a/dsl/extdeps/cpu/ampere.dag +++ b/dsl/extdeps/cpu/ampere.dag @@ -1,18 +1,9 @@ -// extdeps/cpu/ampere.dag — Ampere CPU model catalog (vendor data authority). -// -// Ampere's published Altra-family parts, as extdeps.cpu CpuModelCatalogRow values. -// Vendor hardware is an external dependency: it lives in extdeps/, importing the -// catalog SHAPE from extdeps/cpu. extdeps/cpu owns only the shape; it does not enumerate -// any one vendor's lineup. Which specific part a given host runs is an operator -// deployment fact (ctrl), not a fact about Ampere. - module extdeps.cpu.ampere import extdeps.cpu.types { Architecture, CpuModelCatalogRow, CpuSocket, SocketPackage } import extdeps.vendor.ampere { ampere } import std.measure { hardware_thread_count, hertz, watt } -// Ampere Altra Max M128-30 — 128c/128t, 183W, Neoverse-N1. data altra_max_m12830_catalog: CpuModelCatalogRow = CpuModelCatalogRow { model_number: "M128-30", oem_listing_id: none, @@ -25,7 +16,6 @@ data altra_max_m12830_catalog: CpuModelCatalogRow = CpuModelCatalogRow { tdp_watts: watt(183), } -// Ampere Altra Q64-30 — 64c/64t, 124W. data altra_q6430_catalog: CpuModelCatalogRow = CpuModelCatalogRow { model_number: "Q64-30", oem_listing_id: "AC-106418002", diff --git a/dsl/extdeps/cpu/types.dag b/dsl/extdeps/cpu/types.dag index aeaf7cce5a1..c12cf846461 100644 --- a/dsl/extdeps/cpu/types.dag +++ b/dsl/extdeps/cpu/types.dag @@ -1,10 +1,3 @@ -// extdeps/cpu/types.dag — shared CPU taxonomy types (no vendor catalog data). -// -// A CPU is a hardware domain model, not a universal framework, so it lives downstream -// of std (extdeps), alongside the per-vendor catalog rows that inhabit this shape -// (extdeps/cpu/.dag). std owns only the universal frameworks it builds on -// (measure, types). - module extdeps.cpu.types import std.measure { HardwareThreadCount, Hertz, Watt } @@ -24,12 +17,6 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// CpuSocket — the physical CPU mount, decomposed from the marketing string (e.g. -// "LGA4926" = a Land Grid Array package with 4926 contacts/lands). `package` is the -// contact technology (a closed set); `contact_count` is the number of electrical -// contacts (lands for LGA, pins for PGA, balls for BGA) — so the string's trailing -// number is a grounded Int, not an opaque token. -// Anchor: https://en.wikipedia.org/wiki/CPU_socket (land grid array vs pin grid array) type SocketPackage = LandGridArray | PinGridArray | BallGridArray type CpuSocket { @@ -37,9 +24,6 @@ type CpuSocket { contact_count: Int } -// A vendor part identifies itself by its catalog row — extdeps/cpu owns the SHAPE, the -// per-vendor rows live in extdeps/cpu/. No std-level enum of one vendor's -// SKUs (that would make the concept a purchase order). type CpuModelCatalogRow { model_number: NonEmptyStr oem_listing_id: NonEmptyStr? @@ -50,16 +34,13 @@ type CpuModelCatalogRow { nominal_sustained_per_thread_hz: Hertz socket: CpuSocket tdp_watts: Watt - // TODO(P-CF-ISA): populate instruction_sets when InstructionSet dissolves - // from Node in product.compute_fabric (Neoverse-N1 extension set for Altra Max). + } type CpuDeploymentFacts { sustained_per_thread_hz: Hertz } -// CpuFacts is vendor-agnostic: it carries the catalog row (identity-by-part) plus -// the deployment facts. Which catalog row — that's an extdeps/deployment fact. type CpuFacts { catalog: CpuModelCatalogRow deployment: CpuDeploymentFacts diff --git a/dsl/extdeps/cron/cron.dag b/dsl/extdeps/cron/cron.dag index 18b76d260db..18bd6175f53 100644 --- a/dsl/extdeps/cron/cron.dag +++ b/dsl/extdeps/cron/cron.dag @@ -1,20 +1,5 @@ -// extdeps/cron/cron.dag — POSIX crontab shell transport (`cron.Tab` operations). -// -// Interface shape only (DESIGN.md §3): faithful `crontab` utility primitives. -// Schedule field grammar lives in `cron/schedule_model.dag` (`module extdeps.cron.schedule_model`). -// Tag-based upsert/remove idempotency is workflow policy — compose `List` + `Replace` in -// `gunbc/tools/cron_tag.dag`, not here. -// -// External authority: POSIX.1-2017 user crontab interface (crontab utility / on-disk entries) -// — schedule-shaped data cites the same POSIX volume as the carrier module header. - module extdeps.cron -// 🟡 dissolved — feature:cron-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); extdeps.cron.mock_corpus (whole-tree loaded by M4.1) governs WHICH -// cron.Tab ops are hermetically realizable, and the fixture store owns the payloads (§3). -// forbidden: reintroducing mock_response constants for Hermetic dispatch on these shapes. service cron.Tab { operation List { input {} @@ -27,7 +12,6 @@ service cron.Tab { } } - // Install crontab from stdin — POSIX `crontab -` (replaces the user's entire table). operation Replace { input { entries: String } output { success: Bool from "exit_success", stdout: String from "stdout", stderr: String from "stderr" } diff --git a/dsl/extdeps/cron/mock_corpus.dag b/dsl/extdeps/cron/mock_corpus.dag index d8091273e27..2294bfada93 100644 --- a/dsl/extdeps/cron/mock_corpus.dag +++ b/dsl/extdeps/cron/mock_corpus.dag @@ -1,18 +1,3 @@ -// dsl/extdeps/cron/mock_corpus.dag -// Scope: the cron layer's PUBLISHED mock corpus as a closed, declared structural fact. -// Anchor: DESIGN.md §3 (single authority) / §6 (model-just-in-time, mark the carrier). -// -// SINGLE authority for WHICH cron.Tab operations are hermetically realizable. Read by BOTH the -// compile-time M2 mock_totality_lens (src/v2/lens/mock_totality.dag, via the per-layer witness) -// AND the v1 runtime's eval_service_call (the M4 hermetic-realization fold) — one model, not two. -// The v1 runtime loads the dsl/ tree, so this corpus lives in dsl/ for the runtime to reach the -// SAME model the lens reads. Modeled on the M4.0 filesystem pilot -// (dsl/extdeps/filesystem/mock_corpus.dag, #5188). -// -// Rows inhabit std.hermetic_replay.PublishedMockCase. The operation set authority remains -// dsl/extdeps/cron/cron.dag (`service cron.Tab`); per-case payloads live in the Phase-2 -// RecordedFixture store ONLY — rows carry the (operation_key, case_id) structural key. - module extdeps.cron.mock_corpus import std.hermetic_replay { PublishedMockCase } @@ -31,15 +16,6 @@ data cron_tab_mock_case_replace: PublishedMockCase = PublishedMockCase { case_id: 0 } -// 🟡 gated — feature:cron-mock-corpus-from-service-decl — bind node://adhoc-aeaa1c56-be5 -// dissolve-on-arrival: project this corpus directly from the `service cron.Tab` operation set in -// dsl/extdeps/cron/cron.dag (the SINGLE authority for WHICH operations exist), joined with the -// Phase-2 RecordedFixture store (the authority for WHICH recorded cases exist per operation), once -// a v2 lens can read a service decl's operation nodes and the fixture store's keys; this declared -// list then deletes in the same PR. forbidden: a row carrying a response VALUE (entries/success/ -// stdout/stderr) — that would fork the payload authority, now owned by the fixture store (§3); -// rows mirror the (operation_key, case_id) structural key ONLY, and grow when a published -// operation/case is added upstream. data cron_published_mock_corpus: List = [ cron_tab_mock_case_list, cron_tab_mock_case_replace diff --git a/dsl/extdeps/cron/schedule_model.dag b/dsl/extdeps/cron/schedule_model.dag index b2172b73347..58bf8113a05 100644 --- a/dsl/extdeps/cron/schedule_model.dag +++ b/dsl/extdeps/cron/schedule_model.dag @@ -1,69 +1,8 @@ -// extdeps/cron/schedule_model.dag — POSIX crontab schedule protocol (carriers + wire render). -// -// Fidelity — extdeps invariant (cite source + declare version; DESIGN.md §3): -// Spec: https://pubs.opengroup.org/onlinepubs/9699919799/utilities/crontab.html -// Version: POSIX.1-2017 (IEEE Std 1003.1-2017; Open Group Issue 7, 2018 edition online snapshot) -// -// Sections referenced: -// — XCU `crontab` utility: user crontab file layout; five time-and-date fields (minute, hour, -// day-of-month, month, day-of-week) followed by command; POSIX.1-2017 documents `*`, lists, -// and ranges for those fields. -// -// Step / slash syntax (`*/n`, `start/step`) is not POSIX-defined for user crontabs; it is a -// widely deployed implementation extension (historically associated with Vixie cron). The -// `Step` carrier and `render_cron_field` slash rendering model that wire shape — cite deployment -// docs for consumers that require strict POSIX-only schedules. -// -// Split from `cron/cron.dag` so v3 bootstrap loads schedule carriers without parsing `service` blocks -// (`cron.Tab` shell transport remains in `cron/cron.dag`). -// -// Consumers: -// dsl/extdeps/github/actions.dag — `WorkflowTrigger::Schedule` -// dsl/gunbc/tools/review*.dag — `CronSchedule` data + `render_cron_schedule` - module extdeps.cron.schedule_model import std.integer { NonNegativeInt, PositiveInt } import std.list { List } -// Coproduct dissolution: `CronField`. -// -// Classification ledger (N≥2 variants — checkpoint names 🟢 / 🟡 / 🔴): -// -// **🟢 GREEN (terminal at shape partition)** — `CronField` is the carrier for schedule-field -// *token-shape* alternatives at the external grammar boundary (wildcard vs exact vs list vs range -// vs step/slash). Ledger — four dissolution patterns were considered: -// 1. Fact placement: every variant is consumed by the same wire renderer (`render_cron_field`); -// splitting would scatter portable vs extension token shapes across consumers without -// removing the alternative structure users author in crontab entries. -// 2. Variant-is-data: shapes are not label-only — `Wildcard` vs `Listed` vs `Step` carry -// incompatible payloads matching distinct crontab token shapes, not a closed enum label. -// 3. Algebraic form: fields are syntax carriers for the external crontab schedule language, -// not eliminators into a single `std/` algebra operator family. -// 4. Dimensional: only `Ranged` / `Step` are naturally two-coordinate; `Wildcard`, `Exact`, -// and `Listed` do not share one coordinate space, so a single dimensional record would -// mis-model the field grammar. -// -// **🟡 YELLOW (scaffold — bounded refinements deferred)** — payloads still admit **ill-formed** -// crontab facts this module does not rule out at the type layer (boundary discipline, DESIGN.md §3 / extdeps fidelity gap): -// - `Listed` may be an **empty** list (no corresponding empty-list field token in portable grammar). -// - `Ranged` may have **start > end** (inverted range — not a valid portable range token). -// - `Exact`, list elements, range endpoints, and step coordinates may sit **outside each field's -// domain** (minute/hour/DOM/month/DOW bounds); carriers use `NonNegativeInt` / unrestricted lists -// only, so out-of-range integers serialize without failing closed here. -// -// **Dissolution trigger:** introduce per-field refined carriers (or one validated `CronField` -// view + total `well_formed_cron_field` / parse validators) that reject the three bullets above at -// construction or wire ingress — or prove those invariants at every authoring site before schedules -// reach Actions/workflow carriers. -// -// **🔴 RED (dissolvable-now)** — none for this checkpoint: the missing work above is refinement / -// validation discipline (YELLOW), not an immediate cheaper coproduct split inside this file. -// -// Authority: POSIX.1-2017 XCU `crontab` for wildcard/list/range token shapes; `Step` slash forms -// track common implementation extensions (not POSIX normative text). -// -// CronSchedule / CronEntry: records over `CronField` + command metadata — not N≥2 coproducts. type CronField = Wildcard | Exact { value: NonNegativeInt } diff --git a/dsl/extdeps/diagnostic/edac.dag b/dsl/extdeps/diagnostic/edac.dag index 71ce2a3afa7..50568eec8ad 100644 --- a/dsl/extdeps/diagnostic/edac.dag +++ b/dsl/extdeps/diagnostic/edac.dag @@ -1,6 +1,3 @@ -// extdeps/diagnostic/edac.dag — EDAC correctable counter read (ras-mc-ctl). -// Anchor: https://www.kernel.org/doc/html/latest/admin-guide/ras.html - module extdeps.diagnostic.edac import extdeps.external_authority { ExternalAuthority } @@ -13,12 +10,6 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// 🟡 dissolved — feature:diagnostic-edac-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); the published corpus (extdeps.diagnostic.mock_corpus) now governs -// WHICH diagnostic.edac.RasMcCtl ops are hermetically realizable, and the fixture store owns the -// payloads (§3). forbidden: reintroducing mock_response constants for Hermetic dispatch on these -// shapes. service diagnostic.edac.RasMcCtl { operation CorrectableCounts { input {} diff --git a/dsl/extdeps/diagnostic/ipmi.dag b/dsl/extdeps/diagnostic/ipmi.dag index f55563edde9..9c07a107baf 100644 --- a/dsl/extdeps/diagnostic/ipmi.dag +++ b/dsl/extdeps/diagnostic/ipmi.dag @@ -1,8 +1,3 @@ -// extdeps/diagnostic/ipmi.dag — IPMI/ipmitool out-of-band BMC (sensor / SDR / SEL). -// Anchor: https://www.intel.com/content/www/us/en/products/docs/servers/ipmi/ipmi-second-gen-interface-spec-v2-rev1-1.html -// -// argv grounded in ipmitool(8) sensor/sdr/sel subcommands. - module extdeps.diagnostic.ipmi import std.types { NonEmptyStr } @@ -17,12 +12,6 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// 🟡 dissolved — feature:diagnostic-ipmi-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); the published corpus (extdeps.diagnostic.mock_corpus) now governs -// WHICH diagnostic.ipmi.Tool ops are hermetically realizable, and the fixture store owns the -// payloads (§3). forbidden: reintroducing mock_response constants for Hermetic dispatch on these -// shapes. service diagnostic.ipmi.Tool { operation SensorList { input { bmc_host: NonEmptyStr } diff --git a/dsl/extdeps/diagnostic/mock_corpus.dag b/dsl/extdeps/diagnostic/mock_corpus.dag index e86ac8c1c3d..a444a53830d 100644 --- a/dsl/extdeps/diagnostic/mock_corpus.dag +++ b/dsl/extdeps/diagnostic/mock_corpus.dag @@ -1,25 +1,3 @@ -// dsl/extdeps/diagnostic/mock_corpus.dag -// Scope: the diagnostic layer's PUBLISHED mock corpus as a closed, declared structural fact. -// Anchor: DESIGN.md §3 (single authority) / §6 (model-just-in-time, mark the carrier). -// -// SINGLE authority for WHICH diagnostic.* / redfish.Http operations are hermetically realizable. -// Read by BOTH the compile-time M2 mock_totality_lens (src/v2/lens/mock_totality.dag, via the -// per-layer witness) AND the v1 runtime's eval_service_call (the M4 hermetic-realization fold) — -// one model, not two. The v1 runtime loads the dsl/ tree, so this corpus lives in dsl/ for the -// runtime to reach the SAME model the lens reads. Modeled on the M4.0 filesystem pilot -// (dsl/extdeps/filesystem/mock_corpus.dag, #5188). -// -// Per-SERVICE governance: eval_service_call splits an operation_key on its last `.`, so each of -// diagnostic.ssh.Session / redfish.Http / diagnostic.edac.RasMcCtl / diagnostic.ipmi.Tool is -// governed independently. Every op that today carries an inline mock_response IS published below, -// so no governed service's sibling is silently fail-closed. -// -// Rows inhabit std.hermetic_replay.PublishedMockCase. The operation set authority remains the -// service decls under dsl/extdeps/diagnostic/{ssh,edac,ipmi}.dag and -// dsl/extdeps/bmc/http.dag (redfish.Http); per-case payloads live in the Phase-2 -// RecordedFixture store ONLY — rows carry the structural key (service, operation, -// operation_key, case_id). - module extdeps.diagnostic.mock_corpus import std.hermetic_replay { PublishedMockCase } @@ -101,15 +79,6 @@ data diagnostic_ipmi_tool_mock_case_sel_list: PublishedMockCase = PublishedMockC case_id: 0 } -// 🟡 gated — feature:diagnostic-mock-corpus-from-service-decl — bind node://adhoc-49ce4678-496 -// dissolve-on-arrival: project this corpus directly from the diagnostic service operation sets -// in dsl/extdeps/diagnostic/{ssh,edac,ipmi}.dag and dsl/extdeps/bmc/http.dag (the SINGLE -// authority for WHICH operations exist), joined with the Phase-2 RecordedFixture store (the authority for WHICH -// recorded cases exist per operation), once a v2 lens can read a service decl's operation nodes -// and the fixture store's keys; this declared list then deletes in the same PR. forbidden: a row -// carrying a response VALUE (exit_code/stdout/success/body/reachable) — that would fork the -// payload authority, now owned by the fixture store (§3); rows mirror the structural key ONLY, -// and grow when a published operation/case is added upstream. data diagnostic_published_mock_corpus: List = [ diagnostic_ssh_session_mock_case_exec, diagnostic_ssh_session_mock_case_reachability, diff --git a/dsl/extdeps/diagnostic/ssh.dag b/dsl/extdeps/diagnostic/ssh.dag index 7f7d8d1b422..7d49319bd54 100644 --- a/dsl/extdeps/diagnostic/ssh.dag +++ b/dsl/extdeps/diagnostic/ssh.dag @@ -1,8 +1,3 @@ -// extdeps/diagnostic/ssh.dag — OpenSSH session transport (in-band observe + probe run). -// Anchor: https://datatracker.ietf.org/doc/html/rfc4253 -// -// PS-0 observe/control boundary for host health workflows. - module extdeps.diagnostic.ssh import std.types { NonEmptyStr } @@ -17,12 +12,6 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// 🟡 dissolved — feature:diagnostic-ssh-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); the published corpus (extdeps.diagnostic.mock_corpus) now governs -// WHICH diagnostic.ssh.Session ops are hermetically realizable, and the fixture store owns the -// payloads (§3). forbidden: reintroducing mock_response constants for Hermetic dispatch on these -// shapes. service diagnostic.ssh.Session { operation Exec { input { host: NonEmptyStr, command: NonEmptyStr } diff --git a/dsl/extdeps/docker/docker.dag b/dsl/extdeps/docker/docker.dag index 8daaea14da8..8993cf6972e 100644 --- a/dsl/extdeps/docker/docker.dag +++ b/dsl/extdeps/docker/docker.dag @@ -1,50 +1,13 @@ -// extdeps/docker/docker.dag -- "What is Docker?" (the container-runtime surface -// we consume: images, mounts). -// -// Spec: https://docs.docker.com/engine/storage/ (mounts) and -// https://docs.docker.com/reference/cli/docker/image/ (images) -// Version: Docker Engine 24.x+ -// -// Facts about Docker's data model, not how we invoke it. CLI encodings -// ("-v host:ctr:ro", "--mount type=bind,...", "256m" size strings) are -// boundary syntax: parsed into these facts at ingress, re-encoded at -// egress, never stored (units discipline -- quantities are bare standard -// units; product/compute_fabric.dag models the hardware the runtime sits on). -// -// Consumers: -// gunb-ai/ctrl plans/models/session_contract -- session bind mounts - module extdeps.docker import std.types { FilePath, NonEmptyStr, ContentHash } -// -- Images ---------------------------------------------------------- - type DockerImage { - repository: NonEmptyStr // e.g. "ctrl-session" - tag: NonEmptyStr // e.g. "latest" - digest: ContentHash? // Some("sha256:...") when pinned; None when by-tag only + repository: NonEmptyStr + tag: NonEmptyStr + digest: ContentHash? } -// -- Mounts ---------------------------------------------------------- -// Docker's three mount kinds. A bind mount maps a host path into the -// container; a volume mount attaches a daemon-managed named volume; a -// tmpfs mount is container-private memory-backed scratch. -// -// Coproduct dissolution classification (DESIGN.md §2 decompress->map->reduce): -// 🟢 GREEN (terminal). Docker's `--mount type=` surface is a closed, -// daemon-defined taxonomy of exactly these three kinds; the variants are -// the irreducible distinction at the docker-CLI boundary, with genuinely -// distinct payloads (a host path / a named volume / a memory size). -// Ledger (Patterns 1–5): (1) fact-placement rejected — all three flow to -// the same consumer (the container runtime), no per-consumer split. -// (2) variant-is-data rejected — not one shape with a label; payloads -// differ structurally (host_path vs volume name vs size_bytes). -// (3) no std algebraic source — these are runtime config, not ops over a -// std type. (4) not dimensional — the kinds do not factor into orthogonal -// axes; readonly is already an explicit field, not a hidden dimension. -// (5) not a parameterized family — no separately-declared set is being -// enumerated. The closed docker mount-kind set is the source. type DockerMount = BindMount { host_path: FilePath, container_path: FilePath, readonly: Bool } | VolumeMount { volume: NonEmptyStr, container_path: FilePath, readonly: Bool } diff --git a/dsl/extdeps/external_authority.dag b/dsl/extdeps/external_authority.dag index 6b9788570d2..26f779a0b36 100644 --- a/dsl/extdeps/external_authority.dag +++ b/dsl/extdeps/external_authority.dag @@ -1,16 +1,3 @@ -// extdeps/external_authority.dag — external authority citation carrier (DESIGN §3). -// -// Every extdeps/ module cites an EXTERNAL authority — a real URL to a wiki, ISO, -// ECMA, vendor SPEC page, or other intersubjective framework for the *concept* -// modeled in the module (not the umbrella company homepage). The locator names the -// spec surface the module's facts ground on. -// -// Canonical module-level data row name (projection + lens match literally): -// data extdeps_external_authority_anchor: ExternalAuthority = ... -// -// Internal file: anchors are reserved for anchor-machinery modules only -// (extdeps.uri, extdeps.external_authority) — see lens machinery-exempt roster. - module extdeps.external_authority import std.types { NonEmptyStr } @@ -20,14 +7,11 @@ type ExternalAuthority { uri: Uri } -// Field-level override: a specific fact cites a finer locator than the module -// root (e.g. a page fragment on a PDF). Absent ⇒ inherit module root. type FactAuthorityOverride { fact: NonEmptyStr authority: ExternalAuthority } -// Self-anchor: DESIGN §3 single-authority (internal doc cited as file: fragment). data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { uri: Uri { scheme: File diff --git a/dsl/extdeps/filesystem/filesystem_io.dag b/dsl/extdeps/filesystem/filesystem_io.dag index f3a9f6aa7d2..8c1d57a2341 100644 --- a/dsl/extdeps/filesystem/filesystem_io.dag +++ b/dsl/extdeps/filesystem/filesystem_io.dag @@ -1,35 +1,7 @@ -// extdeps/filesystem/filesystem_io.dag -- Live filesystem read/write effects. -// -// Spec: POSIX.1-2017 write(2) / read(2) -// https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html -// https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html -// -// The host-effect peer of git.Core (shell) and the REST transports: a service -// whose operations the v2 interpreter EXECUTES live via the `file` transport -// (extdeps/transports/file.dag). `Filesystem.Write(path:, content:)` commits -// bytes to a POSIX pathname and returns its receipt; `Filesystem.Read(path:)` -// pulls them back. The interpreter selects the direction from the operation's -// static signature: an operation with a `content` input WRITES, one without -// READS (see dispatch_file in v1_interpreter.rs). -// -// The write receipt -- the WriteResult of the ROADMAP "Runnable v2 program with -// I/O" item -- is the `Write` operation's output product: -// { success: Bool, bytes_written: Int, path: String, error: String } -// realized field-by-field from the host write, exactly as a shell operation's -// output record is realized from captured stdout/exit. Like shell, a failed -// effect does NOT throw: the op returns its record with `success = false` and -// the OS error in `error`, so the caller branches on `result.success`. -// -// 🟡 dissolved — feature:filesystem-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch -// --fixture-store (recorded wet via --record); forbidden: reintroducing mock_response -// constants for Hermetic dispatch on this shape. - module extdeps.filesystem.filesystem_io service Filesystem { - // Commit `content` to the file at `path`, creating or truncating it. - // Returns the WriteResult receipt (success / bytes_written / path / error). + operation Write { input { path: String, content: String } output { @@ -41,8 +13,6 @@ service Filesystem { transport file { path: "{path}" } } - // Read the file at `path` back into a String. `success` is false (and - // `error` carries the OS text) when the path is missing or unreadable. operation Read { input { path: String } output { diff --git a/dsl/extdeps/filesystem/mock_corpus.dag b/dsl/extdeps/filesystem/mock_corpus.dag index b3f43e9accf..639c9ad3677 100644 --- a/dsl/extdeps/filesystem/mock_corpus.dag +++ b/dsl/extdeps/filesystem/mock_corpus.dag @@ -1,19 +1,3 @@ -// dsl/extdeps/filesystem/mock_corpus.dag -// Scope: the filesystem layer's PUBLISHED mock corpus as a closed, declared structural fact. -// Anchor: DESIGN.md §3 (single authority) / §6 (model-just-in-time, mark the carrier). -// -// SINGLE authority for WHICH filesystem operations are hermetically realizable. Read by BOTH the -// compile-time M2 mock_totality_lens (src/v2/lens/mock_totality.dag) AND the v1 runtime's -// eval_service_call (the M4 hermetic-realization fold) — one model, not two. The v1 runtime loads -// the dsl/ tree, so this corpus must live in dsl/ for the runtime to reach the SAME model the lens -// reads; the v2 mirror (src/v2/extdeps/filesystem/mock_corpus.dag) is dissolved by this PR. The v2 -// lens imports this dsl module directly — cross-tree v2->dsl import is the EXISTING pattern (cf. v2 -// importing std.realization / std.types), not a new mechanism. -// -// Rows inhabit std.hermetic_replay.PublishedMockCase. The operation set authority remains -// dsl/extdeps/filesystem/filesystem_io.dag (`service Filesystem`); per-case payloads live in the -// Phase-2 RecordedFixture store ONLY — rows carry the (operation_key, case_id) structural key. - module extdeps.filesystem.mock_corpus import std.hermetic_replay { PublishedMockCase } @@ -32,15 +16,6 @@ data filesystem_mock_case_read_contents: PublishedMockCase = PublishedMockCase { case_id: 0 } -// 🟡 gated — feature:filesystem-mock-corpus-from-service-decl — bind node://adhoc-a9399cb3-628 -// dissolve-on-arrival: project this corpus directly from the `service Filesystem` operation set -// in dsl/extdeps/filesystem/filesystem_io.dag (the SINGLE authority for WHICH operations exist), -// joined with the Phase-2 RecordedFixture store (the authority for WHICH recorded cases exist -// per operation), once a v2 lens can read a service decl's operation nodes and the fixture -// store's keys; this declared list then deletes in the same PR. forbidden: a row carrying a -// response VALUE (success/bytes_written/content/error) — that would fork the payload authority, -// now owned by the fixture store (§3); rows mirror the (operation_key, case_id) structural key -// ONLY, and grow when a published operation/case is added upstream. data filesystem_published_mock_corpus: List = [ filesystem_mock_case_write_committed, filesystem_mock_case_read_contents diff --git a/dsl/extdeps/filesystem/ntfs.dag b/dsl/extdeps/filesystem/ntfs.dag index e21946b15a7..0cd43d304dd 100644 --- a/dsl/extdeps/filesystem/ntfs.dag +++ b/dsl/extdeps/filesystem/ntfs.dag @@ -1,31 +1,13 @@ -// extdeps/filesystem/ntfs.dag — NTFS file-type taxonomy, cited. -// -// Upstream: [MS-FSCC] File System Control Codes, Microsoft Open Specifications -// — file attributes (FILE_ATTRIBUTE_*) and reparse-point tags (IO_REPARSE_TAG_*). -// https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-fscc/ -// -// The cited NATIVE taxonomy for the Ntfs arm of std.os.types.FileSystemSemantics, -// reduced into the OS-agnostic std.filesystem.EntryKind. This realization is why -// EntryKind is NOT "POSIX renamed": NTFS has no S_IFIFO/S_IFSOCK/S_IFCHR/S_IFBLK -// FILE entries (those live in the NT object namespace, not the volume), and it -// adds the mount-point junction — a reparse construct with no POSIX equivalent. - module extdeps.filesystem.ntfs import std.filesystem.types { EntryKind } -// NTFS native entry types as observed via file attributes + reparse tags. -// Real spec names (the FILE_ATTRIBUTE_* / IO_REPARSE_TAG_* constants). type NtfsEntryType - = NormalFile // no FILE_ATTRIBUTE_DIRECTORY, no reparse point - | NtfsDirectory // FILE_ATTRIBUTE_DIRECTORY - | SymlinkReparse // FILE_ATTRIBUTE_REPARSE_POINT + IO_REPARSE_TAG_SYMLINK - | MountPointReparse // FILE_ATTRIBUTE_REPARSE_POINT + IO_REPARSE_TAG_MOUNT_POINT (junction) + = NormalFile + | NtfsDirectory + | SymlinkReparse + | MountPointReparse -// Reduce the NTFS native type into the agnostic EntryKind. -// - A symlink reparse is the genuine path-indirection → Symlink. -// - A mount-point junction is a distinct NTFS reparse construct (not a POSIX -// symlink: different resolution semantics) → Other, NOT nicknamed Symlink. fn ntfs_entry_kind(t: NtfsEntryType) -> EntryKind { match t { NormalFile => RegularFile diff --git a/dsl/extdeps/filesystem/posix.dag b/dsl/extdeps/filesystem/posix.dag index 33fcd44ae9d..52d09ca73b4 100644 --- a/dsl/extdeps/filesystem/posix.dag +++ b/dsl/extdeps/filesystem/posix.dag @@ -1,31 +1,16 @@ -// extdeps/filesystem/posix.dag — POSIX file-type taxonomy, cited. -// -// Upstream: IEEE Std 1003.1-2017 (POSIX.1-2017), , the S_IFMT -// field-of-st_mode file-type encoding. -// https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/sys_stat.h.html -// -// The cited NATIVE taxonomy for the Posix arm of std.os.types.FileSystemSemantics, -// plus its reduction into the OS-agnostic std.filesystem.EntryKind. Real names -// kept (the S_IF* macros, masked from st_mode by S_IFMT). This is the P2 split: -// the data + mapping live in extdeps; only the agnostic shape lives in std. - module extdeps.filesystem.posix import std.filesystem.types { EntryKind } -// The seven S_IFMT file types (sys/stat.h). Real spec names. type PosixFileType - = S_IFREG // regular file - | S_IFDIR // directory - | S_IFLNK // symbolic link - | S_IFIFO // FIFO / named pipe - | S_IFSOCK // socket - | S_IFCHR // character device - | S_IFBLK // block device + = S_IFREG + | S_IFDIR + | S_IFLNK + | S_IFIFO + | S_IFSOCK + | S_IFCHR + | S_IFBLK -// Reduce the POSIX native type into the agnostic EntryKind. POSIX is the -// richest arm: it is the only realization with first-class fifo/socket/device -// FILE entries, all of which fold to `Other` (exists, but not regular/dir/link). fn posix_entry_kind(t: PosixFileType) -> EntryKind { match t { S_IFREG => RegularFile diff --git a/dsl/extdeps/formats/elf/encode.dag b/dsl/extdeps/formats/elf/encode.dag index 29057fe8451..0dc25130f5f 100644 --- a/dsl/extdeps/formats/elf/encode.dag +++ b/dsl/extdeps/formats/elf/encode.dag @@ -1,8 +1,3 @@ -// extdeps/formats/elf/encode.dag — ELF-64 encode (inverse of decode, Slice 0.5). -// -// Anchor: https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html -// Anchor: https://refspecs.linuxfoundation.org/elf/gabi4+/ch5.pheader.html - module extdeps.formats.elf.encode import extdeps.formats.elf.primitives { diff --git a/dsl/extdeps/formats/elf/hello_static_witness.dag b/dsl/extdeps/formats/elf/hello_static_witness.dag index b822c483ac4..f11ade74851 100644 --- a/dsl/extdeps/formats/elf/hello_static_witness.dag +++ b/dsl/extdeps/formats/elf/hello_static_witness.dag @@ -1,12 +1,3 @@ -// extdeps/formats/elf/hello_static_witness.dag — end-to-end decode + encode round-trip of one real static hello ELF. -// -// Fixture: musl-static x86-64 hello built in Alpine 3.20 (linux/amd64): -// cc -static -o hello 'write(1,"Hello\n",6); return 0;' -// Bytes are the on-disk ELF-64 Ehdr (64 B) + first PT_LOAD Phdr (56 B) — verified with readelf. -// -// Anchor: https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html -// Anchor: https://refspecs.linuxfoundation.org/elf/gabi4+/ch5.pheader.html - module extdeps.formats.elf.hello_static_witness import extdeps.formats.elf.primitives { @@ -52,7 +43,6 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// Real static hello — ELF-64 Ehdr (64 bytes). data static_hello_elf64_ehdr_bytes: List = [ 127, 69, 76, 70, 2, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 62, 0, 1, 0, 0, 0, 43, 16, 64, 0, 0, 0, 0, 0, @@ -60,7 +50,6 @@ data static_hello_elf64_ehdr_bytes: List = [ 0, 0, 0, 0, 64, 0, 56, 0, 9, 0, 64, 0, 26, 0, 25, 0, ] -// Continuation at file offset 64 — first PT_LOAD program header (56 bytes). data static_hello_first_phdr_bytes: List = [ 1, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 0, 0, 0, @@ -91,9 +80,6 @@ data static_hello_elf32_class_ehdr_bytes: List = [ 0, 0, 0, 0, 64, 0, 56, 0, 9, 0, 64, 0, 26, 0, 25, 0, ] -// Witnesses: green-by-execution via `gunbc run --source-root dsl --entry ... --claim-run`. -// 🟡 consumer:dsl-rooted-claim-run-gate — not CI-enrolled until dsl corpus gate lands. - fn witness_format_atom_is_elf() -> Bool { linux_x86_64_elf_format.family == Elf } diff --git a/dsl/extdeps/formats/elf/primitives.dag b/dsl/extdeps/formats/elf/primitives.dag index 036adbd1b3c..adab8cd69ad 100644 --- a/dsl/extdeps/formats/elf/primitives.dag +++ b/dsl/extdeps/formats/elf/primitives.dag @@ -1,9 +1,3 @@ -// extdeps/formats/elf/primitives.dag — ELF specification atoms (Slice 1: ELF-64 + Linux x86-64 subset). -// -// Anchor: https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html -// Anchor: https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.reloc.html -// Anchor: https://refspecs.linuxfoundation.org/elf/x86_64-abi-0.99.pdf (EM_X86_64) - module extdeps.formats.elf.primitives import std.exec_format { ExecutableFormat, Elf } @@ -18,7 +12,6 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// 🟢 terminal — gABI ELFMAG0..ELFMAG3 are irreducible identification bytes. type ElfMagicByte = Mag0 | Mag1 | Mag2 | Mag3 data elf_mag0: Int = 127 @@ -26,21 +19,18 @@ data elf_mag1: Int = 69 data elf_mag2: Int = 76 data elf_mag3: Int = 70 -// gABI §ELF Header e_ident[EI_CLASS] type ElfClass = ElfClassNone | ElfClass32 | ElfClass64 data elf_class_none: Int = 0 data elf_class_32: Int = 1 data elf_class_64: Int = 2 -// gABI §ELF Header e_ident[EI_DATA] type ElfDataEncoding = ElfDataNone | ElfData2Lsb | ElfData2Msb data elf_data_none: Int = 0 data elf_data_2lsb: Int = 1 data elf_data_2msb: Int = 2 -// gABI §ELF Header e_type — Slice 1: ET_EXEC only (static hello witness). type ElfFileType = EtNone | EtRel | EtExec | EtDyn | EtCore data et_none: Int = 0 @@ -49,27 +39,22 @@ data et_exec: Int = 2 data et_dyn: Int = 3 data et_core: Int = 4 -// gABI §ELF Header e_machine — Slice 1: EM_X86_64 only. type ElfMachine = EmNone | EmX86_64 data em_none: Int = 0 data em_x86_64: Int = 62 -// gABI §Program Header p_type — Slice 1: PT_LOAD only. type ElfSegmentType = PtNull | PtLoad data pt_null: Int = 0 data pt_load: Int = 1 -// gABI §Program Header p_flags data pf_x: Int = 1 data pf_w: Int = 2 data pf_r: Int = 4 -// gABI §ELF Header field sizes (ELF-64). data elf64_ehdr_size: Int = 64 data elf64_phdr_size: Int = 56 data elf64_shdr_size: Int = 64 -// Cited ELF format row inhabiting std.exec_format.ExecutableFormat. data linux_x86_64_elf_format: ExecutableFormat = ExecutableFormat { family: Elf } diff --git a/dsl/extdeps/formats/elf/relocation.dag b/dsl/extdeps/formats/elf/relocation.dag index 28729522efa..2c8ce852f36 100644 --- a/dsl/extdeps/formats/elf/relocation.dag +++ b/dsl/extdeps/formats/elf/relocation.dag @@ -1,9 +1,3 @@ -// extdeps/formats/elf/relocation.dag — ELF relocation carriers (Slice 1: type only). -// -// Anchor: https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.reloc.html -// -// Relocation decode lands in a follow-on slice; R_X86_64_* constants are cited facts. - module extdeps.formats.elf.relocation import extdeps.external_authority { ExternalAuthority } @@ -16,9 +10,6 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// x86-64 relocation types cited from gABI / x86-64 psABI (subset). -// 🟡 dissolve-on: Relocation decode deferred to Slice 2 (shift/mask primitives for sym+type split -// from Elf64Rela.info; do NOT add elf64_rela_to_relocation here until that lands). data r_x86_64_none: Int = 0 data r_x86_64_64: Int = 1 data r_x86_64_pc32: Int = 2 @@ -31,4 +22,3 @@ type Elf64Rela { info: Int addend: Int } - diff --git a/dsl/extdeps/formats/elf/sections.dag b/dsl/extdeps/formats/elf/sections.dag index 27101b7a81d..9523a521e8f 100644 --- a/dsl/extdeps/formats/elf/sections.dag +++ b/dsl/extdeps/formats/elf/sections.dag @@ -1,9 +1,3 @@ -// extdeps/formats/elf/sections.dag — ELF-64 section header carrier (Slice 1: type only). -// -// Anchor: https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.sheader.html -// -// Section decode lands in a follow-on slice; header fields are cited for module completeness. - module extdeps.formats.elf.sections import extdeps.external_authority { ExternalAuthority } @@ -29,7 +23,6 @@ type Elf64Shdr { entsize: Int } -// gABI SHT_* subset named for later slices — values cited from gABI ch4. data sht_null: Int = 0 data sht_progbits: Int = 1 data sht_symtab: Int = 2 diff --git a/dsl/extdeps/formats/elf/segments.dag b/dsl/extdeps/formats/elf/segments.dag index 1d0eb5207c6..96fb3e4cf02 100644 --- a/dsl/extdeps/formats/elf/segments.dag +++ b/dsl/extdeps/formats/elf/segments.dag @@ -1,7 +1,3 @@ -// extdeps/formats/elf/segments.dag — ELF-64 program header decode (Slice 1: PT_LOAD subset). -// -// Anchor: https://refspecs.linuxfoundation.org/elf/gabi4+/ch5.pheader.html - module extdeps.formats.elf.segments import extdeps.formats.elf.primitives { diff --git a/dsl/extdeps/formats/elf/types.dag b/dsl/extdeps/formats/elf/types.dag index 6b532b70d4a..6e4eddcd7c9 100644 --- a/dsl/extdeps/formats/elf/types.dag +++ b/dsl/extdeps/formats/elf/types.dag @@ -1,7 +1,3 @@ -// extdeps/formats/elf/types.dag — ELF-64 carriers and header decode (Slice 1). -// -// Anchor: https://refspecs.linuxfoundation.org/elf/gabi4+/ch4.eheader.html - module extdeps.formats.elf.types import extdeps.formats.elf.primitives { @@ -84,7 +80,6 @@ type ElfDecodeOutcome = ElfDecoded { value: T } | ElfRejected { reason: ElfDecodeReason } -// Caller must guarantee offset in bounds — used only after a length guard. fn byte_at_in_bounds(bytes: List, offset: Int) -> Int { match bytes |> get(offset) { null => 0 diff --git a/dsl/extdeps/formats/yaml.dag b/dsl/extdeps/formats/yaml.dag index 5d6780a4f07..c472931a5e7 100644 --- a/dsl/extdeps/formats/yaml.dag +++ b/dsl/extdeps/formats/yaml.dag @@ -1,18 +1,3 @@ -// extdeps/formats/yaml.dag — YAML 1.2 structural value model + byte-faithful serializer. -// -// SCAFFOLD — §3 fork of `src/v2/extdeps/formats/yaml.dag` `YamlValue`: this module is the -// v1-interpreter / projection substrate (ordered `List`, `serialize_yaml`, -// witnessable under `gunbc run`). The v2 copy is ingest/grammar-only (Map-based entries). -// Dissolution trigger: v2 `YamlMapping.entries` migrates to ordered pairs AND v2 emit/ingest -// imports this module (or a shared `std/formats/yaml.dag` home) — one YamlValue authority, -// zero parallel type definitions. -// -// v2-clean module (no std.unicode / std.render imports) so witnesses execute under -// the v1 interpreter. Ordered mapping entries preserve YAML key order (DESIGN §2: -// std Map is an unordered HAMT — unsuitable for deterministic emit). -// -// Anchor: https://yaml.org/spec/1.2.2/ - module extdeps.formats.yaml import std.render_repeat_string_bootstrap { repeat_string } @@ -43,8 +28,6 @@ type YamlValue data empty_yaml_values: List = [] -// -- scalar helpers --------------------------------------------------- - fn yaml_string(s: String) -> YamlValue { YamlString { value: s } } @@ -69,8 +52,6 @@ fn kv(key: String, value: YamlValue) -> YamlKeyValue { YamlKeyValue { key: key, value: value } } -// -- indent / layout -------------------------------------------------- - fn indent(depth: Int) -> String { repeat_string(s: " ", n: depth) } @@ -83,8 +64,6 @@ fn is_expression(s: String) -> Bool { starts_with(s: s, prefix: "${{") } -// Plain scalar unless YAML parsing would mis-read the value. Embedded shell quotes, -// single quotes in hashFiles(), and colons inside ${{ }} are valid plain scalars. fn is_reserved_yaml_scalar(s: String) -> Bool { (s == "true") || (s == "false") || @@ -194,7 +173,6 @@ fn strip_leading_indent(line: String, depth: Int) -> String { } } -// Block sequence of mappings: `- key: val` on the first entry; sibling keys share item indent. fn prefix_block_sequence_mapping(body: String, seq_depth: Int) -> String { let item_depth = seq_depth + 1 let lines = split(s: body, delimiter: "\n") @@ -280,7 +258,6 @@ fn emit_yaml_value(v: YamlValue, depth: Int) -> String { } } -// Total serializer: YamlValue → byte-faithful YAML text (trailing newline at EOF). fn serialize_yaml(v: YamlValue) -> String { emit_yaml_value(v: v, depth: 0) } diff --git a/dsl/extdeps/git/git.dag b/dsl/extdeps/git/git.dag index a49ac51bfa5..2c8f6222275 100644 --- a/dsl/extdeps/git/git.dag +++ b/dsl/extdeps/git/git.dag @@ -1,23 +1,7 @@ -// extdeps/git/git.dag -- "What is Git?" -// -// Core Git object model: commits, branches, refs, diffs, merge strategies, -// and the shell-transport binding of git's operations (co-located since the -// services/ tree was merged into extdeps/, commit 55dd577e8c). The operations -// below model git's *interface shape*; `transport shell` is one realization -// handler (libgit2 / the GitHub compare API are others not yet bound). -// -// Consumers: -// gunbc/tools/gist.dag -- branch name -// shared/gist_modes.dag -- git operations -// extdeps/github/pull_requests.dag -- PR branch refs -// tools/build.dag -- branch detection - module extdeps.git import std.types { CommitSha, Email, FilePath, GitRef, Timestamp, Url } -// -- Object model -------------------------------------------------- - type ObjectType = BlobObj | TreeObj | CommitObj | TagObj type GitAuthor { @@ -26,8 +10,6 @@ type GitAuthor { timestamp: Timestamp } -// -- Refs ---------------------------------------------------------- - type GitBranch { name: String upstream: String? @@ -40,25 +22,6 @@ type GitRemote { fetch_refspec: String } -// -- Worktrees ------------------------------------------------------- -// A worktree is a checkout of the repository at a path: the main -// worktree plus zero or more linked worktrees (`git worktree add`), -// all sharing one object store and refs. Each non-bare worktree has -// exactly one checked-out HEAD; a branch may be checked out in at -// most one worktree at a time. - -// Coproduct dissolution classification (DESIGN.md §2 decompress->map->reduce): -// 🟢 GREEN (terminal). Git's worktree HEAD is exactly one of two -// irreducible states — checked out on a branch, or detached at a commit — -// and `git worktree list` reports precisely this distinction. The -// variants carry structurally distinct payloads (a branch ref vs a bare -// sha). Ledger (Patterns 1–5): (1) fact-placement rejected — both states -// feed the same consumer (a worktree's checkout), no per-consumer split. -// (2) variant-is-data rejected — GitBranch and CommitSha are different -// shapes, not a label over one payload. (3) no std algebraic source. -// (4) not dimensional — on-branch/detached is a single binary state, not -// a factoring of orthogonal axes. (5) not a parameterized family. Git's -// own HEAD-state dichotomy is the source. type GitWorktreeHead = WorktreeOnBranch { branch: GitBranch } | WorktreeDetached { sha: CommitSha } @@ -66,12 +29,10 @@ type GitWorktreeHead type GitWorktree { path: FilePath head: GitWorktreeHead - is_main: Bool // the original checkout vs a linked worktree - locked: Bool // `git worktree lock` -- protected from prune + is_main: Bool + locked: Bool } -// -- Diff model ---------------------------------------------------- - type DiffStat { files_changed: Int insertions: Int @@ -90,19 +51,10 @@ type DiffHunk { lines: List } -// -- Constants ----------------------------------------------------- - data default_remote: String = "origin" data default_branch_names: List = ["main", "master"] -// -- Service: shell transport wiring ----------------------------- - -// 🟡 dissolved — feature:git-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); the published corpus (extdeps.git.mock_corpus) now governs WHICH -// git.Core ops are hermetically realizable, and the fixture store owns the payloads (§3). -// forbidden: reintroducing mock_response constants for Hermetic dispatch on these shapes. service git.Core { operation CurrentBranch { input {} @@ -148,10 +100,6 @@ service git.Core { } } - // Name-only diff projection — git's two faithful diff modes. Both are git - // primitives; the *policy* of which mode and which base (e.g. "origin/main") - // belongs to the workflow consumer, NOT to this model (tools.rust_gates_ci - // composes DiffNameOnlyMerge directly). operation DiffNameOnly { input { base: GitRef, head: GitRef = "HEAD" } output { @@ -166,8 +114,6 @@ service git.Core { } } - // Three-dot (merge-base) name-only diff: paths changed on `head` since it - // diverged from `base`. A documented git primitive (`git diff A...B`). operation DiffNameOnlyMerge { input { base: GitRef, head: GitRef = "HEAD" } output { diff --git a/dsl/extdeps/git/gitignore.dag b/dsl/extdeps/git/gitignore.dag index 9043e8b2f7f..a4348e64f42 100644 --- a/dsl/extdeps/git/gitignore.dag +++ b/dsl/extdeps/git/gitignore.dag @@ -1,15 +1,7 @@ -// extdeps/git/gitignore.dag -- "What is .gitignore?" -// -// Stable domain model of .gitignore files. Tautological definitions: -// categories group exclusion patterns with provenance and rationale. -// -// Consumers: config/gitignore.dag (data), tools/bootstrap.dag (rendering). - module extdeps.gitignore import std.render { OutputFormat } -// A category of gitignore rules with provenance tracking. type GitignoreCategory { id: String name: String @@ -19,13 +11,11 @@ type GitignoreCategory { when_build_system: String? } -// A complete .gitignore file with provenance rule comment. type GitignoreFile { rule_comment: String categories: List } -// OutputFormat parameterization for .gitignore. data gitignore_output_format: OutputFormat = { name: "Gitignore", indent_unit: "", @@ -36,8 +26,6 @@ data gitignore_output_format: OutputFormat = { trailing_newline: true } -// -- Category filtering ----------------------------------------------- - fn filter_categories(categories: List, build_system: String) -> List { let by_build = filter(categories, c => match c.when_build_system { Absent => true diff --git a/dsl/extdeps/git/gitignore_render.dag b/dsl/extdeps/git/gitignore_render.dag index 0c5511c8f20..443cee504d2 100644 --- a/dsl/extdeps/git/gitignore_render.dag +++ b/dsl/extdeps/git/gitignore_render.dag @@ -1,9 +1,3 @@ -// extdeps/git/gitignore_render.dag -- Gitignore rendering functions. -// -// Rendering fns extracted from extdeps/git/gitignore.dag to separate -// domain model from serialization (same pattern as markdown.dag + -// markdown_render.dag). - module extdeps.gitignore_render import extdeps.gitignore { GitignoreCategory, GitignoreFile } diff --git a/dsl/extdeps/git/mock_corpus.dag b/dsl/extdeps/git/mock_corpus.dag index cffedf8ff96..22bb9611651 100644 --- a/dsl/extdeps/git/mock_corpus.dag +++ b/dsl/extdeps/git/mock_corpus.dag @@ -1,18 +1,3 @@ -// dsl/extdeps/git/mock_corpus.dag -// Scope: the git layer's PUBLISHED mock corpus as a closed, declared structural fact. -// Anchor: DESIGN.md §3 (single authority) / §6 (model-just-in-time, mark the carrier). -// -// SINGLE authority for WHICH git.Core operations are hermetically realizable. Read by BOTH the -// compile-time M2 mock_totality_lens (src/v2/lens/mock_totality.dag, via the per-layer witness) -// AND the v1 runtime's eval_service_call (the M4 hermetic-realization fold) — one model, not two. -// The v1 runtime loads the dsl/ tree, so this corpus lives in dsl/ for the runtime to reach the -// SAME model the lens reads. Modeled on the M4.0 filesystem pilot -// (dsl/extdeps/filesystem/mock_corpus.dag, #5188). -// -// Rows inhabit std.hermetic_replay.PublishedMockCase. The operation set authority remains -// dsl/extdeps/git/git.dag (`service git.Core`); per-case payloads live in the Phase-2 -// RecordedFixture store ONLY — rows carry the (operation_key, service, operation, case_id) structural key. - module extdeps.git.mock_corpus import std.hermetic_replay { PublishedMockCase } @@ -80,15 +65,6 @@ data git_core_mock_case_show: PublishedMockCase = PublishedMockCase { case_id: 0 } -// 🟡 gated — feature:git-mock-corpus-from-service-decl — bind node://adhoc-aeaa1c56-be5 -// dissolve-on-arrival: project this corpus directly from the `service git.Core` operation set in -// dsl/extdeps/git/git.dag (the SINGLE authority for WHICH operations exist), joined with the -// Phase-2 RecordedFixture store (the authority for WHICH recorded cases exist per operation), once -// a v2 lens can read a service decl's operation nodes and the fixture store's keys; this declared -// list then deletes in the same PR. forbidden: a row carrying a response VALUE (branch/branches/ -// files/diff/paths/commits/base_ref/content) — that would fork the payload authority, now owned -// by the fixture store (§3); rows mirror the (operation_key, case_id) structural key ONLY, and grow -// when a published operation/case is added upstream. data git_published_mock_corpus: List = [ git_core_mock_case_current_branch, git_core_mock_case_remote_branches, diff --git a/dsl/extdeps/git/object_store.dag b/dsl/extdeps/git/object_store.dag index 4c6ab7af548..57bd2216546 100644 --- a/dsl/extdeps/git/object_store.dag +++ b/dsl/extdeps/git/object_store.dag @@ -1,16 +1,3 @@ -// extdeps/git/object_store.dag — Git content-addressed object store -// -// Spec: https://git-scm.com/book/en/v2/Git-Internals-Git-Objects -// Wikipedia: https://en.wikipedia.org/wiki/Object_storage#Content-addressable_storage -// Sections referenced: -// Git Internals §"Git Objects" — blob, tree, commit object types and hash addressing -// Git Internals §"Git References" — refs as name→hash bindings over the CAS store -// -// Git's object store is a content-addressed object store (CAS inhabitant): each -// object's address is the SHA-1 or SHA-256 hash of its content. ObjectRef is the -// CAS key, typed as CasObjectId. Blob/tree/commit are the three forge-plumbing -// object kinds in scope (gunbhub S1); tag objects live in extdeps.git.ObjectType. - module extdeps.git.object_store import std.types { ContentHash, NonEmptyStr } @@ -20,31 +7,19 @@ import extdeps.object_storage { ObjectContainer } import extdeps.object_storage.content_addressed { CasObjectId, CasAddressingConfig } import extdeps.git { GitAuthor, ObjectType } -// Git's CAS addressing configuration: one implicit container (the repo objects/), -// content-addressed by value, write-once per hash. data git_object_store_config: CasAddressingConfig = { container: { name: "objects" } key_derivation: ContentAddressedByValue write_mode: WriteOnce } -// A git object reference: the CAS key is the content hash. -// Alias of CasObjectId in the git domain — no hand-rolled hash field. type ObjectRef = CasObjectId -// --- Blob -------------------------------------------------------------------- - type Blob { size: ByteSize content: Bytes } -// --- Tree -------------------------------------------------------------------- - -// A tree entry names one child object with kind encoded structurally in the variant, -// so kind/hash mismatch is unrepresentable (no parallel kind field alongside hash). -// 🟢 TERMINAL — the three child-object kinds a tree entry can reference; closed by -// git's object trichotomy (blob, subtree, commit-via-submodule). type TreeEntry = BlobEntry { name: NonEmptyStr, hash: ContentHash } | SubtreeEntry { name: NonEmptyStr, hash: ContentHash } @@ -54,10 +29,6 @@ type Tree { entries: List } -// --- Commit ------------------------------------------------------------------ - -// author = who wrote the change; committer = who applied it to the tree. -// Reuses GitAuthor from extdeps.git — single authority for the git identity shape. type Commit { tree_hash: ContentHash parent_hashes: List @@ -66,41 +37,24 @@ type Commit { message: NonEmptyStr } -// --- Object union ------------------------------------------------------------ - -// 🟢 TERMINAL — the three mutable git object kinds in scope for gunbhub S1 -// (blob/tree/commit); closed by git's forge-plumbing trichotomy. type StoreObject = ObjectBlob { blob: Blob } | ObjectTree { tree: Tree } | ObjectCommit { commit: Commit } -// Lookup outcome — pairs the CAS address (ObjectRef) with the loaded payload. -// 🟢 TERMINAL — found/not-found; closed by content-addressed store GET semantics. type ObjectLookupResult = ObjectFound { ref: ObjectRef, object: StoreObject } | ObjectNotFound -// --- Refs: name → object bindings -------------------------------------------- - -// A ref target is a direct content hash or a symbolic pointer to another named ref. -// 🟢 TERMINAL — the two ref target kinds in git; closed by the git ref model -// (git-symbolic-ref(1), gitglossary(7) §"symbolic ref"). type RefTarget = DirectTarget { hash: ContentHash } | SymbolicTarget { ref_name: NonEmptyStr } -// Outcome of resolving a named ref chain to a concrete hash. -// 🟢 TERMINAL — the three ref traversal outcomes; closed by the git ref model -// (chain either resolves, does not exist, or contains a symbolic cycle). type RefResolutionResult = RefResolved { hash: ContentHash } | RefNotFound | SymbolicCycle -// --- Structural projections -------------------------------------------------- - -// 🟢 TERMINAL — structural fold: StoreObject variant → git ObjectType discriminant. fn store_object_kind(object: StoreObject) -> ObjectType { match object { ObjectBlob { blob: _ } => BlobObj diff --git a/dsl/extdeps/git/versioning.dag b/dsl/extdeps/git/versioning.dag index 2b311bc11a8..2a6612e6cb1 100644 --- a/dsl/extdeps/git/versioning.dag +++ b/dsl/extdeps/git/versioning.dag @@ -1,14 +1,3 @@ -// extdeps/git/versioning.dag — Git release version scheme. -// -// Spec: https://git-scm.com/docs/BreakingChanges.html -// Anchor: Git project release numbering since Git 2.0 — major.minor.patch -// triples where major increments only on deliberate breaking releases -// (multi-year cadence: Git 1.6.0, Git 2.0, future Git 3.0). NOT SemVer: -// Git does not follow semver.org semantics for its own releases. -// -// Layer-2 ecosystem model on extdeps.version (VersionIdentity + VersionScheme). -// Layer-3 constraint grounding: min_git_version (GitVersionConstraint). - module extdeps.git.versioning import std.types { Url } @@ -17,44 +6,33 @@ import std.algebra { Ordering, Equal, Greater } import std.nat { nat_compare } import extdeps.version { VersionIdentity, VersionScheme, VersionConstraint } -// Git release triple since the Git 2.0 numbering policy. type GitReleaseVersion { major: NonNegativeInt minor: NonNegativeInt patch: NonNegativeInt } -// Platform suffix on `git version` stdout (e.g. "2.43.0.windows.1"). type GitVersionPlatformSuffix = GitVersionPlain | GitVersionWindows { build: NonNegativeInt } -// Parsed shape of `git version` release component + optional platform suffix. type GitCliReportedVersion { git_release: GitReleaseVersion suffix: GitVersionPlatformSuffix } -// First Git 2.x breaking release — anchor for modern numbering policy. data git_2_0_release: GitReleaseVersion = { major: 2, minor: 0, patch: 0 } -// Spec citation for the release-numbering policy. data git_release_versioning_spec_url: Url = "https://git-scm.com/docs/BreakingChanges.html" -// Git release constraint wire text — predicate over identities, not a version. -// Distinct use site from generic VersionConstraint (§3 distinct facts). type GitVersionConstraint = VersionConstraint where brand("GitVersionConstraint") -// Minimum git for the Git 2.0 numbering policy anchor (BreakingChanges doc). -// Worktree modeling in extdeps/git/git.dag needs 2.5+ at runtime; this row -// is the honest policy floor, not a per-feature matrix. data min_git_version: GitVersionConstraint = ">= 2.0.0" -// Canonical wire label for a GitReleaseVersion (git version / release tag core). fn git_release_version_label(v: GitReleaseVersion) -> String { concat( to_string(v.major), @@ -62,12 +40,10 @@ fn git_release_version_label(v: GitReleaseVersion) -> String { ) } -// Projects GitReleaseVersion to the opaque VersionIdentity surface. fn git_release_to_version_identity(v: GitReleaseVersion) -> VersionIdentity { git_release_version_label(v: v) } -// Total order on Git release triples: major, then minor, then patch. fn git_release_version_compare(a: GitReleaseVersion, b: GitReleaseVersion) -> Ordering { match nat_compare(a: a.major, b: b.major) { Equal => match nat_compare(a: a.minor, b: b.minor) { @@ -78,11 +54,6 @@ fn git_release_version_compare(a: GitReleaseVersion, b: GitReleaseVersion) -> Or } } -// VersionIdentity ingress for extdeps.version.VersionScheme. -// Equality case is correct; full ordering requires parse ingress. -// Scaffold: dissolve-on: parse_git_release_version lands — replace body with: -// (a, b) => git_release_version_compare( -// a: parse_git_release_version(a), b: parse_git_release_version(b)) fn git_release_compare_identity(a: VersionIdentity, b: VersionIdentity) -> Ordering { if a == b { Equal } else { Greater } } diff --git a/dsl/extdeps/github/actions.dag b/dsl/extdeps/github/actions.dag index 5fe51bcf424..6f5347361bc 100644 --- a/dsl/extdeps/github/actions.dag +++ b/dsl/extdeps/github/actions.dag @@ -1,16 +1,3 @@ -// extdeps/github/actions.dag -- GitHub Actions platform model. -// -// Models the GitHub Actions CI/CD platform as external dependency facts: -// workflows, jobs, steps, runners, logging annotations, artifacts, and -// matrix strategies. These are platform constraints -- what GH Actions -// provides and requires -- not repository CI orchestration logic. (The gunbc CI -// gate/projection model that once consumed this carrier was retired in the CI-track rework.) -// -// Spec: https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions -// -// Related extdeps: -// extdeps/github/ci.dag — repository workflow path facts (complements this syntax model) - module extdeps.github.actions import extdeps.cron.schedule_model { CronSchedule } @@ -27,15 +14,6 @@ import extdeps.github.log_annotations { import extdeps.formats.yaml { YamlValue, YamlKeyValue } import std.types { NonEmptyStr, SecretName, Unit } -// §3 layering — ordered env/with/outputs on Workflow / Job / Step: -// 🟡 SCAFFOLD. Fields use `List` from `extdeps.formats.yaml` so emit -// preserves YAML key order (std Map is an unordered HAMT — see yaml.dag:11-12). The -// YAML value carrier binding the GitHub Actions syntax model is a known layer inversion -// (yaml.dag:5-8 documents the parallel fork; this module is the upward leak site). -// Dissolution trigger: `std` gains an ordered key/value pair primitive (reused by -// TOML/JSON emitters); `actions.dag` migrates to that type and format projectors -// consume it only at the extdeps/formats seam. - type GitHubActionsRuntime { oidc_request_url_env: NonEmptyStr oidc_request_token_env: NonEmptyStr @@ -46,19 +24,12 @@ data github_actions_runtime: GitHubActionsRuntime = { oidc_request_token_env: "ACTIONS_ID_TOKEN_REQUEST_TOKEN" } -// -- Workflows -------------------------------------------------------- -// A workflow is the top-level unit: trigger + jobs. -// `concurrency` is workflow-scoped (YAML `concurrency:`); `none` = block absent. -// Actions accepts a scalar group string or a mapping (`group` + optional `cancel-in-progress`); -// both are modeled — no fabricated booleans when the mapping omits `cancel-in-progress`. - type Workflow { name: String on: List concurrency: ConcurrencySpec? jobs: List - // `none` models an absent top-level `env:` block in Actions YAML (no fabricated keys). - // Ordered key/value pairs (YAML key order is semantic; std Map is unordered). + env: List? permissions: WorkflowPermissions? } @@ -72,9 +43,6 @@ type WorkflowPermissions { type PermissionLevel = PermRead | PermWrite | PermNone -// -- Triggers --------------------------------------------------------- -// Events that cause a workflow to run. - type WorkflowTrigger = Push { branches: List, paths: List } | PullRequest { branches: List, types: List } @@ -99,62 +67,22 @@ type DispatchInput { type DispatchInputType = InputString | InputBoolean | InputChoice | InputEnvironment -// -- Secrets ---------------------------------------------------------- -// Opaque-at-rest secret reference scoped by step / job / workflow. -// Resolution happens at workflow-execution time via the provider's -// secret store (GitHub Secrets); the substrate carries only the -// typed identifier (`SecretName` from std.types -- already cross-provider -// with anthropic/openai providers) and the workflow-scope binding. -// The scope discriminator IS GitHub-Actions-specific (not all providers -// distinguish step-vs-job-vs-workflow secret scopes), which is why the -// carrier folds into actions.dag rather than std. -// -// Coproduct dissolution classification (DESIGN.md §2 decompress->map->reduce): -// 🟡 SCAFFOLD. The three-way step/job/workflow scope split mirrors the -// existing placement sites (`Step.env`, `Job.env`, `Workflow.env`) named -// in the dissolution trigger below: once `WorkflowSecret` attaches at -// those sites in Slice 3, scope becomes structural (a `WorkflowSecret` -// living inside `Step.env` is step-scoped by placement; the explicit -// `SecretScope` field duplicates that placement fact). Dissolution -// trigger is therefore the SAME Slice 3 wiring that attaches the -// carrier -- at that point `SecretScope` and the `scope` field on -// `WorkflowSecret` collapse into the placement structure and the -// coproduct can be dropped. -// -// Structural-consumer dissolution trigger: -// `WorkflowSecret` is a Slice 1 carrier introduction; structural attachment -// to consumer sites (`Step.env`, `Job.env`, `Workflow.env`) is the **next** -// shape change after today's GitHub-faithful optional plain-text maps -// (`Map?` everywhere — `none` = absent `env:` at workflow, -// job, and step scopes; no fabricated keys). Slice 3 upgrades those maps to a -// sum type that includes `WorkflowSecret` (`ci_workflow_modeled_as_dag` demo, -// tracked at #1956), consuming Slices 1+2. Until that wiring lands, the carrier -// is intentionally unattached -- promoting the env-shape change in Slice 1 -// would expand the migration cascade beyond the brief's authorized 2-fixture scope. - type SecretScope = StepScope | JobScope | WorkflowScope -// `name` is enforced as `SecretName` (the cross-provider authority in -// `std.types`), not a free type parameter -- the brief's `WorkflowSecret` -// shape collapses to the concrete binding once the cross-provider grep -// confirmed `SecretName` already exists at std. type WorkflowSecret { name: SecretName scope: SecretScope } -// -- Jobs ------------------------------------------------------------- -// A job runs on a runner, has steps, and may depend on other jobs. - type Job { id: String name: String? runner: RunnerSpec steps: List needs: List - // `none` models an absent `env:` block in Actions YAML (no fabricated keys). + env: List? - // Job outputs: ordered name -> expression pairs. + outputs: List? if_condition: String? strategy: MatrixStrategy? @@ -163,76 +91,33 @@ type Job { concurrency: ConcurrencySpec? } -// YAML `concurrency:` is either a scalar group expression or a mapping. -// See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency -// and https://docs.github.com/en/actions/using-jobs/using-concurrency (mapping keys -// `group`, `cancel-in-progress`, `queue`; expression-valued cancel-in-progress). - -// Coproduct dissolution classification (DESIGN.md §2 decompress->map->reduce): -// 🟡 YELLOW (scaffold). Literal bool vs opaque `${{ }}` expression string mirrors GitHub's -// surface union; richer source is a typed Actions boolean-expression carrier when/if -// modeled structurally in this repo. -// Named dissolution trigger: typed workflow-boolean expression substrate lands AND -// `gunbc/ci_emission.dag` projection consumes it for `cancel-in-progress` mapping values. type CancelInProgressSpec = CancelInProgressBool { value: Bool } | CancelInProgressExpression { expression: String } -// When YAML fixes `queue: max`, GitHub rejects `cancel-in-progress: true` (literal bool). -// This sum therefore excludes literal `true` while still modeling omitted key, literal -// `false`, and opaque `${{ }}` (expression truth remains runtime — see 🟡 below). -// -// Coproduct dissolution classification (DESIGN.md §2 decompress->map->reduce): -// 🟢 GREEN (terminal). `QueueMaxCancelInProgressFalse` is 1:1 with YAML `cancel-in-progress: false`. -// 🟡 YELLOW (scaffold). `QueueMaxCancelInProgressExpression` mirrors expression-valued mapping; -// GitHub may still reject at runtime if the expression evaluates to true with `queue: max`. -// Named dissolution trigger: same as `CancelInProgressSpec` — typed boolean-expression substrate -// plus `gunbc/ci_emission.dag` consumption for mapping values. type CancelInProgressWhenQueueMax = QueueMaxCancelInProgressFalse | QueueMaxCancelInProgressExpression { expression: String } -// 🟡 YELLOW (scaffold). Scalar vs mapping mirrors GitHub's top-level `concurrency:` grammar -// split. Mapping is split into two arms so `queue: max` + literal `cancel-in-progress: true` -// is **unrepresentable** (GitHub validation rejects that product — docs: -// https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#concurrency ). -// Named dissolution trigger: GitHub adds documented concurrency mapping fields beyond -// `group` / `cancel-in-progress` / `queue` OR emitter needs single-axis dimensional dispatch. type ConcurrencySpec = ConcurrencyScalar { group: String } | ConcurrencyMappingQueueMax { group: String - // `none` when YAML omits `cancel-in-progress:` (do not invent `false`). + cancel_in_progress: CancelInProgressWhenQueueMax? } | ConcurrencyMappingQueueNotMax { group: String - // `none` when YAML omits `cancel-in-progress:` (do not invent `false`). + cancel_in_progress: CancelInProgressSpec? - // `none` when YAML omits `queue:` (GitHub default single-queue semantics). - // `some(Unit)` when YAML sets explicit `queue: single` (marker only — no payload). + explicit_single: Unit? } -// -- Runners ---------------------------------------------------------- -// The execution environment for a job. - -// Coproduct dissolution classification (DESIGN.md §2 decompress->map->reduce): -// 🟢 GREEN (terminal). `HostedRunner` + `RunnerLabel` are a closed scaffold set aligned with -// GitHub's documented hosted runner images for this repo's first-draft model. -// Ledger (patterns 1–4): no cheaper dissolution for the label enum itself — expanding the -// closed set is a deliberate taxonomy change when GitHub documents new hosted targets. -// 🟡 YELLOW (scaffold). `SelfHosted` carries arbitrary label strings as GitHub accepts for -// self-hosted runner label matching; dissolution: typed runner-label substrate OR emission -// narrows to a closed vocabulary where the compiler owns runner topology. -// 🟡 YELLOW (scaffold). `RunsOnExpression` mirrors GitHub's expression-valued `runs-on:` form; -// the opaque string is faithful YAML surface syntax, not a typed Actions expression carrier. -// Named dissolution trigger: typed Actions string-expression substrate for `runs-on:` AND -// `gunbc/ci_emission.dag` projection consumes it for emitted workflow YAML. type RunnerSpec = HostedRunner { label: RunnerLabel } | SelfHosted { labels: List } - // `runs-on:` as an expression (e.g. `${{ vars.CI_RUNNER || 'ubuntu-latest' }}`). + | RunsOnExpression { expression: String } type RunnerLabel @@ -243,9 +128,6 @@ type RunnerLabel | Macos14 | WindowsLatest -// -- Steps ------------------------------------------------------------ -// Each step either runs a shell command or uses a published action. - type Step = RunStep { name: String?, @@ -262,7 +144,7 @@ type Step name: String?, id: String?, uses: ActionRef, - // `none` models omitted `with:` or YAML `with: {}` (no fabricated action inputs). + with: List?, env: List?, if_condition: String?, @@ -278,21 +160,12 @@ type ActionRef { ref: String } -// -- Logging annotations ---------------------------------------------- -// Workflow commands that the runner interprets from stdout. -// Authority: extdeps/github/log_annotations.dag (imported above). - -// -- Artifacts -------------------------------------------------------- -// Upload/download operations for build artifacts. -// Spec: https://docs.github.com/en/actions/using-workflows/storing-workflow-data-as-artifacts - type ArtifactOp = Upload { name: String, path: String, retention_days: Int?, if_no_files_found: MissingFilesBehavior } | Download { name: String, path: String? } type MissingFilesBehavior = Warn | ErrorOut | Ignore -// Standard action refs for artifact operations. data upload_artifact_action: ActionRef = ActionRef { owner: "actions", repo: "upload-artifact", ref: "v2" } @@ -301,9 +174,6 @@ data download_artifact_action: ActionRef = ActionRef { owner: "actions", repo: "download-artifact", ref: "v2" } -// -- Matrix strategy -------------------------------------------------- -// Parameterized job execution across multiple configurations. - type MatrixStrategy { dimensions: Map> include: List> @@ -312,9 +182,6 @@ type MatrixStrategy { max_parallel: Int? } -// -- Check conclusions ------------------------------------------------ -// Terminal states for a workflow run, job, or step. - type CheckConclusion = Success | Failure @@ -323,9 +190,6 @@ type CheckConclusion | TimedOut | ActionRequired -// -- Common action refs ----------------------------------------------- -// Well-known actions referenced by CI workflows. - data checkout_action: ActionRef = ActionRef { owner: "actions", repo: "checkout", ref: "v5" } @@ -338,8 +202,6 @@ data cache_action: ActionRef = ActionRef { owner: "actions", repo: "cache", ref: "v5" } -// -- Platform constants ----------------------------------------------- - data max_job_timeout_minutes: Int = 360 data default_job_timeout_minutes: Int = 360 diff --git a/dsl/extdeps/github/auth.dag b/dsl/extdeps/github/auth.dag index 99fc019b9d6..0aa3cdda86f 100644 --- a/dsl/extdeps/github/auth.dag +++ b/dsl/extdeps/github/auth.dag @@ -1,10 +1,3 @@ -// extdeps/github/auth.dag -- GitHub credential acquisition. -// -// Delegates to extdeps.shell.credentials for concrete materialization. -// Service-specific knowledge (which secret, which scopes) stays here; -// materialization mechanics (read env var via the host shell) live in -// extdeps.shell.credentials. - module extdeps.github.auth import extdeps.github.github { GitHubAuthToken, GitHubScope, ScopeGist, ScopeRepo } @@ -12,9 +5,6 @@ import std.credentials { CredentialSource, EnvVar } import extdeps.shell.credentials { env_credential } import std.types { NonEmptyStr, Timestamp } -// The default PAT path cannot introspect GitHub-issued token claims. Keep the -// locally declared policy explicit so callers can distinguish configured -// assumptions from provider-verified token metadata when that surface lands. type GitHubTokenMetadataAuthority = DeclaredGitHubTokenMetadata { scopes: List, expires_at: Timestamp? } diff --git a/dsl/extdeps/github/ci.dag b/dsl/extdeps/github/ci.dag index 71aecd28c0b..bfc3ae1b116 100644 --- a/dsl/extdeps/github/ci.dag +++ b/dsl/extdeps/github/ci.dag @@ -1,56 +1,19 @@ -// extdeps/github/ci.dag — GitHub repository facts for Actions workflow artifacts. -// -// This module is the extdeps home for **where** GitHub expects workflow YAML -// under a repository tree — not the YAML syntax model (`extdeps.github.actions` -// in actions.dag). gunbc CI workflow YAML is emitted from `gunbc.ci_workflow` -// via `gunbc.ci_yaml_emit` (byte-drift-gated; see dsl/tools/ci_yaml_gate.dag). -// -// `extdeps.github.actions.Workflow` stays a platform-only carrier (no emission- -// policy fields). This module declares only *where* GitHub loads workflow YAML. -// -// Spec (workflow file location): https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions - module extdeps.github.ci import std.types { NonEmptyStr } -// Directory (repository-relative, forward slashes) where GitHub loads workflow definitions. -// Single string authority for the tree root — do not add a parallel unconstrained -// `path: String` carrier for the same fact (DESIGN.md §3 single authority). data github_actions_workflows_dir: String = ".github/workflows" -// Coproduct dissolution classification (DESIGN.md §2 decompress->map->reduce): -// 🟢 GREEN (terminal). GitHub allows exactly two filename suffixes for workflow definitions -// under `.github/workflows/` (`.yml` / `.yaml`); variants are 1:1 with that closed surface. -// Ledger (Patterns 1–4): (1) no per-consumer split — suffix is global to the file ref. -// (2) variant-is-data rejected — the two suffixes are not labels on identical payloads; they -// select distinct YAML parse entrypoints. (3) no std algebraic source. (4) not dimensional -// beyond the single binary suffix axis already explicit in the two variants. type GitHubActionsWorkflowExtension = GitHubActionsWorkflowYml | GitHubActionsWorkflowYaml -// Coproduct dissolution classification (DESIGN.md §2 decompress->map->reduce): -// 🟡 YELLOW (scaffold). `NonEmptyStr` + nominal brand enforces non-emptiness only; GitHub -// additionally requires a single path segment (no `/`) and stem/extension consistency -// (no embedded `.yml`/`.yaml` suffix in the segment when extension is carried separately). -// Named dissolution trigger: WI-2 / Slice 4 `project_github_actions` emitter asserts stem -// segment invariant at projection boundary (#1956) OR `std` lands a validated workflow- -// basename refinement rejecting `/` and suffix overlap with `GitHubActionsWorkflowExtension`. type GitHubActionsWorkflowStemSegment = NonEmptyStr where brand("GitHubActionsWorkflowStemSegment") -// Filename stem (no `/`, no extension suffix — enforced at projection per YELLOW trigger). -// Projection joins: -// github_actions_workflows_dir + "/" + segment + (extension → ".yml" | ".yaml") type GitHubActionsWorkflowStem { segment: GitHubActionsWorkflowStemSegment } -// Workflow file identity: composes only with `github_actions_workflows_dir` — no -// unconstrained repository-relative path string as a second authority. -// Coproduct dissolution classification (DESIGN.md §2 decompress->map->reduce): -// 🟢 GREEN (terminal). Product of the fixed-dir constant + stem + closed extension; -// single structural sink for "which workflow file" under the GitHub layout rule. type GitHubActionsWorkflowFileRef { stem: GitHubActionsWorkflowStem extension: GitHubActionsWorkflowExtension diff --git a/dsl/extdeps/github/errors.dag b/dsl/extdeps/github/errors.dag index e1c17b741df..8e5bc0d530e 100644 --- a/dsl/extdeps/github/errors.dag +++ b/dsl/extdeps/github/errors.dag @@ -1,8 +1,3 @@ -// extdeps/github/errors.dag -- GitHub REST API error envelope shape. -// -// Spec: https://docs.github.com/en/rest/overview/resources-in-the-rest-api#client-errors -// API version: 2022-11-28 (X-GitHub-Api-Version header) - module extdeps.github.errors import std.types { Url } diff --git a/dsl/extdeps/github/expressions.dag b/dsl/extdeps/github/expressions.dag index 43e0432dad0..9c832403429 100644 --- a/dsl/extdeps/github/expressions.dag +++ b/dsl/extdeps/github/expressions.dag @@ -1,41 +1,3 @@ -// extdeps/github/expressions.dag — GitHub Actions `${{ }}` expression sub-language as Nodes. -// -// The first roster entry of the **medium-as-Node guard** (docs/plans/emission-ingestion-inverse.md -// §5: a target medium stays a modeled Node from authoring through checking; raw string only at the -// realization edge). GitHub Actions expressions are a sub-language layered on YAML scalars; modeling -// them as opaque `String` (see `actions.dag` `RunsOnExpression { expression: String }`, 🟡 scaffold) -// makes every consumer hand-author the `${{ … }}` delimiters and every check string-grep the emitted -// YAML — an ad-hoc partial re-ingest, the N×M heuristic DESIGN §4 forbids. This module makes the -// expression a typed `Node`, and `serialize_expression` / `interpolate` the SINGLE place the -// `${{ … }}` delimiter bytes are produced. Emit-side (`gunbc.ci_workflow_expressions`) and check-side -// (the model-walk witnesses) both consume it; neither carries the inline syntax (§3 single authority). -// -// Grounding (DESIGN §3 — cite the real upstream, keep its real names, model what it actually provides): -// Expressions: https://docs.github.com/en/actions/learn-github-actions/expressions -// Contexts: https://docs.github.com/en/actions/learn-github-actions/contexts -// The context set (`github`/`env`/`vars`/`runner`/…) and the documented functions -// (`contains`/`hashFiles`/…) are GitHub's, not minted nicknames. -// -// Scope (the first instance — one medium): the expression sub-language sufficient for the -// expressions `gunbc.ci_workflow` emits (context access, function call, logical-or, string literal, -// and a literal/interpolation template). NOT all of YAML and NOT shell-in-`run:` blocks — those are -// later roster entries (§5.1 census). -// -// v1-interpreter-clean (only language builtins + citation deps), so the witnesses execute under -// `gunbc run` exactly as `extdeps/formats/yaml.dag` does. -// -// 🟡 SCAFFOLD (round-trip slice, #5527) — feature:gha-expr-round-trip; dissolve-on: the v2 -// 06_translate GHA-expression `TargetModel` lands and the `ExpressionSpellings` delimiter ROWS + -// the v1-seed `ingest_*` relocate into it as the TargetModel `binding_spellings` -// (`Map`) read by the grammar-inverse `target_model_edge_translation_rules` — they -// RELOCATE, no rework (same rows, table-driven), and the §5.2 round-trip law is then INHERITED from -// `v2.compiler.source_authority.source_authority_round_trip_with_model` over that TargetModel, not -// this hand-rolled v1-seed ingest + witness. (Parity with the markdown medium's header dissolve-on, -// `extdeps/languages/markdown.dag`.) SCOPE of this scaffold: the `ExpressionSpellings` rows and -// `ingest_expression` / `ingest_template` (the §5.2 round-trip inverse, this slice). The typed -// `Expression` / `ExpressionTemplate` model, the `serialize_*` emit, and the model-walk guard -// witnesses are the MERGED medium-as-Node surface (#5499), NOT scaffold. - module extdeps.github.expressions import extdeps.external_authority { ExternalAuthority } @@ -49,10 +11,6 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// -- Contexts --------------------------------------------------------- -// The documented GitHub Actions expression contexts (the objects an expression may read). -// Closed set per the contexts spec; expanding it is a deliberate taxonomy change when GitHub -// documents a new context. type ExpressionContext = Github | Env @@ -67,7 +25,6 @@ type ExpressionContext | Needs | Inputs -// The documented GitHub Actions expression functions (general + status-check). type ExpressionFunction = Contains | StartsWith @@ -82,30 +39,12 @@ type ExpressionFunction | Cancelled | Failure -// -- Expression ------------------------------------------------------- -// One `${{ … }}` expression, as an AST rather than a string. -// -// Field ledger (§2 decompress — each arm genuinely atomic): -// ContextAccess — a context object read by a dotted property path. `runner.os` is -// `ContextAccess { context: Runner, path: ["os"] }`; `github.event.pull_request.number` -// is `ContextAccess { context: Github, path: ["event", "pull_request", "number"] }`. The -// path is the grounded GitHub property path — NOT split into a fresh enum per context -// (GitHub's property space per context is open). -// FunctionCall — a documented function applied to argument expressions. -// StringLiteral — a single-quoted expression-level string literal (GitHub uses `'…'`). -// LogicalOr — the `||` operator (the only operator `ci_workflow` uses today; other -// operators are added as arms when a consumer needs them, not pre-minted — §6 just-in-time). type Expression = ContextAccess { context: ExpressionContext, path: List } | FunctionCall { function: ExpressionFunction, args: List } | StringLiteral { value: String } | LogicalOr { left: Expression, right: Expression } -// -- Template --------------------------------------------------------- -// A YAML scalar may interleave literal text with one or more `${{ }}` expressions -// (`cargo-ci-${{ runner.os }}-${{ runner.arch }}-…`). A template is that interleaving: -// literal runs and interpolated expressions. A lone `${{ runner.temp }}` is the degenerate -// one-segment template `[Interpolation { … }]`. type TemplateSegment = LiteralText { text: String } | Interpolation { expression: Expression } @@ -114,8 +53,6 @@ type ExpressionTemplate { segments: List } -// -- Serialization (the SINGLE delimiter-byte authority) -------------- - fn context_name(context: ExpressionContext) -> String { match context { Github => "github" @@ -150,24 +87,15 @@ fn function_name(function: ExpressionFunction) -> String { } } -// -- The delimiter spelling rows (single authority, read in BOTH directions) --- -// -// Every structural delimiter byte the serializer produces lives in ONE row the -// fold looks up, so a wrong delimiter is one row edit (and one RED witness), -// never a literal buried in the fold. This is what lets the §5.2 round-trip law -// read the SAME rows backward (the ingest below) — DESIGN §4 one grammar, both -// directions. The closed name maps (context_name / function_name) are the OTHER -// authority; ingest reverses those same functions. (The default values are the -// real GitHub Actions spellings — `${{ … }}`, `.`, `'…'`, `||` — not nicknames.) type ExpressionSpellings { - path_sep: String // "." dotted context property path - call_open: String // "(" function call open - call_close: String // ")" function call close - arg_sep: String // ", " between function arguments - string_quote: String // "'" expression-level string literal delimiter - or_op: String // " || " logical-or operator - interp_open: String // "${{ " interpolation open - interp_close: String // " }}" interpolation close + path_sep: String + call_open: String + call_close: String + arg_sep: String + string_quote: String + or_op: String + interp_open: String + interp_close: String } data default_expression_spellings: ExpressionSpellings = { @@ -189,7 +117,6 @@ fn serialize_args_with(args: List, sp: ExpressionSpellings) -> Strin join(map(args, a => serialize_expression_with(expression: a, sp: sp)), sp.arg_sep) } -// The expression body (no `${{ }}` delimiters): `runner.os`, `hashFiles('a', 'b')`, `x || y`. fn serialize_expression_with(expression: Expression, sp: ExpressionSpellings) -> String { match expression { ContextAccess { context: c, path: p } => @@ -203,7 +130,6 @@ fn serialize_expression_with(expression: Expression, sp: ExpressionSpellings) -> } } -// The place the interpolation delimiter bytes are produced (now via the rows). fn interpolate_with(expression: Expression, sp: ExpressionSpellings) -> String { join([sp.interp_open, serialize_expression_with(expression: expression, sp: sp), sp.interp_close], "") } @@ -220,10 +146,6 @@ fn serialize_template_with(template: ExpressionTemplate, sp: ExpressionSpellings concat(acc, serialize_segment_with(segment: segment, sp: sp))) } -// -- Canonical-spelling entries (the corpus surface; consumers untouched) ------ -// `serialize_expression` / `interpolate` / `serialize_template` keep their -// signatures, delegating to the `_with` forms over the default GHA spellings. - fn join_path(path: List) -> String { join_path_with(path: path, sp: default_expression_spellings) } @@ -232,13 +154,10 @@ fn serialize_args(args: List) -> String { serialize_args_with(args: args, sp: default_expression_spellings) } -// The expression body (no delimiters): `runner.os`, `hashFiles('a', 'b')`, `x || y`. fn serialize_expression(expression: Expression) -> String { serialize_expression_with(expression: expression, sp: default_expression_spellings) } -// The ONLY place the `${{ … }}` delimiter bytes are produced. Every emitted GitHub Actions -// expression in the corpus routes through here; nothing hand-authors the delimiters. fn interpolate(expression: Expression) -> String { interpolate_with(expression: expression, sp: default_expression_spellings) } @@ -251,41 +170,6 @@ fn serialize_template(template: ExpressionTemplate) -> String { serialize_template_with(template: template, sp: default_expression_spellings) } -// ========================================================================= -// INGEST — GHA expression SOURCE → Expression / ExpressionTemplate (the §5.2 -// round-trip inverse). DESIGN §4 one grammar, both directions; §5.2 the -// round-trip law `ingest ∘ emit = id` is the medium-completeness oracle. -// -// Reads the SAME authorities the emitter writes: the `ExpressionSpellings` -// delimiter rows (backward) AND the closed name maps `context_name` / -// `function_name` (reversed via the enumerations below — NO re-spelled second -// name authority; §3 single authority). Fail-closed: any structure outside the -// core yields `Absent`, never a fabricated expression (§5). -// -// FIDELITY BOUNDARY (extdeps.communication.medium): -// `ingest ∘ emit = id` is Lossless over the **FLAT canonical core**: -// - ContextAccess (context + dotted path), StringLiteral (delimiter-free value), -// - FunctionCall whose args are FLAT ContextAccess/StringLiteral, -// - LogicalOr in LEFT-associative (canonical) nesting, -// - ExpressionTemplate interleaving literal text + interpolations. -// This is round-trip-complete for the FLAT core, NOT the whole GHA expression -// language — nesting is COMMON in real GHA (`contains(x, fromJSON(y))`) and is -// explicitly the **Lossy frontier**, not claimed: -// - nested FunctionCall / LogicalOr as a function argument, -// - RIGHT-associative LogicalOr nesting (emit→ingest collapses to left-assoc: -// `id` on the canonical normal form, a section on non-canonical input), -// - StringLiteral values containing delimiter bytes (quote / `||` / `, ` / parens), -// - whitespace variants (`${{runner.os}}` — emit/ingest use canonical spacing only). -// Frontier inputs fail the round-trip (Absent or a different tree), asserted by -// execution in the witness — the boundary is enforced, not just commented. -// Dissolve-on: a precedence/paren-aware tokenizer recovering nested expressions, -// at which point nesting flips to Lossless. -// ========================================================================= - -// The closed variant enumerations — the reverse name lookups iterate these and -// match via the FORWARD authority (context_name / function_name), so the spelling -// of each name lives in exactly one place (§3). Listing the closed set is not a -// name fork; the names themselves are never re-typed here. data all_expression_contexts: List = [ Github, Env, Vars, Job, Jobs, Steps, Runner, Secrets, Strategy, Matrix, Needs, Inputs ] @@ -333,7 +217,6 @@ fn parse_args_with(args_str: String, sp: ExpressionSpellings) -> List Expression? { if expr_is_string_literal(s: s, sp: sp) { Present { value: StringLiteral { @@ -363,7 +246,6 @@ fn parse_atom_with(s: String, sp: ExpressionSpellings) -> Expression? { } } -// Top-level: split on or_op and fold LEFT (the canonical normal form), else atom. fn parse_expression_with(s: String, sp: ExpressionSpellings) -> Expression? { let parts = split(s: s, delimiter: sp.or_op) if parts.length() == 1 { @@ -387,8 +269,6 @@ fn ingest_expression(src: String) -> Expression? { ingest_expression_with(src: src, sp: default_expression_spellings) } -// Template ingest: split on interp_open; the leading segment is literal text, -// each following segment is ``. fn ingest_template_with(src: String, sp: ExpressionSpellings) -> ExpressionTemplate? { let parts = split(s: src, delimiter: sp.interp_open) let lead = parts.first() @@ -423,24 +303,14 @@ fn ingest_template(src: String) -> ExpressionTemplate? { ingest_template_with(src: src, sp: default_expression_spellings) } -// The §5.2 (B) per-medium decidability partition: the FLAT core is Lossless; -// the carried representation is the recovered expression. Nesting / non-canonical -// input is the unclaimed Lossy partition (never advertised by this Medium). fn gha_expression_medium_lossless(expr: Expression) -> Medium { Medium { carried: expr, fidelity: Lossless } } -// -- Runner-context grounding ----------------------------------------- -// Constructors for the runner context properties `gunbc.ci_workflow` reads (real property names). fn runner_os() -> Expression { ContextAccess { context: Runner, path: ["os"] } } fn runner_arch() -> Expression { ContextAccess { context: Runner, path: ["arch"] } } fn runner_temp() -> Expression { ContextAccess { context: Runner, path: ["temp"] } } -// The default environment variables GitHub injects that mirror the runner context (each has a -// proper `runner.*` home). Reading one of these through the `env` context instead of `runner.*` -// ties correctness to runtime step-ordering rather than the model — the bad state the model-walk -// guard flags. Grounded in the runner default-env-var table: -// https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables data runner_provided_env_var_names: List = [ "RUNNER_NAME", "RUNNER_OS", @@ -455,10 +325,6 @@ fn string_in_list(needle: String, haystack: List) -> Bool { fold(haystack, init: false, f: (acc, candidate) => acc || (candidate == needle)) } -// -- Model-walk predicates (the guard) -------------------------------- -// These walk the typed expression model — never the emitted YAML string. - -// True iff this expression (recursively) reads a runner-provided var through the `env` context. fn expression_accesses_runner_var_via_env(expression: Expression) -> Bool { match expression { ContextAccess { context: c, path: p } => @@ -475,7 +341,6 @@ fn expression_accesses_runner_var_via_env(expression: Expression) -> Bool { } } -// True iff this expression (recursively) reads the given context. fn expression_uses_context(expression: Expression, target: ExpressionContext) -> Bool { match expression { ContextAccess { context: c, path: _ } => context_name(context: c) == context_name(context: target) @@ -502,7 +367,6 @@ fn template_uses_context(template: ExpressionTemplate, target: ExpressionContext }) } -// Walk a roster of templates: does ANY interpolated expression read a runner-provided var via env? fn any_template_accesses_runner_var_via_env(templates: List) -> Bool { fold(templates, init: false, f: (acc, template) => acc || template_accesses_runner_var_via_env(template: template)) diff --git a/dsl/extdeps/github/gists.dag b/dsl/extdeps/github/gists.dag index 2eb41731c07..e3adec28506 100644 --- a/dsl/extdeps/github/gists.dag +++ b/dsl/extdeps/github/gists.dag @@ -1,20 +1,9 @@ -// extdeps/github/gists.dag -- "What is a GitHub Gist?" -// -// Gist resource model: files, visibility, versions. -// Simpler than issues/PRs -- gists are standalone code snippets. -// -// Consumers: -// shared/gist_modes.dag -- gist operations -// gunbc/tools/gist.dag -- gist creation workflow - module extdeps.github.gists import extdeps.github.github { GitHubUser, default_api_base } import std.types { Timestamp, GistId, Url, HttpMethod, AuthScheme } import extdeps.github.errors { GitHubErrorShape } -// -- Gist model ---------------------------------------------------- - type GistFile { filename: String content: String @@ -33,22 +22,14 @@ type Gist { html_url: Url } -// -- Service: REST transport wiring ------------------------------ -// -// 🟡 dissolved — feature:github-gist-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); the published corpus (extdeps.github.mock_corpus) now governs WHICH -// github.Gist ops are hermetically realizable, and the fixture store owns the payloads (§3). -// forbidden: reintroducing mock_response constants for Hermetic dispatch on this shape. - service github.Gist { config { endpoint: default_api_base auth: Bearer auth_input: auth_token - // GitHub API rate limits: 5000 requests/hour for authenticated users + rate_limit: { requests: 5000, per: hour, scope: core } - // Retry on rate limit and server errors with exponential backoff + retry: { max_attempts: 3, backoff: exponential, retry_on: [429, 500, 502, 503, 504] } } diff --git a/dsl/extdeps/github/github.dag b/dsl/extdeps/github/github.dag index 5b9682bbd39..cab10bf2c23 100644 --- a/dsl/extdeps/github/github.dag +++ b/dsl/extdeps/github/github.dag @@ -1,27 +1,10 @@ -// extdeps/github/github.dag -- "What is GitHub?" -// -// Core resource model: repositories, users, auth, pagination. -// Complements extdeps/api/github_ops.dag (which covers rate limits and tiers). -// REST-transport bindings of these resources live in sibling service files -// (pulls.dag, gists.dag, actions_runs.dag) -- co-located since services/ was -// merged into extdeps/. REST is one realization handler; the `gh` CLI and -// GraphQL are others not yet bound. -// -// Consumers: -// extdeps/github/issues.dag -- issue resource model -// extdeps/github/pull_requests.dag -- PR resource model -// extdeps/github/gists.dag -- gist resource model - module extdeps.github.github import std.serialization { VariantEncoding, StringVariant, VariantNaming, AsAuthored } import std.types { Timestamp, Url } -// Wire contract: GitHub API returns enum values as plain strings ("User", "Bot"). data wire_contract: VariantEncoding = StringVariant { naming: AsAuthored } -// -- Users --------------------------------------------------------- - type UserType = User | Bot | Organization type GitHubUser { @@ -30,8 +13,6 @@ type GitHubUser { type: UserType } -// -- Repositories -------------------------------------------------- - type Repository { owner: String name: String @@ -40,8 +21,6 @@ type Repository { default_branch: String } -// -- Authentication ------------------------------------------------ - type GitHubAuthToken { token: Secret scopes: List @@ -55,21 +34,14 @@ type GitHubScope | ScopeReadOrg | ScopeReadUser -// -- Pagination ---------------------------------------------------- -// GitHub uses Link-header cursor-based pagination. - type Pagination { per_page: Int cursor: String? has_next: Bool } -// -- Permissions --------------------------------------------------- - type GitHubPermission = PermRead | PermWrite | PermAdmin -// -- Constants ----------------------------------------------------- - data default_api_base: Url = "https://api.github.com" data default_per_page: Int = 30 diff --git a/dsl/extdeps/github/log_annotations.dag b/dsl/extdeps/github/log_annotations.dag index 88335fe7f95..d3bec40f702 100644 --- a/dsl/extdeps/github/log_annotations.dag +++ b/dsl/extdeps/github/log_annotations.dag @@ -1,10 +1,3 @@ -// extdeps/github/log_annotations.dag — GitHub Actions stdout log commands. -// -// Split from actions.dag so CI runners can import annotation rendering without -// the full workflow syntax model (which transitively imports cron). -// -// Spec: https://docs.github.com/en/actions/using-workflows/workflow-commands-for-github-actions - module extdeps.github.log_annotations type LogAnnotation @@ -27,21 +20,10 @@ data annotation_add_mask_prefix: String = "::add-mask::" data annotation_stop_commands_prefix: String = "::stop-commands::" fn shell_single_quote(s: String) -> String { - // POSIX sh: wrap in single quotes; internal ' → '\'' (end quote, escaped quote, resume). + concat("'", replace(s, "'", "'\\''"), "'") } -// Safe `printf '%s\n' …` for sh -c: one line, no word-split on spaces. fn emit_line_shell(line: String) -> String { concat("printf '%s\\n' ", shell_single_quote(s: line)) } - -// `render_log_annotation` (a hand-rolled forward emitter — `match` → `concat("::error::", …)`) -// was DELETED here (Gap A, PR #5505). It was dead (only re-exported via actions.dag, never -// called), and dissolving dead code into rows would be §5 specification-without-execution -// (DESIGN.md §5) — so it is removed as a dead scaffold, not migrated. The medium-agnostic -// emission intent now lives in `v2.std.diagnostic` (`EmitDirective` / `DiagnosticSeverity`); -// its Bash realization (`emit(EmitDirective, Bash)`) is in `v2.extdeps.languages.bash`. The -// GitHub-Actions severity realization (`::error`/`::warning` over this annotation model) lands -// with the GHA-as-Node arc; the `LogAnnotation` type + prefix data below are kept as that -// model's grounded carrier. diff --git a/dsl/extdeps/github/mock_corpus.dag b/dsl/extdeps/github/mock_corpus.dag index b7a42b5be4f..e03495536d0 100644 --- a/dsl/extdeps/github/mock_corpus.dag +++ b/dsl/extdeps/github/mock_corpus.dag @@ -1,17 +1,3 @@ -// dsl/extdeps/github/mock_corpus.dag -// Scope: the github layer's PUBLISHED mock corpus as a closed, declared structural fact. -// Anchor: DESIGN.md §3 (single authority) / §6 (model-just-in-time, mark the carrier). -// -// SINGLE authority for WHICH github.* operations are hermetically realizable. Read by BOTH the -// compile-time M2 mock_totality_lens (src/v2/lens/mock_totality.dag, via the per-layer witness) -// AND the v1 runtime's eval_service_call (the M4 hermetic-realization fold) — one model, not two. -// POST-M4.1 (#5236): the runtime precomputes published keys from the whole dsl/ tree, so this -// corpus is discoverable without co-locating an import into each service module's closure. -// -// Rows inhabit std.hermetic_replay.PublishedMockCase. The operation set authority remains -// dsl/extdeps/github/{pulls,gists}.dag (`service github.Pulls` / `service github.Gist`); -// per-case payloads live in the Phase-2 RecordedFixture store ONLY — rows carry the structural key. - module extdeps.github.mock_corpus import std.hermetic_replay { PublishedMockCase } @@ -72,15 +58,6 @@ data github_pulls_mock_case_list_comments: PublishedMockCase = PublishedMockCase case_id: 0 } -// 🟡 gated — feature:github-mock-corpus-from-service-decl — bind node://adhoc-2f09a66f-a60 -// dissolve-on-arrival: project this corpus directly from the `service github.Pulls` / -// `service github.Gist` operation sets in dsl/extdeps/github/{pulls,gists}.dag (the SINGLE -// authority for WHICH operations exist), joined with the Phase-2 RecordedFixture store (the -// authority for WHICH recorded cases exist per operation), once a v2 lens can read a service -// decl's operation nodes and the fixture store's keys; this declared list then deletes in the -// same PR. forbidden: a row carrying a response VALUE — that would fork the payload authority, -// now owned by the fixture store (§3); rows mirror the (operation_key, case_id) structural key -// ONLY, and grow when a published operation/case is added upstream. data github_published_mock_corpus: List = [ github_gist_mock_case_create, github_pulls_mock_case_list, diff --git a/dsl/extdeps/github/pulls.dag b/dsl/extdeps/github/pulls.dag index fafbea782a7..09f07714759 100644 --- a/dsl/extdeps/github/pulls.dag +++ b/dsl/extdeps/github/pulls.dag @@ -1,18 +1,3 @@ -// extdeps/github/pulls.dag -- GitHub Pull Requests API -// -// Spec: https://docs.github.com/en/rest/pulls/pulls -// API version: 2022-11-28 (X-GitHub-Api-Version header) -// Endpoints modeled: -// GET /repos/{owner}/{repo}/pulls (List) -// GET /repos/{owner}/{repo}/pulls/{pull_number} (Get) -// GET /repos/{owner}/{repo}/pulls/{pull_number} [diff] (Diff) -// POST /repos/{owner}/{repo}/issues/{issue_number}/comments (CreateComment) -// -// PR comments use the Issues API because PRs are issues in GitHub's model. -// -// Consumers: -// gunbc/tools/review.dag -- PR review workflow - module extdeps.github.pulls import extdeps.github.github { GitHubUser, default_api_base, default_per_page } @@ -21,33 +6,24 @@ import extdeps.github.errors { GitHubErrorShape } import std.credentials { CredentialSource, EnvVar } import std.serialization { WireFormat, Text, CoproductWireContract, StringVariant, SnakeCase, ScreamingSnakeCase } -// -- Enumerations: GitHub-spec closed vocabularies -------------------- -// Spec: https://docs.github.com/en/rest/pulls/pulls#list-pull-requests -// Wire: "open" | "closed" (lowercase, SnakeCase) type PullRequestState = Open | Closed data pull_request_state_wire_contract: CoproductWireContract = { coproduct: "PullRequestState", encoding: StringVariant { naming: SnakeCase } } -// Spec: https://docs.github.com/en/rest/pulls/reviews -// Wire: "PENDING" | "COMMENTED" | "APPROVED" | "CHANGES_REQUESTED" | "DISMISSED" type ReviewState = Pending | Commented | Approved | ChangesRequested | Dismissed data review_state_wire_contract: CoproductWireContract = { coproduct: "ReviewState", encoding: StringVariant { naming: ScreamingSnakeCase } } -// Spec: https://docs.github.com/en/rest/pulls/reviews#create-a-review-for-a-pull-request -// Wire: "APPROVE" | "REQUEST_CHANGES" | "COMMENT" | "PENDING" type ReviewEvent = Approve | RequestChanges | Comment | Pending data review_event_wire_contract: CoproductWireContract = { coproduct: "ReviewEvent", encoding: StringVariant { naming: ScreamingSnakeCase } } -// -- Pull request model ----------------------------------------------- - type PullRequestRef { ref: GitRef sha: CommitSha @@ -76,22 +52,14 @@ type IssueComment { created_at: Timestamp } -// -- Service: REST transport wiring ----------------------------------- -// -// 🟡 dissolved — feature:github-pulls-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); the published corpus (extdeps.github.mock_corpus) now governs WHICH -// github.Pulls ops are hermetically realizable, and the fixture store owns the payloads (§3). -// forbidden: reintroducing mock_response constants for Hermetic dispatch on these shapes. - service github.Pulls { config { endpoint: default_api_base auth: Bearer auth_source: EnvVar { name: "GITHUB_TOKEN" } - // GitHub API rate limits: 5000 requests/hour for authenticated users + rate_limit: { requests: 5000, per: hour, scope: core } - // Retry on rate limit and server errors with exponential backoff + retry: { max_attempts: 3, backoff: exponential, retry_on: [429, 500, 502, 503, 504] } } @@ -195,9 +163,6 @@ service github.Pulls { } } - // Spec: https://docs.github.com/en/rest/pulls/reviews - // Stateless dedup: check if a review exists at a specific commit SHA. - // Returns review count -- 0 means not yet reviewed at this commit. operation ListReviews { input { auth_token: Secret @@ -221,9 +186,6 @@ service github.Pulls { } } - // Spec: https://docs.github.com/en/rest/pulls/reviews#create-a-review - // Posts a review with line-level comments. Idempotent when guarded - // by ListReviews check (don't post if review at this SHA exists). operation CreateReview { input { auth_token: Secret @@ -252,8 +214,6 @@ service github.Pulls { } } - // Spec: https://docs.github.com/en/rest/pulls/comments - // Lists review comments (line-level). Used for resolution checking. operation ListComments { input { auth_token: Secret @@ -278,8 +238,6 @@ service github.Pulls { } } -// -- Review and comment types ----------------------------------------- - type PullReview { id: Int body: String diff --git a/dsl/extdeps/gunbc/gunbc.dag b/dsl/extdeps/gunbc/gunbc.dag index 1d8a4c41c42..8dfad3ae43e 100644 --- a/dsl/extdeps/gunbc/gunbc.dag +++ b/dsl/extdeps/gunbc/gunbc.dag @@ -1,21 +1,5 @@ -// extdeps/gunbc/gunbc.dag -- "What is gunbc?" -// -// Meta model of this repo's workspace structure. Technically an -// internal system, but modeled as an extdep because: -// 1. The crate graph is a stable fact (changes rarely) -// 2. Multiple tools derive from it (clippy policy, codegen, testgen) -// 3. Treating it uniformly with external deps simplifies composition -// -// Consumers: -// config/arch_rules.dag -- exemption scopes reference packages -// config/clippy_policy.dag -- crate policies reference roles -// tools/codegen.dag -- codegen shell operations - module extdeps.gunbc -// -- Package roles --------------------------------------------------- -// How a crate participates in the architecture. - type CrateRole = TransportBoundary | Compiler @@ -25,9 +9,6 @@ type CrateRole | Library | Tool -// -- Package declarations -------------------------------------------- -// Each package states its role and whether it's an I/O boundary. - type WorkspacePackage { name: String role: CrateRole @@ -36,19 +17,17 @@ type WorkspacePackage { } data packages: List = [ - // Transport layer -- the designated I/O boundary + { name: "gunbc-lib-transport", role: TransportBoundary, description: "Designated I/O boundary: all filesystem, network, process I/O flows through here", io_boundary: true }, - // Execution engine { name: "gunbc-exec", role: Runtime, description: "DAG execution engine with freshness checking and CI display", io_boundary: false }, - // IR and infrastructure { name: "gunbc-ir", role: Infra, description: "Intermediate representation types, workspace layout, transport credential", @@ -58,13 +37,11 @@ data packages: List = [ description: "Leaf infrastructure: ResourceId, ContentHash, hash, manifest, freshness", io_boundary: false }, - // Codegen and tool registry { name: "gunbc-codegen", role: CodegenBootstrap, description: "Code generation from IR to Rust/Go/C/MIPS targets", io_boundary: false }, - // Compiler pipeline { name: "daglang-syntax", role: Compiler, description: "DSL lexer and parser", @@ -94,7 +71,6 @@ data packages: List = [ description: "CLI frontend for the DSL compiler", io_boundary: false }, - // Main DAG crate { name: "gunbc-app", role: CodegenBootstrap, description: "Workspace DAG: tool graphs, extern impls, policy, registry", @@ -102,14 +78,12 @@ data packages: List = [ ] -// -- Service: codegen shell operations --------------------------- - service shell.Codegen { operation Check { input {} output { needed: Bool from "exit_success" } readonly - // Checks if codegen output files exist / are stale + transport shell { argv: ["test", "-f", "target/codegen/.stamp"] } exit { 0 => Unit "File exists" diff --git a/dsl/extdeps/hardware.dag b/dsl/extdeps/hardware.dag index 68b21d2ae5c..1d9f3c92ce9 100644 --- a/dsl/extdeps/hardware.dag +++ b/dsl/extdeps/hardware.dag @@ -1,13 +1,3 @@ -// extdeps/hardware.dag — the electronic-hardware domain marker. -// -// "Hardware" here is electronic hardware: the physical devices/components a system -// is built from (CPUs, GPUs, DRAM, …) — the real-world domain that the per-vendor -// catalogs under extdeps/{cpu,memory}/ and product/compute_fabric model. It is a -// domain TAG, not a universal framework, so it lives downstream of std (extdeps), -// not in std. It is the type argument that specializes the generic Vendor concept: -// a hardware maker is a `Vendor` (extdeps/vendor.dag). -// Anchor: https://en.wikipedia.org/wiki/Electronic_hardware - module extdeps.hardware import extdeps.external_authority { ExternalAuthority } @@ -20,8 +10,4 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// Phantom domain marker (no inhabitants of its own — same deferral shape as -// std.ReferenceModel / the Measure phantom scales). It exists only to specialize -// `Vendor`; a richer hardware taxonomy decomposes here when a consumer needs -// to dispatch on it (DESIGN §6 model just-in-time). type Hardware diff --git a/dsl/extdeps/http/server.dag b/dsl/extdeps/http/server.dag index 2a02ea79667..418f5fa1752 100644 --- a/dsl/extdeps/http/server.dag +++ b/dsl/extdeps/http/server.dag @@ -1,30 +1,8 @@ -// extdeps/http/server.dag -- HTTP server emission target surface. -// -// Specs: -// RFC 9110 HTTP Semantics -// https://www.rfc-editor.org/rfc/rfc9110 -// RFC 3986 URI generic syntax -// https://www.rfc-editor.org/rfc/rfc3986 -// OpenAPI 3.1 path templating convention -// https://spec.openapis.org/oas/v3.1.0 -// Node.js http module (gunbhub-A serve/listen/respond effect chain) -// https://nodejs.org/api/http.html#httpcreateserveroptions-requestlistener -// https://nodejs.org/api/http.html#serverlisten -// https://nodejs.org/api/http.html#responseenddata-encoding-callback -// -// Ctrl-Migration Phase 3 authority for generated HTTP server surfaces. -// This file models the emitted server artifact shape, not a runtime framework -// and not a concrete ctrl subsystem. Subsystem projections consume this target -// only after their staged model has parity coverage. - module extdeps.http.server import std.http_path { PathTemplate } import std.types { HttpMethod, HttpStatus, Port } -// Coproduct dissolution classification (DESIGN.md §2 decompress->map->reduce): -// 🟢 GREEN (terminal). Static-route content types are a closed MIME surface for -// the gunbhub serve host; wire labels are the RFC 9110 media-type strings. type HttpContentType = TextHtmlUtf8 | TextPlainUtf8 @@ -40,10 +18,6 @@ fn http_content_type_wire_label(content_type: HttpContentType) -> String { } } -// Coproduct dissolution classification (DESIGN.md §2 decompress->map->reduce): -// GREEN (terminal). These are distinct HTTP request-body media families -// with externally specified wire behavior. A variant payload would erase the -// parser/serializer selection carried by the media type itself. type HttpRequestBodyKind = NoRequestBody | JsonRequestBody @@ -51,10 +25,6 @@ type HttpRequestBodyKind | BinaryRequestBody | FormRequestBody -// Coproduct dissolution classification (DESIGN.md §2 decompress->map->reduce): -// GREEN (terminal). Route parameters are externally visible in different -// request locations; server emitters must bind them from different request -// components, so the variants are not aliases for one unstructured map. type HttpInputLocation = PathInput | QueryInput @@ -72,7 +42,6 @@ type HttpStatusResponse { body_kind: HttpRequestBodyKind } -// Framework-agnostic route metadata + declared response contract. type HttpServerRoute { operation_name: String method: HttpMethod @@ -82,15 +51,11 @@ type HttpServerRoute { responses: List } -// STAGED. This is the Phase 3 emission target contract a ctrl subsystem -// projection will consume. It intentionally carries no framework, port, or -// deployment policy; those are subsystem/runtime decisions, not HTTP facts. type HttpServerEmissionTarget { service_name: String routes: List } -// Node requestListener emission symbol (nodejs.org/api/http.html#createServer). type NodeHttpRequestListener { handler_name: String } @@ -100,35 +65,25 @@ type HttpServerListenConfig { port: Port } -// Per-route Node projection: route metadata + requestListener + respond contract. -// Respond (ServerResponse#end) is per-binding callback work inside the listener, -// not a server-level step parallel to createServer/listen. type NodeHttpServerRouteBinding { route: HttpServerRoute listener: NodeHttpRequestListener } -// http.createServer(requestListener) — registers route→listener dispatch. type NodeHttpCreateServerServe { route_bindings: List } -// Fixed Node server effect chain: createServer (serve) then listen. -// Field shape enforces ordering; not a free phase list. type NodeHttpCreateServerEffectChain { serve: NodeHttpCreateServerServe listen: HttpServerListenConfig } -// STAGED. Node http.createServer emission target for gunbhub web surfaces. type NodeHttpCreateServerEmissionTarget { service_name: String effects: NodeHttpCreateServerEffectChain } -// Host contract (gunbhub-M2 consumer → quick-crane host): pre-rendered static -// routes. Bodies are verbatim serialize output; host MUST NOT re-encode/escape. -// Miss → host 404; consumer supplies no body for misses. type ServedStaticRoute { method: HttpMethod path_pattern: PathTemplate diff --git a/dsl/extdeps/languages/bash/program.dag b/dsl/extdeps/languages/bash/program.dag index 4318f8a977b..9ada63a2564 100644 --- a/dsl/extdeps/languages/bash/program.dag +++ b/dsl/extdeps/languages/bash/program.dag @@ -1,90 +1,38 @@ -// extdeps/languages/bash/program.dag — structured shell-program model + byte-faithful serializer. -// -// ⚠️ DISSOLUTION-BOUND — DO NOT BUILD NEW TRANSPORTS ON THIS. This module is a SIDECAR EMITTER: -// a hand-rolled per-language bash serializer (`serialize_bash`, self-declared "Peer of -// serialize_yaml") running PARALLEL to the compiler's row-driven emit (§4: emit = -// serialize_target ∘ translate — one grammar read backward). That parallel emitter IS the cruft. -// It is being DISSOLVED: bash becomes the 19th v2 TARGET LANGUAGE — a TargetModel of translation -// rows under `src/v2/extdeps/languages/bash.dag` — so a transport authors INTENT and -// `emit(intent, Bash)` renders shell the same row-driven way `emit(intent, Rust)` already does. -// `serialize_bash` + this whole AST DELETE once the consumers below migrate. Authoring new -// transports against ShellProgram/serialize_bash/Raw deepens the fork — model the OPERATION and -// emit instead. (The once-mooted `shell.Exec.Run.script` String→ShellProgram type-flip is -// CANCELLED — it would sanction this sidecar.) Tracking: warm-badger-46 shell(intent()) arc. -// -// Until that migration completes it stays load-bearing for the live consumers below. -// -// Spec: POSIX.1-2017 Shell Command Language §2.2 (Quoting), §2.9 (Lists / Compound Commands) -// https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html -// -// v2-clean (no std.render / std.unicode imports) so witnesses execute under the v1 interpreter. -// -// Consumers (ALL migrate off, then this module deletes): -// test.claim.bash_serializer_witness_test, tools/host_prelude, tools/dsl_compile_clean_transport, -// tools/layering_imports_transport, tools/emit_host_transport, -// gunbc/ci_yaml_validate - module extdeps.languages.bash.program -// ========================================================================= -// Words — the atoms of a simple command. -// -// `Lit` MUST be single-quoted so the shell does not expand metacharacters inside it -// (POSIX §2.2.2: single quotes preserve every character literally). `VarRef` is a -// double-quoted parameter expansion. `Concat` glues adjacent words with no separator -// (the structural form of `"$ROOT"/path` interpolation). `CmdSubst` is `$( stmt )`. -// `Raw` is the escape hatch for an already-correct fragment with no structural model. -// ========================================================================= - type ShellWord = Lit { text: String } | VarRef { name: String } | Concat { parts: List } | CmdSubst { body: ShellStmt } - // 🟡 escape hatch — dissolves WITH this whole module into the v2 bash TargetModel (rows, - // src/v2/extdeps/languages/bash.dag, slice 1 in PR #5155). The transport-script-position - // enforcement (lens / `shell.Exec.Run.script` String→ShellProgram flip) then makes a `Raw` - // in transport position a typecheck/lens error. No caller uses Raw; do not add one. - | Raw { text: String } -// ========================================================================= -// Statements + lists. -// -// A test (`[ ... ]`, `test -x …`) is NOT a separate kind — POSIX §2.9.1: the `if` -// condition is a command list whose exit status is consulted, and `[`/`test` are -// ordinary commands. So `If.cond` is a `ShellStmt` and a bracket test is a `Command` -// (see `test_not_executable`), one concept not two (§2). -// ========================================================================= + | Raw { text: String } type AndOrOp - = AndThen // && - | OrElse // || + = AndThen + | OrElse type Redir - = StderrToNull // 2>/dev/null - | StdoutAndStderrToNull // >/dev/null 2>&1 - | StdoutToStderr // >&2 + = StderrToNull + | StdoutAndStderrToNull + | StdoutToStderr type ShellStmt = Command { words: List } | Assign { name: String, value: ShellWord } | If { cond: ShellStmt, then: List } | Subshell { body: List } - // Brace-group — `{ stmt; }` in the current shell (idiomatic precedence wrap for compound - // operands of `|`; distinct from Subshell which forks). Dissolves into v2 bash TargetModel rows. + | BraceGroup { body: List } | AndOr { left: ShellStmt, op: AndOrOp, right: ShellStmt } - | Pipe { left: ShellStmt, right: ShellStmt } // left | right - // NAME=value — a single environment assignment scoped to one command (POSIX §2.9.1). + | Pipe { left: ShellStmt, right: ShellStmt } + | EnvPrefixed { name: String, value: ShellWord, command: ShellStmt } | WithRedir { stmt: ShellStmt, redir: Redir } - // Heredoc: `cat > <<''\n\n`. The body is literal - // file content (a fixture / a .dag source), not shell control flow — a String payload, - // not smuggled policy. Always a quoted delimiter (no expansion in the body). + | Heredoc { path: ShellWord, delimiter: String, body: String } | Exit { code: Int } - // 🟡 escape hatch — dissolves WITH this whole module into the v2 bash TargetModel (rows); - // same trigger as ShellWord.Raw (transport-script-position typecheck/lens ban). + | RawLine { text: String } type ShellProgram { @@ -92,8 +40,6 @@ type ShellProgram { statements: List } -// -- constructors ----------------------------------------------------- - fn lit(text: String) -> ShellWord { Lit { text: text } } @@ -110,22 +56,14 @@ fn assign(name: String, value: ShellWord) -> ShellStmt { Assign { name: name, value: value } } -// `[ ! -x ]` — bracket test as the ordinary command it is. fn test_not_executable(path: ShellWord) -> ShellStmt { Command { words: [lit(text: "["), lit(text: "!"), lit(text: "-x"), path, lit(text: "]")] } } -// -- quoting ---------------------------------------------------------- - -// POSIX §2.2.2: inside single quotes every character is literal and a single quote -// cannot appear, so an embedded `'` is rendered as the canonical `'\''` (close, escaped -// quote, reopen). This is the total, always-safe quoting of an arbitrary literal. fn single_quote(s: String) -> String { concat("'", concat(replace(s, "'", "'\\''"), "'")) } -// -- serialization (mirror of serialize_yaml's per-node helpers + one top fold) ---- - fn serialize_word(w: ShellWord) -> String { match w { Lit { text: t } => single_quote(s: t) @@ -158,7 +96,6 @@ fn serialize_and_or_op(op: AndOrOp) -> String { } } -// then-body / subshell-body: statements joined by `; ` (single-line compound command). fn join_stmts_semi(stmts: List) -> String { fold(stmts, init: "", f: (acc, s) => { let part = serialize_stmt(s: s) @@ -192,7 +129,6 @@ fn serialize_stmt(s: ShellStmt) -> String { } } -// Total serializer: ShellProgram → POSIX shell text (trailing newline at EOF). fn serialize_bash(p: ShellProgram) -> String { let body = fold(p.statements, init: "", f: (acc, s) => concat(acc, concat(serialize_stmt(s: s), "\n"))) diff --git a/dsl/extdeps/languages/dag/emit.dag b/dsl/extdeps/languages/dag/emit.dag index 7143a3f4538..8312ef81dc9 100644 --- a/dsl/extdeps/languages/dag/emit.dag +++ b/dsl/extdeps/languages/dag/emit.dag @@ -1,23 +1,11 @@ -// extdeps/languages/dag/emit.dag -- .dag language facts for the v2 emitter. -// -// The .dag target is used for debug output and pretty-printing. -// This file provides Dag-specific data so that language_spec_for_target(Dag) -// returns a proper dag_spec() instead of falling back to rust_spec(). -// -// Consumers: -// v2/languages.dag -- dag_spec() constructor - module extdeps.languages.dag.emit -// -- Keyword/operator translation ---------------------------------------- data dag_keywords: Map = { "true": "true", "false": "false", "null": "none", "and": "&&", "or": "||", "not": "!", "div": "/" } -// -- Container type templates -------------------------------------------- -// .dag containers use their natural names. data dag_container_templates: Map = { "list": "List<\{0\}>", "set": "Set<\{0\}>", "non_empty_list": "NonEmptyList<\{0\}>", "non_empty_set": "NonEmptySet<\{0\}>", @@ -26,13 +14,10 @@ data dag_container_templates: Map = { "boolean_algebra": "Bool" } -// -- Reserved words (empty — .dag handles keywords via keyword_set) ------ data dag_reserved: List = [] -// -- String-like types --------------------------------------------------- data dag_string_types: List = ["String", "Secret"] -// -- Item definition facts ----------------------------------------------- data dag_func_keyword: String = "fn" data dag_async_prefix: String = "" data dag_struct_keyword: String = "type" @@ -45,7 +30,6 @@ data dag_module_keyword: String = "module" data dag_import_keyword: String = "import" data dag_import_from_keyword: String = "" -// -- Expression syntax templates ------------------------------------------ data dag_lambda_template: String = "({0}) => {1}" data dag_error_expr_template: String = "error({0})" data dag_list_literal_empty: String = "[]" @@ -60,5 +44,4 @@ data dag_tuple_pair_template: String = "({0}, {1})" data dag_tuple_multi_template: String = "({0})" data dag_tuple_separator: String = ", " -// -- Project scaffold ---------------------------------------------------- data dag_source_extension: String = ".dag" diff --git a/dsl/extdeps/languages/dag/syntax.dag b/dsl/extdeps/languages/dag/syntax.dag index 80e969d84e2..9aa08288227 100644 --- a/dsl/extdeps/languages/dag/syntax.dag +++ b/dsl/extdeps/languages/dag/syntax.dag @@ -1,9 +1,3 @@ -// .dag syntax specification — instance #1 of SyntaxSpec. -// -// This file declares the grammar of the .dag language as data. -// The parser reads this spec; adding a new item type = one entry here. -// Future language frontends (Python, Go source) provide their own SyntaxSpec. - module extdeps.languages.dag.syntax import std.syntax { @@ -17,11 +11,6 @@ import std.syntax { LiteralValue, LitBool, LitNull } -// Item forms: keyword -> structural components + body kind. -// The parser dispatches on keyword text, looks up the form, -// then parses the shared prefix (name, type params, params, return, uses) -// and delegates to the appropriate body parser. - data dag_item_forms: List = [ ItemForm { kind: TypeAliasForm, keyword: "type", has_type_params: true, has_params: false, has_return_type: false, return_required: false, @@ -49,9 +38,6 @@ data dag_item_forms: List = [ has_uses: false, body_kind: BlockBody } ] -// Literal keywords: keyword text -> LiteralValue. -// The parser checks this map before expression keywords. - data dag_keyword_literals: Map = { "true": LitBool { value: true }, "false": LitBool { value: false }, @@ -59,10 +45,6 @@ data dag_keyword_literals: Map = { "null": LitNull } -// Keyword lookup map — the single authority for what strings are keywords. -// Map used as a set: O(1) lookup per identifier token. -// The tokenizer and parser both derive from this map. - data dag_keyword_set: Map = { "module": true, "import": true, "type": true, "fn": true, "func": true, "resource": true, "service": true, "data": true, @@ -75,29 +57,11 @@ data dag_keyword_set: Map = { "idempotent": true, "readonly": true, "hermetic": true } -// Keywords that cannot be used as identifiers (field names, type names). -// Includes literal keywords (true/false/none/null) and resource lifecycle -// keywords (acquire/release). The parser derives from this set — no local -// enumeration needed in 02_parse.dag. -// -// `inhabits` is intentionally **not** in `dag_keyword_set`: it must tokenize as -// an ordinary identifier so it can spell a declared type name, a sum variant, -// or a record field without a dedicated keyword token. The v3 compiler -// recognizes `type inhabits = ...` structurally (token order), -// not via global keyword reservation (see `parse_parser_body.txt`). - data dag_non_name_keywords: Map = { "true": true, "false": true, "none": true, "null": true, "acquire": true, "release": true } -// External .dag operator precedence authority. -// This table models external .dag syntax reality, not the current v3-supported -// tokenizer/parser/operator subset. -// || < && < ?? < cmp < add < mul < |> < . -// |> and . have binding power entries but their binop field is unused -// (the expression loop handles them as pipe/field-access, not binary ops). - data dag_operators: List = [ OperatorSpec { symbol: "||", left_bp: 5, right_bp: 6, binop: Or, algebra_field: none }, OperatorSpec { symbol: "&&", left_bp: 7, right_bp: 8, binop: And, algebra_field: none }, @@ -117,13 +81,6 @@ data dag_operators: List = [ OperatorSpec { symbol: ".", left_bp: 19, right_bp: 20, binop: none, algebra_field: none } ] -// Current v3 capability projection. -// v3 tokenizer/parser/operator validation consumes these explicit supported -// symbols, then reads precedence/binop facts from `dag_operators`. This avoids -// duplicating operator semantics while still fencing current v3 capability. -// It intentionally excludes external `dag_operators` rows that v3 does not -// parse end-to-end yet, including `??` and `%`. - data v3_supported_dag_operators: Map = { "||": true, "&&": true, "==": true, "!=": true, "<": true, ">": true, "<=": true, ">=": true, diff --git a/dsl/extdeps/languages/dag/types.dag b/dsl/extdeps/languages/dag/types.dag index 52a3be7b0ab..099a13e91c2 100644 --- a/dsl/extdeps/languages/dag/types.dag +++ b/dsl/extdeps/languages/dag/types.dag @@ -1,18 +1,7 @@ -// extdeps/languages/dag/types.dag -- Dag target coercion data. -// -// The Dag target is used for debug output and pretty-printing. -// TypeCheckpoints here ensure the emitter's fail-closed path stays -// intact: literal_suffix returns Some("") for Dag rather than None, -// so a missing checkpoint on a real target still emits an error. -// -// SCHEMA: Type definitions live in std/coercion.dag (shared authority). - module extdeps.languages.dag.types import std.coercion { TypeCheckpoint } -// Dag type checkpoints: identity mapping (dag_name == target_type). -// literal_suffix is none for all entries — Dag doesn't add suffixes. data dag_type_checkpoints: List = [ { dag_name: "Int", target_type: "Int", default_expr: "0", is_copy: none, literal_suffix: none }, { dag_name: "Float", target_type: "Float", default_expr: "0.0", is_copy: none, literal_suffix: none }, diff --git a/dsl/extdeps/languages/go/emit.dag b/dsl/extdeps/languages/go/emit.dag index 2f18ac0e4a4..f31ed2d4844 100644 --- a/dsl/extdeps/languages/go/emit.dag +++ b/dsl/extdeps/languages/go/emit.dag @@ -1,31 +1,13 @@ -// extdeps/languages/go/emit.dag -- Go language facts for the v2 emitter. -// -// Single source of truth for Go-specific data consumed by the emitter. -// Imports only the shared SimpleMethodSpec carrier from std; the rest are -// leaf data declarations. -// -// Ref: The Go Programming Language Specification (go.dev/ref/spec) -// Go Standard Library (pkg.go.dev/std) -// -// Consumers: -// v2/05_emit.dag -- type mapping, keywords, container templates - module extdeps.languages.go.emit import std.emit_model { SimpleMethodSpec } -// -- Keyword/operator translation ---------------------------------------- -// DAG keywords/operators -> Go syntax. -// Ref: Go Spec, Operators and punctuation data go_keywords: Map = { "true": "true", "false": "false", "null": "nil", "and": "&&", "or": "||", "not": "!", "div": "/" } -// -- Container type templates -------------------------------------------- -// {0} = element type, {1} = second type (maps). -// Ref: Go Spec, Composite literals data go_container_templates: Map = { "list": "[]\{0\}", "set": "map[\{0\}]struct{}", "optional": "*\{0\}", "map": "map[\{0\}]\{1\}", @@ -33,8 +15,6 @@ data go_container_templates: Map = { "boolean_algebra": "bool" } -// -- Reserved words ------------------------------------------------------ -// Ref: Go Spec "Keywords" + predeclared identifiers data go_reserved: List = [ "break", "case", "chan", "const", "continue", "default", "defer", "else", "fallthrough", "for", @@ -50,14 +30,8 @@ data go_reserved: List = [ "real", "recover" ] -// -- Reserved word escape ------------------------------------------------ -// Ref: Go Spec -- Go uses no raw identifier escape; underscore suffix by convention. -// Mirrors go_reserved_words.strategy from std.languages (NoEscape, but -// the emitter appends "_" for keywords that clash with identifiers). data go_reserved_escape_suffix: String = "_" -// -- Item definition facts ------------------------------------------------ -// Ref: Go Specification "Declarations and scope" data go_func_keyword: String = "func" data go_async_prefix: String = "" data go_struct_keyword: String = "struct" @@ -70,27 +44,11 @@ data go_module_keyword: String = "package" data go_import_keyword: String = "import" data go_import_from_keyword: String = "" -// -- Project scaffold ---------------------------------------------------- -// Ref: Go modules reference (go.dev/ref/mod) data go_manifest_file: String = "go.mod" data go_source_extension: String = ".go" -// -- String-like types ------------------------------------------------------ -// Types that use string comparison/indexing semantics in Go. data go_string_types: List = ["String", "Secret"] -// -- Method templates ------------------------------------------------------- -// Named-placeholder templates for algebra method calls. -// \{recv\} = pre-emitted receiver, \{arg\} = pre-emitted first argument. -// Ref: Go standard library + v2rt runtime helpers. -// -// Single authority: `go_simple_method_specs` carries the flat-templatable -// (unary `{recv}`/`{arg}`) methods the emitter renders by template. -// `map`/`fold`/`concat` are deliberately NOT here — they are binary+ -// (`fold(coll, init, f)` per dsl/std/algebra.dag) and route through the runtime -// bridge, which forwards every argument (a flat one-arg template would drop -// fold's accumulator/callback). `go_method_templates_flat()` derives the emit -// map from this list. Mirrors #5039's Rust slice. data go_simple_method_specs: List = [ { method_name: "count", template: "len(\{recv\})", wraps_result: false }, { method_name: "join", template: "strings.Join(\{recv\}, \{arg\})", wraps_result: false }, @@ -106,15 +64,11 @@ data go_simple_method_specs: List = [ { method_name: "append", template: "append(\{recv\}, \{arg\})", wraps_result: false } ] -// Derived: the flat templatable map the emitter reads (single authority above). -// `map`/`fold`/`concat` are absent → they route via the runtime bridge (correct -// argument forwarding). fn go_method_templates_flat() -> Map { go_simple_method_specs |> fold(init: empty_map(), f: (acc, spec) => map_insert(acc, spec.method_name, spec.template)) } -// -- Expression syntax templates ------------------------------------------ data go_lambda_template: String = "func({0}) interface\{\} \{ {1} \}" data go_error_expr_template: String = "panic({0})" data go_list_literal_empty: String = "[]interface\{\}\{\}" diff --git a/dsl/extdeps/languages/go/module.dag b/dsl/extdeps/languages/go/module.dag index 261e6adfcf3..fa61f4e3b94 100644 --- a/dsl/extdeps/languages/go/module.dag +++ b/dsl/extdeps/languages/go/module.dag @@ -1,30 +1,3 @@ -// extdeps/languages/go/module.dag — Go module system (go.mod, versioning, MVS). -// -// Anchor: https://go.dev/ref/mod -// -// Single authority for the Go module system types and versioning semantics. -// Upstream: Go Modules Reference (go.dev/ref/mod). -// -// DESIGN §3: this file is the authority for: -// - GoSemVer (decomposed v-prefixed semver atoms), go_semver_label -// - go_semver_to_version_identity (projector GoSemVer → VersionIdentity) -// - go_semver_compare (structural compare over GoSemVer atoms) -// - go_module_version_scheme: VersionScheme (scheme data row; compare scaffold -// pending string-parse builtin — dissolve-on: parse_go_semver lands) -// - GoModulePath, GoMajorVersionSuffix, go_major_suffix_str -// - GoLanguageVersion, GoToolchainName -// - GoRequireEntry, GoReplaceEntry, GoExcludeEntry, GoRetractEntry -// - GoModFile (go.mod structure) -// - go_mvs_properties (algorithm properties, not a runnable function) -// -// go.mod filename authority: extdeps.languages.go.emit.go_manifest_file -// (v1-seed scaffold, load-bearing in src/v1/languages.dag; this module does -// NOT re-declare it — dissolve-on: emit.dag imports go_manifest_file from -// module.dag when module.dag becomes the v1-bootstrap-read authority). -// -// Consumers: -// dsl/test/claim/go_module_versioning_witness_test.dag — by-execution witnesses - module extdeps.languages.go.module import std.types { NonEmptyStr } @@ -41,28 +14,14 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// ── Module version ─────────────────────────────────────────────────────────── -// go.dev/ref/mod#versions -// -// A module version is a v-prefixed semver tag. Decomposed to grounded atoms -// (major/minor/patch Int + optional prerelease/build) per DESIGN.md §2. -// Examples: v1.2.3, v0.1.0-alpha.1, v2.0.0-rc.1 -// -// Pseudo-versions (go.dev/ref/mod#pseudo-versions) are a PREDICATE on this -// structure — the prerelease field matches the yyyymmddhhmmss-abcdefabcdef -// pattern — not a separate type fork. type GoSemVer { major: Int minor: Int patch: Int - prerelease: String? // e.g. "alpha.1", "rc.2", pseudo-version timestamp-hash - build: String? // e.g. "build.1" — informational, ignored in version ordering + prerelease: String? + build: String? } -// Canonical wire label for a GoSemVer (go.dev/ref/mod#versions). -// MajorV0OrV1 example: v1.2.3 → "v1.2.3" -// Pre-release example: v0.1.0-alpha.1 → "v0.1.0-alpha.1" -// Build meta example: v1.0.0+build.1 → "v1.0.0+build.1" fn go_semver_label(v: GoSemVer) -> String { let base = concat("v", concat(to_string(v.major), concat(".", concat(to_string(v.minor), concat(".", to_string(v.patch)))))) let with_pre = match v.prerelease { @@ -75,18 +34,10 @@ fn go_semver_label(v: GoSemVer) -> String { } } -// Projects a GoSemVer to the opaque VersionIdentity surface (extdeps.version). -// The v-prefixed label is the canonical wire form (go.dev/ref/mod#versions). fn go_semver_to_version_identity(v: GoSemVer) -> VersionIdentity { go_semver_label(v: v) } -// Structural comparison of two GoSemVer values (go.dev/ref/mod#versions). -// Order: major → minor → patch (Int); prerelease presence: -// no-prerelease > same-version-with-prerelease (semver.org §11). -// Prerelease STRING ordering: not implemented — no string compare in the -// substrate; equal-core versions with distinct prerelease labels resolve Equal. -// Scaffold: dissolve-on: parse_go_semver builtin lands (prerelease string ordering). fn go_semver_compare(a: GoSemVer, b: GoSemVer) -> Ordering { let mc = if a.major < b.major { Less } else { if a.major > b.major { Greater } else { Equal } } let nc = if a.minor < b.minor { Less } else { if a.minor > b.minor { Greater } else { Equal } } @@ -116,38 +67,16 @@ fn go_semver_compare(a: GoSemVer, b: GoSemVer) -> Ordering { } } -// VersionScheme row for Go module versioning (extdeps.version.VersionScheme). -// compare equality case is correct; ordering is a scaffold — VersionIdentity -// strings cannot be parsed back to GoSemVer atoms without a builtin. -// Scaffold: dissolve-on: parse_go_semver lands — replace compare body with: -// (a, b) => go_semver_compare(a: parse_go_semver(a), b: parse_go_semver(b)) data go_module_version_scheme: VersionScheme = { compare: (a, b) => if a == b { Equal } else { Less } } -// ── Module path ────────────────────────────────────────────────────────────── -// go.dev/ref/mod#module-path -// -// A module path identifies the module in the global namespace. It is -// URL-path-like (not a URL itself) and usually reflects the VCS root. -// Examples: "github.com/foo/bar", "github.com/foo/bar/v2", "golang.org/x/text" -// Major version v2+ MUST append a /vN suffix -// (go.dev/ref/mod#major-version-suffixes). -// -// Scaffold: `where pattern(...)` pending Q-Regex. type GoModulePath = NonEmptyStr where brand("GoModulePath") -// Major version suffix encoding (go.dev/ref/mod#major-version-suffixes). -// v0 and v1 have NO /vN suffix in the module path; v2+ must append /vN. -// Single authority for this rule — do not re-state in emit.dag or workflow. type GoMajorVersionSuffix - = MajorV0OrV1 // no suffix: v0 and v1 are suffix-free (go.dev/ref/mod#major-version-suffixes) - | MajorV2Plus { major: Int where range(min: 2) } // path must end in /v2, /v3, …; major MUST be ≥ 2 + = MajorV0OrV1 + | MajorV2Plus { major: Int where range(min: 2) } -// Renders the /vN suffix string for a given major version suffix. -// MajorV0OrV1 → "" (no suffix appended to module path) -// MajorV2Plus { major: 3 } → "/v3" -// Ref: go.dev/ref/mod#major-version-suffixes fn go_major_suffix_str(suffix: GoMajorVersionSuffix) -> String { match suffix { MajorV0OrV1 => "" @@ -155,90 +84,40 @@ fn go_major_suffix_str(suffix: GoMajorVersionSuffix) -> String { } } -// ── Go language version (go directive) ────────────────────────────────────── -// go.dev/ref/mod#go-mod-file-go -// -// The `go` directive specifies the minimum Go version required by the module. -// Format: MAJOR.MINOR (e.g., "1.21") or MAJOR.MINOR.PATCH (e.g., "1.21.0"). -// Since Go 1.21 this also selects language semantics and the default toolchain. -// -// Scaffold: `where pattern("^\\d+\\.\\d+(\\.\\d+)?$")` pending Q-Regex. type GoLanguageVersion = NonEmptyStr where brand("GoLanguageVersion") -// ── Toolchain name (toolchain directive) ───────────────────────────────────── -// go.dev/ref/mod#go-mod-file-toolchain (introduced Go 1.21) -// -// Names a specific Go toolchain distribution. Format: goVERSION (e.g., "go1.21.0"). -// Absent in modules predating Go 1.21 toolchain switching. -// -// Scaffold: `where pattern("^go\\d+\\.\\d+")` pending Q-Regex. type GoToolchainName = NonEmptyStr where brand("GoToolchainName") -// ── require directive ──────────────────────────────────────────────────────── -// go.dev/ref/mod#go-mod-file-require -// -// Each `require` entry declares a direct or indirect module dependency. -// `indirect: true` for modules not directly imported by this module -// (transitive dependencies pinned for reproducible builds via MVS). type GoRequireEntry { module_path: GoModulePath version: GoSemVer indirect: Bool } -// ── replace directive ──────────────────────────────────────────────────────── -// go.dev/ref/mod#go-mod-file-replace -// -// The replace RHS is one of two structurally distinct shapes -// (go.dev/ref/mod#go-mod-file-replace): -// ModuleRedirect — another module path + required version -// LocalDirRedirect — a relative filesystem path (must start with ./ or ../) -// which MUST NOT have a version -// -// Collapsing these into `target_path: GoModulePath + target_version: GoSemVer?` -// is a §2/§3 violation (illegal states representable, two upstream shapes merged). type GoReplaceTarget = ModuleRedirect { path: GoModulePath, version: GoSemVer } | LocalDirRedirect { path: NonEmptyStr } -// `source_version: absent` replaces all versions of the source module. type GoReplaceEntry { source_path: GoModulePath source_version: GoSemVer? target: GoReplaceTarget } -// ── exclude directive ──────────────────────────────────────────────────────── -// go.dev/ref/mod#go-mod-file-exclude -// -// Excludes a specific version of a module from the build graph. -// Only applies in the main module's go.mod (ignored in dependencies). type GoExcludeEntry { module_path: GoModulePath version: GoSemVer } -// ── retract directive ──────────────────────────────────────────────────────── -// go.dev/ref/mod#go-mod-file-retract (Go 1.16+) -// -// Marks a version or version range as retracted — not recommended for use. -// Single-version: retract v1.2.3 -// Range: retract [v1.2.0, v1.2.5] (both bounds inclusive) type GoRetractRange = RetractSingle { version: GoSemVer } | RetractRange { low: GoSemVer, high: GoSemVer } type GoRetractEntry { range: GoRetractRange - rationale: String? // comment preceding the directive in go.mod + rationale: String? } -// ── go.mod file ────────────────────────────────────────────────────────────── -// go.dev/ref/mod#go-mod-file -// -// Complete go.mod file structure. All directive lists may be empty. -// `toolchain` is optional; present only in modules that opt into Go 1.21+ -// toolchain switching. type GoModFile { module_path: GoModulePath go_version: GoLanguageVersion @@ -249,21 +128,10 @@ type GoModFile { retract: List } -// ── Minimum version selection algorithm properties ─────────────────────────── -// go.dev/ref/mod#minimal-version-selection -// -// MVS selects, for each module, the MINIMUM version satisfying all require -// directives in the module graph — never "latest", never a range resolver. -// Determinism comes from the graph structure; the go.sum file locks by content -// hash (go.dev/ref/mod#go-sum-files). replace and exclude directives only apply -// in the main module's go.mod (dependencies cannot override the graph via these). -// -// Modeled as closed enum facts about the algorithm — not a runnable procedure -// (MVS executes inside the Go toolchain, not here). type GoMvsProperty - = DeterministicMinimal // selects minimum required version; never above - | ContentHashLocked // go.sum locks by content hash (reproducible builds) - | MainModuleOnly // replace/exclude apply only in the main module go.mod + = DeterministicMinimal + | ContentHashLocked + | MainModuleOnly data go_mvs_properties: List = [ DeterministicMinimal, @@ -271,8 +139,5 @@ data go_mvs_properties: List = [ MainModuleOnly ] -// ── Emit-host toolchain floors ─────────────────────────────────────────────── -// tools/emit_host_transport.dag bootstraps go1.22.5 when `go` is missing on PATH. -// Minimum language version uses go-directive wire form ("1.22") — not ">= 1.22". data emit_host_min_go_language_version: GoLanguageVersion = "1.22" data emit_host_bootstrap_toolchain: GoToolchainName = "go1.22.5" diff --git a/dsl/extdeps/languages/go/primitives.dag b/dsl/extdeps/languages/go/primitives.dag index 56830a6530e..8ea4a1bad8d 100644 --- a/dsl/extdeps/languages/go/primitives.dag +++ b/dsl/extdeps/languages/go/primitives.dag @@ -1,80 +1,17 @@ -// extdeps/languages/go/primitives.dag — Structural target-primitive declarations -// for the Go target (T-Ground-Go / spec authority). -// -// FIRST SLICE (this file): Go spec predeclared types with fixed machine -// representations — booleans, fixed-width integers, floats, complex, string, -// and the byte/rune aliases (go.dev/ref/spec §Types, §Predeclared_identifiers). -// The empty struct type `struct{}` is **not** predeclared; it is the canonical -// **DAG Unit → Go target** realization (same authority edge as `go/types.dag`) -// and lives in a **separate** top-level row `go_dag_unit_target_primitive` below. -// Implementation-sized int, uint, and uintptr are intentionally omitted from the -// data table: their width / value set is implementation-defined (spec §Numeric -// types, https://go.dev/ref/spec#Numeric_types), so a fixed Word* carrier + -// numeric range would violate the same no-lying-about-width discipline as the -// Rust pilot’s u64 note — close under a GOARCH-tagged width story with DB-11 / -// cardinality substrate. -// -// TWO-AUTHORITY DISCIPLINE (ROADMAP §Post-R1 Grounding lanes): -// (a) THIS FILE — Go language specification (go.dev/ref/spec). -// (b) stdlib carriers and product-specific rows (e.g. []byte for Bytes, -// interface{} for Json) stay in go/types.dag + emit tables until a -// dedicated stdlib-authority slice lands; do not cite stdlib paths here. -// -// CONSUMER BOUNDARY: same Path-2 honest state as rust/primitives.dag — the -// top-level `go_spec_predeclared_primitives` list and `go_dag_unit_target_primitive` -// lower as ValueBody::Unparsed until R2 T-Substrate’s top-level aggregate sub-lane -// lands; type-structure (GoPrimitive = …) is walkable for Engine / future loaders. -// -// LESSON 5 (grounding-pilot-receipt.md): subset-only axes are structurally -// partitioned — integer overflow lives only on integer variants; float width -// only on GoFloatPrimitive; complex component width only on GoComplexPrimitive; -// alias linkage only on GoIntegerAliasPrimitive (byte/rune). -// -// STRING (spec §String types, https://go.dev/ref/spec#String_types): a string -// value is an immutable sequence of bytes (free monoid over bytes). UTF-8 is -// not a second carrier/algebra authority on the predeclared `string` row — it -// is source text / `[]rune` conversion and belongs in operator or stdlib -// slices, not parallel sum arms on `GoStringPrimitive`. -// -// SUBSTRATE-GAP FLAGS: Integer overflow / terminal / numeric carriers still use -// structural tag bridges (algebra.dag + bit.dag by tag), same honest-state -// pattern as rust/primitives.dag — but Go’s overflow enum is spec-only -// (`GoModularWrapOnFixedWidth`), not Rust’s three-way operator zoo. Post-DB-11 -// these become refinements on carriers / algebras. - module extdeps.languages.go.primitives -// --- Algebra tags (Go-prefixed names; avoid colliding with rust/primitives.dag -// in the shared bootstrap Dag). --- - type GoIntegerAlgebra = GoOrderedRingAlgebra | GoSemiringAlgebra -// Float width is a single authority on `GoFloatPrimitive` (`GoFloatWidth`). -// IEEE width fixes both the approximate-field algebra tag and the IEEE-754 -// bits carrier witness — do not duplicate width as independent algebra+carrier -// fields on the same row. -// -// **🟢 GREEN (terminal coproduct).** -// Ledger — both arms are spec-realized and consumed: `GoFloat32Width` / -// `GoFloat64Width` are the irreducible width distinction for Go’s two -// predeclared floating-point types (spec §Floating-point_types); each arm has a -// matching `GoFloatPrimitive` row in `go_spec_predeclared_primitives`. type GoFloatWidth = GoFloat32Width | GoFloat64Width -// Bool + empty struct share one closed algebra-tag sum (mirrors rust -// `NonIntegerAlgebra` grouping for non-integer scalars). String is separate — -// spec value domain is byte sequence (see header note). type GoSpecDiscreteAlgebra = GoCanonicalTwoElementBooleanAlgebra | GoTerminalAlgebra - -// --- Target carrier tags (value-domain witnesses; not ABI / GC shape). --- - type GoTargetCarrier = GoBitCarrier | GoByteCarrier @@ -83,43 +20,11 @@ type GoTargetCarrier | GoWord64Carrier | GoTerminalCarrier - -// Go spec §Integer overflow (https://go.dev/ref/spec#Integer_overflow): if an -// operation yields a value that cannot fit the result type's width, the result -// is truncated to fit — modular arithmetic on the fixed bit width. That is the -// sole built-in overflow fact for Go's fixed-width predeclared integers; it is -// not Rust's three-mode Saturating/Trap/debug-release matrix (those stay in -// rust/primitives.dag only). -// -// Closed sum (not a unary type alias): `GoModularWrapOnFixedWidth` is introduced -// here as a variant so structural loading / v2 bootstrap resolve the tag. -// -// Multi-arm sum (same structural rule as rust/primitives.dag `IntegerOverflow` and -// this file's float tags): a single-arm `type X = Tag` leaves `Tag` unresolved in -// the v2 bootstrap compiler — `GoModularWrapOnFixedWidth` must be introduced as a -// sum arm. Rows in this file use only `GoModularWrapOnFixedWidth`. The two additional -// arms are **parse scaffolding only** (never populated in this authority slice); -// future operator/substrate refinements get their own rows — not Rust `Saturating` -// / `Trap` names copied onto the Go spec surface. -// -// **🟢 GREEN** — `GoModularWrapOnFixedWidth` is the terminal ledger entry -// for Go spec §Integer_overflow on fixed-width predeclared numerics in this slice. -// **🟡 YELLOW (scaffold)** — `GoIntegerOverflowRefinementReservedA/B` exist only for -// the v2 “≥2 sum arms” tag-resolution constraint; named trigger: same-row engine -// consumption of overflow refinements, or bootstrap accepting single-arm sums. type GoIntegerOverflow = GoModularWrapOnFixedWidth | GoIntegerOverflowRefinementReservedA | GoIntegerOverflowRefinementReservedB - -// Spec-backed string value = immutable byte sequence (monoid + byte carrier). -// Second arms are v2 parse scaffolding only (never used in data) — same -// single-arm-resolution issue as `GoIntegerOverflow`; do **not** add a UTF-8 -// parallel authority here (header §STRING). -// -// **🟢 GREEN** — first arms are the terminal string-value witnesses. -// **🟡 YELLOW** — reserved arms; trigger: bootstrap / loader closes single-arm sums. type GoSpecStringAlgebraTag = GoImmutableByteSequenceMonoidAlgebra | GoSpecStringAlgebraParseReserved @@ -128,22 +33,16 @@ type GoSpecStringCarrierTag = GoImmutableByteSequenceCarrier | GoSpecStringCarrierParseReserved - type GoComplexComponentWidth = GoComplex64Components | GoComplex128Components - -// --- Sum-typed Go spec primitive (Lesson 5 partition). --- - type GoPrimitive = GoIntegerPrimitive { target_name: String algebra: GoIntegerAlgebra carrier: GoTargetCarrier - // scaffold: R2 top-level aggregate `ValueBody` sub-lane makes - // `go_spec_predeclared_primitives` rows structurally walkable; until then, - // consumers read the duplicated `GoIntegerRangeFact` rows below. + range_min_inclusive: String range_max_inclusive: String overflow: GoIntegerOverflow @@ -153,7 +52,7 @@ type GoPrimitive canon_name: String algebra: GoIntegerAlgebra carrier: GoTargetCarrier - // Same scaffold as `GoIntegerPrimitive` (see `GoIntegerRangeFact`). + range_min_inclusive: String range_max_inclusive: String overflow: GoIntegerOverflow @@ -182,8 +81,6 @@ type GoPrimitive carrier: GoTargetCarrier } - -// Structurally walkable integer range facts (mirrors rust IntegerRangeFact pattern). type GoIntegerRangeFact { target_name: String algebra: GoIntegerAlgebra @@ -256,10 +153,6 @@ data go_uint64_integer_range: GoIntegerRangeFact = { range_max_inclusive: "18446744073709551615" } - -// Predeclared fixed-width numerics + aliases + floats + complex + bool + string -// only (spec §Predeclared_identifiers / §Types). Order: signed ints, unsigned ints, -// aliases, floats, complex, bool, string. (int/uint/uintptr omitted — implementation width.) data go_spec_predeclared_primitives: List = [ GoIntegerPrimitive { target_name: "int8", algebra: GoOrderedRingAlgebra, carrier: GoByteCarrier, range_min_inclusive: "-128", range_max_inclusive: "127", overflow: GoModularWrapOnFixedWidth }, @@ -300,9 +193,6 @@ data go_spec_predeclared_primitives: List = [ carrier: GoImmutableByteSequenceCarrier } ] -// DAG Unit → Go: `struct{}` is the target spelling for DagName `Unit` in -// `go/types.dag`; it is not a predeclared identifier, so it must not share the -// `go_spec_predeclared_primitives` table with spec-predeclared types. data go_dag_unit_target_primitive: GoPrimitive = GoUnitPrimitive { target_name: "struct{}", algebra: GoTerminalAlgebra, diff --git a/dsl/extdeps/languages/go/syntax.dag b/dsl/extdeps/languages/go/syntax.dag index f8daed5f418..98006d0ef4b 100644 --- a/dsl/extdeps/languages/go/syntax.dag +++ b/dsl/extdeps/languages/go/syntax.dag @@ -1,11 +1,3 @@ -// Go syntax specification. -// -// Operator semantics for Go emission. The emitter reads operator -// symbols from this spec — no hardcoded Go syntax in the compiler. -// -// Ref: Go Specification "Operators" -// https://go.dev/ref/spec#Operators - module extdeps.languages.go.syntax import std.syntax { @@ -16,8 +8,6 @@ import std.syntax { Eq, Ne, Lt, Gt, Le, Ge, And, Or, NullCoalesce } -// Go emission item forms — target keywords for .dag→Go compilation. -// Ref: Go Specification "Declarations and scope" data go_item_forms: List = [ ItemForm { kind: FuncForm, keyword: "func", has_type_params: false, has_params: true, has_return_type: true, return_required: false, @@ -36,10 +26,6 @@ data go_item_forms: List = [ has_uses: false, body_kind: NoBody } ] -// Go operator precedence (emission-relevant subset). -// Go uses C-style operators: &&, ||, / for all division. -// Ref: Go Specification "Operator precedence" - data go_operators: List = [ OperatorSpec { symbol: "||", left_bp: 5, right_bp: 6, binop: Or, algebra_field: none }, OperatorSpec { symbol: "&&", left_bp: 7, right_bp: 8, binop: And, algebra_field: none }, diff --git a/dsl/extdeps/languages/go/types.dag b/dsl/extdeps/languages/go/types.dag index 1a01e0175fa..b824f1d4c85 100644 --- a/dsl/extdeps/languages/go/types.dag +++ b/dsl/extdeps/languages/go/types.dag @@ -1,37 +1,9 @@ -// extdeps/languages/go/types.dag -- Go coercion data. -// -// Declares which Go types inhabit which .dag algebraic structures. -// Go has garbage collection (like Python) but uses pointer types for -// optional values (like Rust uses Option). -// -// FAIL-CLOSED CONTRACT: Missing inhabitant = compile error. -// -// SCHEMA: Type definitions live in std/coercion.dag (shared authority). -// This file instantiates data only — no local type families. -// -// Ref: The Go Programming Language Specification (go.dev/ref/spec) -// Effective Go (go.dev/doc/effective_go) -// std/algebra.dag, std/coercion.dag -// -// Consumers: -// v2/05_emit_go.dag -- coercion engine reads inhabitants - module extdeps.languages.go.types import std.coercion { TypeCheckpoint, InhabitantDecl, CallableRepr, CastSyntax } - -// ========================================================================= -// Type checkpoints -// -// Go has value types (int64, bool, float64) and reference types (slices, -// maps, channels). is_copy is none — Go has no Copy trait; the value vs -// reference distinction is structural and handled by the emitter via -// ValueContext, not by a declared flag. -// ========================================================================= - data go_type_checkpoints: List = [ { dag_name: "Int", target_type: "int64", default_expr: "0", is_copy: none, literal_suffix: none }, { dag_name: "Float", target_type: "float64", default_expr: "0.0", is_copy: none, literal_suffix: none }, @@ -43,21 +15,8 @@ data go_type_checkpoints: List = [ { dag_name: "Json", target_type: "interface{}", default_expr: "nil", is_copy: none, literal_suffix: none } ] - -// ========================================================================= -// Algebra inhabitants -// -// CROSS-LANGUAGE COMPARISON: -// FreeMonoid → []T (Go) vs Vec (Rust) vs list[T] (Python) -// BooleanAlgebra → map[A]struct{} (Go) vs BTreeSet (Rust) vs set[A] (Python) -// PartialFunction→ map[K]V (Go) vs HashMap (Rust) vs dict[K,V] (Python) -// -// Go has no native set type. map[T]struct{} is idiomatic: isomorphic to -// A → Bool (the set-theoretic definition). -// ========================================================================= - data go_algebra_inhabitants: List = [ - // FreeMonoid → []T (Go slice) + { algebra: "FreeMonoid", template: "[]\{0\}", arity: 1, @@ -65,7 +24,6 @@ data go_algebra_inhabitants: List = [ import_path: none, is_copy: none }, - // BooleanAlgebra → map[A]struct{} { algebra: "BooleanAlgebra", template: "map[\{0\}]struct{}", arity: 1, @@ -73,7 +31,6 @@ data go_algebra_inhabitants: List = [ import_path: none, is_copy: none }, - // PartialFunction → map[K]V { algebra: "PartialFunction", template: "map[\{0\}]\{1\}", arity: 2, @@ -81,7 +38,6 @@ data go_algebra_inhabitants: List = [ import_path: none, is_copy: none }, - // OrderedRing → int64 { algebra: "OrderedRing", template: "int64", arity: 0, @@ -89,7 +45,6 @@ data go_algebra_inhabitants: List = [ import_path: none, is_copy: none }, - // ApproximateField → float64 { algebra: "ApproximateField", template: "float64", arity: 0, @@ -98,22 +53,6 @@ data go_algebra_inhabitants: List = [ is_copy: none } ] - -// ========================================================================= -// Optional: *T (pointer, nil = absent) -// -// Authority: pointer_template and nil_literal below. No separate optional -// declarations — Go optional IS pointer indirection. -// ========================================================================= - - -// ========================================================================= -// Callable: func(T) U -// -// Go functions are first-class. No owned/shared/static distinction — -// all callable types are `func`. Simpler than Rust's fn/Fn/FnMut/FnOnce. -// ========================================================================= - data go_callable: CallableRepr = CallableRepr { template: "func(\{params\}) \{return\}", param_separator: ", ", @@ -121,21 +60,6 @@ data go_callable: CallableRepr = CallableRepr { import_path: none } - -// ========================================================================= -// Sharing -// -// Go has GC but value semantics for structs. The value-vs-reference -// distinction (large structs → *T, slices/maps/channels → identity) is -// derived from ValueContext at emit time, not from a declared config. -// Emission is translation, not decision-making. -// ========================================================================= - - -// ========================================================================= -// Retained Go type system facts -// ========================================================================= - data pointer_template: String = "*\{0\}" data go_optional_template: String = "*\{0\}" data address_of_template: String = "&\{value\}" @@ -155,11 +79,6 @@ data float_types: List = ["float32", "float64"] data type_conversion_template: String = "\{type\}(\{expr\})" -// Cast syntax: Go uses type conversion T(x). fail_open=true models Go's -// actual semantics: type conversions are syntactically valid for compatible -// types. The Go compiler validates type compatibility at build time. -// Go type conversions: T(x). All numeric conversions valid. -// Ref: Go Specification "Conversions" data go_cast_syntax: CastSyntax = { template: "\{type\}(\{expr\})", cast_rules: [ diff --git a/dsl/extdeps/languages/markdown.dag b/dsl/extdeps/languages/markdown.dag index 1cfaf4519c3..9e0dcb2d4eb 100644 --- a/dsl/extdeps/languages/markdown.dag +++ b/dsl/extdeps/languages/markdown.dag @@ -1,31 +1,3 @@ -// extdeps/languages/markdown.dag — Markdown as an emit medium: a row-driven -// MarkdownDocument → markdown-SOURCE serializer. -// -// 🟡 SCAFFOLD — feature:markdown-source-medium; dissolve-on: the v2 06_translate Markdown -// TargetModel (src/v2/extdeps/languages/markdown.dag) lands and these spelling ROWS relocate -// into it as the grammar-inverse `target_model_edge_translation_rules` (they RELOCATE, no -// rework — same rows, table-driven). Until then this is the near-term v1-seed realization -// (the §6 displaced-cost path: the ROADMAP inverts BEFORE self-host, plan invert-hand-maintained -// §7), the byte-for-byte clone of the ci.yml pattern (serialize_yaml ∘ project_workflow_to_yaml). -// -// Peer of extdeps/formats/yaml.dag `serialize_yaml`: a byte-faithful structural-value -// serializer that lands on the gunbc/v1-seed (no std.unicode / std.render imports) so its -// witnesses execute under the v1 interpreter. The convergent IR authority is std.markdown -// (MarkdownDocument / MarkdownBlock / MarkdownInline, extended here's window with the GFM -// task-list / table blocks); this module owns only the SOURCE medium — the inverse direction -// of std.markdown's IR→HTML fold, over the same single IR (DESIGN §4: one grammar, both ways). -// -// ROW DISCIPLINE (the medium-as-Node guard, #5496): every construct→spelling lives in the -// `MarkdownSpellings` ROW the fold LOOKS UP — `#`, `- `, `- [x] `, `[t](u)`, table pipes, -// `*`/`**`, fences — never an inline string literal in the fold. Table-driven = reversible = -// the same rows the future v2 06_translate Markdown target reuses (they RELOCATE, no rework). -// Line breaks (`\n`) are structural layout, not construct spellings (cf. yaml.dag), so they -// stay inline. SCOPE: EMIT only (IR→source). The round-trip (source→IR ingest + lex) is the -// named ① dissolve-on, later, reusing these rows. -// -// Anchors: CommonMark 0.31.2 — https://spec.commonmark.org/0.31.2/ -// GitHub Flavored Markdown 0.29-gfm — https://github.github.com/gfm/ - module extdeps.languages.markdown import extdeps.external_authority { ExternalAuthority } @@ -71,9 +43,6 @@ import std.markdown { AlignRight, } -// §3 grounding: the markdown medium cites CommonMark as a structured fact, not a -// comment. GFM (the task-list / table extensions) extends this base spec — see the -// per-construct GFM citations on the MarkdownSpellings rows below. data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { uri: Uri { scheme: Https @@ -81,41 +50,33 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// ========================================================================= -// The spelling rows — single authority for every markdown source delimiter. -// Each field is the literal source spelling of one construct; the fold below -// looks these up, so a wrong spelling is one row edit (and one RED witness), -// never a literal buried in the fold. -// ========================================================================= - type MarkdownSpellings { - heading_marker: String // "#" (repeated per level) CommonMark §4.2 ATX headings - heading_sep: String // " " between markers and content - unordered_bullet: String // "- " CommonMark §5.2 list items (GFM canonical dash) - ordered_suffix: String // ". " after the ordinal CommonMark §5.2 - task_checked: String // "[x] " GFM §5.3 task list items - task_unchecked: String // "[ ] " - emphasis_delim: String // "*" CommonMark §6.2 emphasis (italic) - strong_delim: String // "**" CommonMark §6.2 strong emphasis (bold) - code_span_delim: String // "`" CommonMark §6.3 code spans - code_fence: String // "```" CommonMark §4.5 fenced code blocks - link_text_open: String // "[" CommonMark §6.5 links - link_text_close: String // "]" - link_url_open: String // "(" - link_url_close: String // ")" - image_marker: String // "!" CommonMark §6.6 images - table_pipe: String // "|" GFM §4.10 tables - table_cell_pad: String // " " padding inside a cell - table_align_none: String // "---" GFM §4.10 delimiter-row cell - table_align_left: String // ":--" - table_align_center: String // ":-:" - table_align_right: String // "--:" - blockquote_marker: String // "> " CommonMark §5.1 block quotes - list_indent: String // " " one nesting level of list indentation - block_separator: String // "\n\n" blank line between top-level blocks -} - -// The CommonMark 0.31.2 + GFM 0.29 canonical spellings — the default medium. + heading_marker: String + heading_sep: String + unordered_bullet: String + ordered_suffix: String + task_checked: String + task_unchecked: String + emphasis_delim: String + strong_delim: String + code_span_delim: String + code_fence: String + link_text_open: String + link_text_close: String + link_url_open: String + link_url_close: String + image_marker: String + table_pipe: String + table_cell_pad: String + table_align_none: String + table_align_left: String + table_align_center: String + table_align_right: String + blockquote_marker: String + list_indent: String + block_separator: String +} + data commonmark_gfm_spellings: MarkdownSpellings = { heading_marker: "#", heading_sep: " ", @@ -143,11 +104,6 @@ data commonmark_gfm_spellings: MarkdownSpellings = { block_separator: "\n\n", } -// ========================================================================= -// Inlines. -// ========================================================================= - -// "[text](url)" / "![alt](url)" share this affix shape (the link form). fn md_link_form(text: String, url: String, sp: MarkdownSpellings) -> String { join( [sp.link_text_open, text, sp.link_text_close, sp.link_url_open, url, sp.link_url_close], @@ -175,12 +131,6 @@ fn md_inlines(inlines: List, sp: MarkdownSpellings) -> String { fold(inlines, init: "", f: (acc, i) => concat(acc, md_inline(inline: i, sp: sp))) } -// ========================================================================= -// Lists (ordered / unordered / GFM task) — depth carries nesting indentation. -// A list item leads with its first paragraph's inlines on the marker line; -// any further blocks (nested lists) render indented one level deeper. -// ========================================================================= - fn md_item(marker: String, blocks: List, sp: MarkdownSpellings, depth: Int) -> String { let pad = repeat_string(s: sp.list_indent, n: depth) fold(blocks, init: { idx: 0, out: "" }, f: (acc, b) => { @@ -227,7 +177,6 @@ fn md_tasklist(items: List, sp: MarkdownSpellings, depth: Int) }), "\n") } -// A block nested inside a list item: lists indent one level; any other block renders flat. fn md_nested(block: MarkdownBlock, sp: MarkdownSpellings, depth: Int) -> String { match block { UnorderedListBlock { items } => md_unordered(items: items, sp: sp, depth: depth) @@ -237,15 +186,10 @@ fn md_nested(block: MarkdownBlock, sp: MarkdownSpellings, depth: Int) -> String } } -// ========================================================================= -// Tables (GFM §4.10): header row, delimiter row (from alignments), body rows. -// ========================================================================= - fn md_table_cell(cell: MarkdownTableCell, sp: MarkdownSpellings) -> String { md_inlines(inlines: cell.inlines, sp: sp) } -// "| a | b |" — open pipe, then each cell padded and pipe-closed. fn md_table_row(row: MarkdownTableRow, sp: MarkdownSpellings) -> String { fold(row.cells, init: sp.table_pipe, f: (acc, c) => join([acc, sp.table_cell_pad, md_table_cell(cell: c, sp: sp), sp.table_cell_pad, sp.table_pipe], "")) @@ -281,10 +225,6 @@ fn md_table( } } -// ========================================================================= -// Block quotes (CommonMark §5.1): prefix every inner line with "> ". -// ========================================================================= - fn md_prefix_lines(text: String, prefix: String) -> String { join(map(split(s: text, delimiter: "\n"), line => concat(prefix, line)), "\n") } @@ -294,10 +234,6 @@ fn md_blockquote(blocks: List, sp: MarkdownSpellings) -> String { md_prefix_lines(text: inner, prefix: sp.blockquote_marker) } -// ========================================================================= -// Top-level blocks. -// ========================================================================= - fn heading_level_to_int(level: HeadingLevel) -> Int { match level { H1 => 1 @@ -326,8 +262,7 @@ fn md_block(block: MarkdownBlock, sp: MarkdownSpellings) -> String { TaskListBlock { items } => md_tasklist(items: items, sp: sp, depth: 0) CodeBlock { code } => - // The fenced block: code is expected to carry its own trailing newline - // (mirrors std.markdown's CodeBlock convention), so "```\n" + code + "```". + join([sp.code_fence, "\n", code, sp.code_fence], "") TableBlock { header, alignments, rows } => md_table(header: header, alignments: alignments, rows: rows, sp: sp) @@ -336,11 +271,6 @@ fn md_block(block: MarkdownBlock, sp: MarkdownSpellings) -> String { } } -// ========================================================================= -// Document entry — the medium serializer. Blocks separated by a blank line, -// one trailing newline at EOF (byte-faithful, peer of serialize_yaml). -// ========================================================================= - fn serialize_markdown_source_with(doc: MarkdownDocument, sp: MarkdownSpellings) -> String { concat( join(map(doc.blocks, b => md_block(block: b, sp: sp)), sp.block_separator), @@ -348,58 +278,12 @@ fn serialize_markdown_source_with(doc: MarkdownDocument, sp: MarkdownSpellings) ) } -// Total serializer: MarkdownDocument → byte-faithful markdown source (CommonMark + GFM). fn serialize_markdown_source(doc: MarkdownDocument) -> String { serialize_markdown_source_with(doc: doc, sp: commonmark_gfm_spellings) } -// ========================================================================= -// INGEST — markdown SOURCE → MarkdownDocument (the §5.2 round-trip inverse). -// -// This is the "① dissolve-on" named in this file's header turned live: the -// inverse direction of the emitter, reading the **same** `MarkdownSpellings` -// rows (DESIGN §4: one grammar, both directions; §5.2: the round-trip law -// `ingest ∘ emit = id` is the medium-completeness oracle). A spelling lives in -// exactly one place — the row — and BOTH directions consult it, so a wrong -// spelling is one row edit and one RED witness, never a literal forked between -// an emitter and a parser (the N×M trap §4 forbids). -// -// FIDELITY BOUNDARY (DESIGN §4/§5/§7, `extdeps.communication.medium`): -// `ingest ∘ emit = id` is proven **Lossless over the canonical core** — the -// block grammar with plain-text inlines: -// headings, single-line paragraphs, flat unordered / ordered / GFM-task -// lists, and fenced code blocks; inlines are literal `TextInline` runs. -// Inline markup (emphasis / strong / code spans / links / images), nested -// lists, tables and block quotes are the **Lossy frontier**: the emitter is -// total over them but their source is ambiguous on re-ingest (e.g. `*x*` could -// be text or emphasis), so this ingest reads them as literal paragraph text and -// the round-trip law is NOT claimed there. That residue is tagged `Lossy` -// (see `markdown_medium_lossless` below) rather than fabricated — §5 -// fail-closed: a lossy decode is marked, never silently advertised exact. -// Dissolve-on for the frontier: an inline tokenizer + indentation/table grammar -// that recover those constructs, at which point their fidelity flips to Lossless. -// -// ROW-SHARING LEDGER (honest, per the §5 "inert lens" guard — claim only what -// is exercised). The rows consulted in BOTH directions over the core, each -// perturbation-discriminable: `heading_marker`, `heading_sep`, `unordered_bullet`, -// `ordered_suffix`, `task_checked`, `task_unchecked`, `code_fence`, -// `block_separator`. The remaining rows are NOT row-shared by this ingest because -// the constructs they spell are the frontier above: `emphasis_delim`/`strong_delim`/ -// `code_span_delim`/`link_*`/`image_marker` (inline markup), `table_*` (tables), -// `blockquote_marker` (block quotes), and `list_indent` (nested-list indentation — -// flat core lists emit at depth 0 with empty indent, so the row is absent from both -// directions in-core). They become row-shared when the frontier dissolves. -// ========================================================================= - -// A leading-run strip result: how many copies of a unit prefix were consumed, -// and the remaining suffix. Reused for ATX heading markers and ordered-list -// ordinals (the two leading-run constructs the core grammar reads back). type RepeatStrip { count: Int, rest: String } -// Inverse of heading_level_to_int. The core grammar admits only depths 1..=6 -// (the emitter emits no others), so the catch-all is unreachable in-core; it -// keeps the function total without fabricating a plausible wrong level (a 7-`#` -// line is classified as a paragraph upstream, never reaching here). fn int_to_heading_level(n: Int) -> HeadingLevel { if n == 1 { H1 } else if n == 2 { H2 } @@ -409,12 +293,10 @@ fn int_to_heading_level(n: Int) -> HeadingLevel { else { H6 } } -// Drop a known prefix (caller has checked starts_with). fn md_drop_prefix(s: String, prefix: String) -> String { substring(s: s, start: prefix.length(), end: s.length()) } -// Consume a maximal run of `unit` from the front of `s`. fn md_strip_repeated(s: String, unit: String, n: Int) -> RepeatStrip { if (unit != "") && starts_with(s: s, prefix: unit) { md_strip_repeated(s: md_drop_prefix(s: s, prefix: unit), unit: unit, n: n + 1) @@ -427,7 +309,6 @@ fn md_is_digit(c: String) -> Bool { (c != "") && string_contains(s: "0123456789", pattern: c) } -// Consume a maximal run of decimal digits from the front of `s`. fn md_strip_digits(s: String, n: Int) -> RepeatStrip { let c = char_at(s, 0) if md_is_digit(c: c) { @@ -437,24 +318,10 @@ fn md_strip_digits(s: String, n: Int) -> RepeatStrip { } } -// Inline ingest over the canonical core: a content run is one literal TextInline -// (the Lossless subset — see the FIDELITY BOUNDARY note above). fn md_ingest_inlines(text: String) -> List { [ TextInline { text: text } ] } -// --- block splitting: split source into top-level block-source strings ------- -// -// The emitter joins top-level blocks with the `block_separator` ROW (:serialize_ -// markdown_source_with) and appends exactly one trailing newline at EOF. The -// inverse READS the SAME row: strip the one trailing newline, then split on -// `sp.block_separator`. This is row-shared in BOTH directions — perturb -// block_separator and emit/ingest shift together (exercised by the witness). -// -// CORE BOUND: a fenced code block whose body contains the block_separator -// sequence internally (e.g. a blank line when block_separator is "\n\n") would -// be wrongly split here — that is the Lossy frontier (code with embedded -// separators), not claimed. The core code-block body has no embedded separator. fn md_split_blocks(src: String, sp: MarkdownSpellings) -> List { let trimmed = if ends_with(s: src, suffix: "\n") { substring(s: src, start: 0, end: src.length() - 1) @@ -464,8 +331,6 @@ fn md_split_blocks(src: String, sp: MarkdownSpellings) -> List { split(s: trimmed, delimiter: sp.block_separator) } -// --- per-block parse, dispatching on the leading spelling row ---------------- - fn md_is_heading(line: String, sp: MarkdownSpellings) -> Bool { let h = md_strip_repeated(s: line, unit: sp.heading_marker, n: 0) (h.count >= 1) && (h.count <= 6) && starts_with(s: h.rest, prefix: sp.heading_sep) @@ -521,10 +386,6 @@ fn md_task_item(line: String, sp: MarkdownSpellings) -> MarkdownTaskItem { } } -// A fenced code block source is `code_fence` + "\n" + code + `code_fence`, where -// `code` carries its own trailing newline (the std.markdown convention the -// emitter relies on). As grouped lines: [fence, ...code lines..., fence]; -// rejoin the inner lines and restore the trailing newline. fn md_parse_code(block_lines: List) -> MarkdownBlock { let inner = block_lines.skip(n: 1).take(n: block_lines.length() - 2) CodeBlock { @@ -546,31 +407,21 @@ fn md_parse_block(block_src: String, sp: MarkdownSpellings) -> MarkdownBlock { } else if starts_with(s: first, prefix: sp.unordered_bullet) { UnorderedListBlock { items: map(lines, l => md_unordered_item(line: l, sp: sp)) } } else { - // Canonical-core paragraph: a single line of literal inline text. Frontier - // constructs (inline markup, tables, block quotes) also land here as literal - // text — the Lossy boundary, not an exact inverse (see FIDELITY BOUNDARY). + ParagraphBlock { inlines: md_ingest_inlines(text: block_src) } } } -// Ingest with an explicit spelling table (the inverse of -// serialize_markdown_source_with over the same rows). fn ingest_markdown_source_with(src: String, sp: MarkdownSpellings) -> MarkdownDocument { MarkdownDocument { blocks: map(md_split_blocks(src: src, sp: sp), b => md_parse_block(block_src: b, sp: sp)), } } -// Total ingest: byte-faithful markdown source → MarkdownDocument over the -// CommonMark + GFM canonical spellings (the inverse of serialize_markdown_source). fn ingest_markdown_source(src: String) -> MarkdownDocument { ingest_markdown_source_with(src: src, sp: commonmark_gfm_spellings) } -// The honest per-medium fidelity tag (DESIGN §4/§5.2 (B) decidability partition): -// markdown is `Lossless` over the canonical core proven by the round-trip witness; -// the carried representation is the IR recovered by ingest. The frontier residue -// is the `Lossy` partition — never claimed by this Medium. fn markdown_medium_lossless(doc: MarkdownDocument) -> Medium { Medium { carried: doc, fidelity: Lossless } } diff --git a/dsl/extdeps/languages/python/emit.dag b/dsl/extdeps/languages/python/emit.dag index 08a10b4790c..6c98fb055d3 100644 --- a/dsl/extdeps/languages/python/emit.dag +++ b/dsl/extdeps/languages/python/emit.dag @@ -1,31 +1,13 @@ -// extdeps/languages/python/emit.dag -- Python language facts for the v2 emitter. -// -// Single source of truth for Python-specific data consumed by the emitter. -// Imports only the shared SimpleMethodSpec carrier from std; the rest are -// leaf data declarations. -// -// Ref: Python Language Reference (docs.python.org/3/reference) -// Python Standard Library (docs.python.org/3/library) -// -// Consumers: -// v2/05_emit.dag -- type mapping, keywords, container templates - module extdeps.languages.python.emit import std.emit_model { SimpleMethodSpec } -// -- Keyword/operator translation ---------------------------------------- -// DAG keywords/operators -> Python syntax. -// Ref: Python Reference 6.10-6.12 "Comparisons", "Boolean operations" data python_keywords: Map = { "true": "True", "false": "False", "null": "None", "and": "and", "or": "or", "not": "not ", "div": "//" } -// -- Container type templates -------------------------------------------- -// {0} = element type, {1} = second type (maps). -// Ref: typing module (PEP 585) data python_container_templates: Map = { "list": "list[\{0\}]", "set": "set[\{0\}]", "optional": "Optional[\{0\}]", "map": "dict[\{0\}, \{1\}]", @@ -33,8 +15,6 @@ data python_container_templates: Map = { "boolean_algebra": "bool" } -// -- Reserved words ------------------------------------------------------ -// Ref: Python Reference 2.3.1 Keywords data python_reserved: List = [ "False", "None", "True", "and", "as", "assert", "async", "await", "break", "class", "continue", "def", "del", "elif", "else", @@ -44,23 +24,12 @@ data python_reserved: List = [ "type", "match", "case" ] -// -- Reserved word escape ------------------------------------------------ -// Ref: PEP 8 -- trailing underscore convention for keyword conflicts. -// Mirrors python_reserved_words.strategy.suffix from std.languages. data python_reserved_escape_suffix: String = "_" -// -- Type definitions ---------------------------------------------------- -// Ref: PEP 557 "Data Classes", PEP 484 "Type Hints" -// Mirrors python_type_defs.derive_attribute from std.languages. data python_derive_attribute: String = "@dataclass" -// -- Serialization ------------------------------------------------------- -// Ref: Python builtins -// Mirrors python_serialization.default_value from std.languages. data python_default_value: String = "None" -// -- Item definition facts ------------------------------------------------ -// Ref: Python Reference §8 "Compound statements" data python_func_keyword: String = "def" data python_async_prefix: String = "async " data python_struct_keyword: String = "class" @@ -73,28 +42,11 @@ data python_module_keyword: String = "" data python_import_keyword: String = "import" data python_import_from_keyword: String = "from" -// -- Project scaffold ---------------------------------------------------- -// Ref: Python packaging conventions -// Mirrors python_scaffold from std.languages. data python_source_extension: String = ".py" data python_module_init: String = "__init__.py" -// -- String-like types ------------------------------------------------------ -// Types that use string comparison/indexing semantics in Python. data python_string_types: List = ["String", "Secret"] -// -- Method templates ------------------------------------------------------- -// Named-placeholder templates for algebra method calls. -// \{recv\} = pre-emitted receiver, \{arg\} = pre-emitted first argument. -// Ref: Python standard library, builtins, functools. -// -// Single authority: `python_simple_method_specs` carries the flat-templatable -// (unary `{recv}`/`{arg}`) methods, exactly the set the emitter renders by -// template. `map`/`fold`/`concat` are deliberately NOT here — they are binary+ -// (`fold(coll, init, f)` per dsl/std/algebra.dag) and route through the runtime -// bridge, which forwards every argument (a flat one-arg template would drop -// fold's accumulator/callback). `python_method_templates_flat()` derives the -// emit map from this list. Mirrors #5039's Rust slice. data python_simple_method_specs: List = [ { method_name: "count", template: "len(\{recv\})", wraps_result: false }, { method_name: "join", template: "\{arg\}.join(\{recv\})", wraps_result: false }, @@ -114,15 +66,11 @@ data python_simple_method_specs: List = [ { method_name: "append", template: "\{recv\} + [\{arg\}]", wraps_result: false } ] -// Derived: the flat templatable map the emitter reads (single authority above). -// `map`/`fold`/`concat` are absent → they route via the runtime bridge (correct -// argument forwarding). fn python_method_templates_flat() -> Map { python_simple_method_specs |> fold(init: empty_map(), f: (acc, spec) => map_insert(acc, spec.method_name, spec.template)) } -// -- Expression syntax templates ------------------------------------------ data python_lambda_template: String = "lambda {0}: {1}" data python_error_expr_template: String = "raise RuntimeError({0})" data python_list_literal_empty: String = "[]" diff --git a/dsl/extdeps/languages/python/primitives.dag b/dsl/extdeps/languages/python/primitives.dag index 5bbf9e77361..185c3cc65d8 100644 --- a/dsl/extdeps/languages/python/primitives.dag +++ b/dsl/extdeps/languages/python/primitives.dag @@ -1,206 +1,37 @@ -// extdeps/languages/python/primitives.dag — Structural target-primitive -// declarations for the Python target (T-Ground-Python tranche 1 / spec authority). -// -// FIRST SLICE (this file): Python language-reference built-in types whose -// value domain is fixed by the language spec — `int` (arbitrary precision), -// `bool`, `str` (immutable Unicode code-point sequence), and `None` (the -// single inhabitant of `NoneType`). See Python Language Reference §"The -// standard type hierarchy" (docs.python.org/3/reference/datamodel.html) and -// §"Numeric Types — int, float, complex" -// (docs.python.org/3/library/stdtypes.html#numeric-types-int-float-complex). -// -// `float` and `complex` are intentionally omitted from this tranche: the -// language reference states "Floating point numbers are usually implemented -// using double in C" and explicitly flags float/complex precision as -// "implementation dependent". Declaring a fixed IEEE-754 carrier here would -// repeat the same no-lying-about-width discipline violation Go's omission of -// `int` / `uint` / `uintptr` calls out — defer until a CPython-tagged -// implementation-width story lands alongside DB-11 / cardinality substrate. -// `bytes` / `bytearray` (built-in byte-sequence types) are also deferred to -// the next tranche; they're language-level but not part of the -// numeric/bool/str tranche-1 scope per dispatch brief. -// -// TWO-AUTHORITY DISCIPLINE (ROADMAP §Post-R1 Grounding lanes): -// (a) THIS FILE — Python language reference (docs.python.org/3/reference). -// (b) stdlib carriers and product-specific rows (e.g. `dict` for Json, -// `bytes` for Bytes payloads consumed via stdlib paths) stay in -// python/types.dag + emit tables until a dedicated stdlib-authority -// slice lands; do not cite stdlib paths here. -// -// CONSUMER BOUNDARY: top-level list / record aggregates lower structurally. -// What is *not* yet live for this file: there is no Python-grounding consumer -// in-tree yet for `python_spec_predeclared_primitives` or -// `python_dag_unit_target_primitive` — so today these rows are loaded but -// unconsumed (Path-2 staging in the fixture-registration sense, not in the -// lowering sense). Type-structure (`PythonPrimitive = …`) is walkable for the -// future engine consumer. -// -// LESSON 5 (grounding-pilot-receipt.md): subset-only axes are structurally -// partitioned — every `PythonPrimitive` variant carries its own per-variant -// algebra-tag and carrier-tag witness types, so any algebra/carrier pair -// other than the spec-valid one is unrepresentable by construction (no -// `PythonBooleanPrimitive { algebra: TerminalAlgebra }`, -// no `PythonIntegerPrimitive { carrier: BitCarrier }`). -// -// STRING (language ref §"Text Sequence Type — str", -// docs.python.org/3/library/stdtypes.html#textseq): a `str` value is an -// immutable sequence of Unicode code points (free monoid over Unicode code -// points). Source-text encoding (UTF-8 / UTF-16 / etc.) is NOT a second -// carrier/algebra authority on the spec `str` row — it is encode/decode -// surface and belongs in operator or stdlib slices, not parallel sum arms -// on `PythonStringPrimitive`. (Same discipline as Go's spec-string row -// declining a UTF-8 parallel authority on `GoStringPrimitive`.) -// -// SUBSTRATE-GAP FLAGS: -// 1. Python `int` is arbitrary precision — no fixed-width carrier and no -// modular-wrap overflow. This file models it with the -// `PythonIntUnboundedCarrier` sentinel (no `range_min/max`, -// no `overflow` field) so consumers cannot read a false fixed width. -// Post-DB-11 / cardinality substrate this becomes -// `OrderedRing` with countably-infinite -// cardinality; today the sentinel carrier is the honest declaration. -// 2. `bool` is a subclass of `int` per the Python data model -// (True == 1, False == 0). This file routes `bool` through -// `PythonBooleanPrimitive` with the canonical two-element Boolean -// algebra value-domain (Bit-carrier sentinel) and does not yet model -// the int-coercion edge — that lives in coercion / operator slices, -// not on the predeclared primitive row. -// 3. Algebra and carrier identity is still carried by structural tags -// (per-variant `PythonSpecAlgebraTag` / -// `PythonSpecCarrierTag`), same bridge pattern as -// rust/primitives.dag and go/primitives.dag, until the .dag substrate -// exposes type expressions as data values. - module extdeps.languages.python.primitives -// ========================================================================= -// Per-variant algebra / carrier witness tags. -// -// State-space modeling discipline: each `PythonPrimitive` variant gets its -// own dedicated algebra-tag and carrier-tag sum, so the spec-valid -// (algebra, carrier) pair is the *only* representable assignment for that -// row. Sharing a broad `PythonNonIntegerAlgebra` across Boolean and Unit -// (or a broad `PythonTargetCarrier` across Integer / Boolean / Unit) would -// admit nonsense rows like `PythonBooleanPrimitive { algebra: TerminalAlgebra }` -// — illegal-states-unrepresentable forbids that. -// -// Coproduct-dissolution ledger annotations follow the -// post-#1046 Go file style: each closed coproduct names its **🟢 GREEN** -// (terminal / consumed) arm and its **🟡 YELLOW** (parse-scaffold reserved) -// arm. Every coproduct below has ≥2 arms by construction (v2 bootstrap -// loader rejects unary `type X = Tag` aliases), with reserved arms named -// for their dissolution trigger: bootstrap / loader closes single-arm sums, -// at which point the reserved arms (and these per-variant tag types -// entirely) collapse into direct algebra/carrier references — see -// substrate-gap flag #3. -// ========================================================================= - -// --- Integer primitive witness tags --- -// -// **🟢 GREEN** — `PythonIntOrderedRingAlgebra` is the terminal -// algebra-tag for Python's spec integer (signed, additive inverse exists). -// **🟡 YELLOW (scaffold)** — `PythonIntegerSpecAlgebraReserved`. type PythonIntegerSpecAlgebraTag = PythonIntOrderedRingAlgebra | PythonIntegerSpecAlgebraReserved -// **🟢 GREEN** — `PythonIntUnboundedCarrier` is the honest -// declaration that Python `int` is arbitrary-precision (substrate-gap -// flag #1; DB-11 will refine to a countably-infinite cardinality witness). -// **🟡 YELLOW (scaffold)** — `PythonIntegerSpecCarrierReserved`. type PythonIntegerSpecCarrierTag = PythonIntUnboundedCarrier | PythonIntegerSpecCarrierReserved - -// --- Boolean primitive witness tags --- -// -// **🟢 GREEN** — `PythonBoolCanonicalTwoElementBooleanAlgebra` -// is the terminal algebra-tag for Python's spec `bool`. -// **🟡 YELLOW (scaffold)** — `PythonBooleanSpecAlgebraReserved`. type PythonBooleanSpecAlgebraTag = PythonBoolCanonicalTwoElementBooleanAlgebra | PythonBooleanSpecAlgebraReserved -// **🟢 GREEN** — `PythonBoolBitCarrier` is the algebra -// value-domain witness for `bool` (per `dsl/std/integer.dag:4` carrier-vs- -// evidence convention; not CPython object representation). -// **🟡 YELLOW (scaffold)** — `PythonBooleanSpecCarrierReserved`. type PythonBooleanSpecCarrierTag = PythonBoolBitCarrier | PythonBooleanSpecCarrierReserved - -// --- String primitive witness tags --- -// -// **🟢 GREEN** — -// `PythonStrImmutableUnicodeCodePointSequenceMonoidAlgebra` is the -// terminal algebra-tag for Python `str` (header §STRING). -// **🟡 YELLOW (scaffold)** — `PythonStringSpecAlgebraReserved`. Encoding -// (UTF-8 / UTF-16) is NOT a second arm here. type PythonStringSpecAlgebraTag = PythonStrImmutableUnicodeCodePointSequenceMonoidAlgebra | PythonStringSpecAlgebraReserved -// **🟢 GREEN** — `PythonStrUnicodeCodePointSequenceCarrier` is -// the terminal carrier-tag for Python `str`. -// **🟡 YELLOW (scaffold)** — `PythonStringSpecCarrierReserved`. type PythonStringSpecCarrierTag = PythonStrUnicodeCodePointSequenceCarrier | PythonStringSpecCarrierReserved - -// --- Unit (None / NoneType) primitive witness tags --- -// -// **🟢 GREEN** — `PythonUnitTerminalAlgebra` is the -// single-inhabitant algebra of `NoneType`. -// **🟡 YELLOW (scaffold)** — `PythonUnitSpecAlgebraReserved`. type PythonUnitSpecAlgebraTag = PythonUnitTerminalAlgebra | PythonUnitSpecAlgebraReserved -// **🟢 GREEN** — `PythonUnitTerminalCarrier` is the -// single-inhabitant carrier sentinel for `None` (DB-11 will refine to -// `Cardinality`). -// **🟡 YELLOW (scaffold)** — `PythonUnitSpecCarrierReserved`. type PythonUnitSpecCarrierTag = PythonUnitTerminalCarrier | PythonUnitSpecCarrierReserved - -// ========================================================================= -// Sum-typed Python spec primitive (Lesson 5 partition). -// -// Sum-typed so each spec primitive's structurally-meaningful axes attach -// only where they have meaning, AND each variant's algebra/carrier fields -// are typed by per-variant singleton-tag pairs (see witness-tag block -// above) — illegal-states-unrepresentable: a `PythonBooleanPrimitive` can -// only carry `PythonBoolCanonicalTwoElementBooleanAlgebra` and -// `PythonBoolBitCarrier`; a `PythonIntegerPrimitive` can only carry -// `PythonIntOrderedRingAlgebra` and `PythonIntUnboundedCarrier`; etc. -// -// No `range_min/max` and no `overflow` field on `PythonIntegerPrimitive`: -// substrate-gap flag #1 — Python's spec `int` is unbounded, so a -// fixed-range / fixed-overflow row would be a lie. Consumers needing -// concrete-width integer routing should consult target-specific lanes -// (Rust / Go `*_integer_range` rows) rather than synthesizing a width here. -// -// **🟡 YELLOW (scheduled -// scaffold).** All four arms are spec-realized and consumed today (each -// has a matching row in `python_spec_predeclared_primitives` / -// `python_dag_unit_target_primitive`): -// - `PythonIntegerPrimitive` ↔ row `int` (spec §"Numeric Types" — int). -// - `PythonBooleanPrimitive` ↔ row `bool` (spec §"Boolean Type — bool"). -// - `PythonStringPrimitive` ↔ row `str` (spec §"Text Sequence — str"). -// - `PythonUnitPrimitive` ↔ row `None` (spec §"The Null Object — None"). -// The partition itself is YELLOW (not GREEN) because its end-state is -// dissolution, not steady-state coexistence: when DB-11 / cardinality -// substrate lets algebra+carrier be referenced as data, all four variants -// collapse into a single record-shaped row with refinement-typed fields, -// and `PythonPrimitive` retires alongside the per-variant witness tags. -// Dissolution trigger: DB-11 / cardinality substrate (named). -// ========================================================================= - type PythonPrimitive = PythonIntegerPrimitive { target_name: String @@ -223,15 +54,6 @@ type PythonPrimitive carrier: PythonUnitSpecCarrierTag } - -// Predeclared spec primitives: int, bool, str. -// (None / NoneType is split into a separate top-level row below — same -// pattern as Go's `go_dag_unit_target_primitive` — because `None` is the -// canonical DAG `Unit` realization in `python/types.dag`, not a numeric -// or sequence primitive.) -// -// `float` / `complex` deferred (header §implementation-defined width). -// `bytes` / `bytearray` deferred to next tranche. data python_spec_predeclared_primitives: List = [ PythonIntegerPrimitive { target_name: "int", algebra: PythonIntOrderedRingAlgebra, @@ -246,14 +68,6 @@ data python_spec_predeclared_primitives: List = [ carrier: PythonStrUnicodeCodePointSequenceCarrier } ] -// DAG Unit → Python: `None` (the sole inhabitant of `NoneType`) is the -// target spelling for DagName `Unit` in `python/types.dag`. Split out from -// the predeclared list (same pattern as `go_dag_unit_target_primitive`) -// because `None` is a value, not a type name in the spec's predeclared-type -// list — `NoneType` is the type and is not a builtin identifier in the -// scope a user can name without `types.NoneType`. The target-name string -// here records the value spelling consumers emit ("None"), aligning with -// `python_type_checkpoints` in `python/types.dag`. data python_dag_unit_target_primitive: PythonPrimitive = PythonUnitPrimitive { target_name: "None", algebra: PythonUnitTerminalAlgebra, diff --git a/dsl/extdeps/languages/python/syntax.dag b/dsl/extdeps/languages/python/syntax.dag index 95b99e4791c..11a3b355c42 100644 --- a/dsl/extdeps/languages/python/syntax.dag +++ b/dsl/extdeps/languages/python/syntax.dag @@ -1,11 +1,3 @@ -// Python syntax specification. -// -// Operator semantics for Python emission. The emitter reads operator -// symbols from this spec — no hardcoded Python syntax in the compiler. -// -// Ref: Python Reference §6 "Expressions" -// https://docs.python.org/3/reference/expressions.html - module extdeps.languages.python.syntax import std.syntax { @@ -17,8 +9,6 @@ import std.syntax { AlgebraFieldKind, AlgReciprocal, AlgQuotient } -// Python emission item forms — target keywords for .dag→Python compilation. -// Ref: Python Reference §8 "Compound statements" data python_item_forms: List = [ ItemForm { kind: FuncForm, keyword: "def", has_type_params: false, has_params: true, has_return_type: true, return_required: false, @@ -37,14 +27,6 @@ data python_item_forms: List = [ has_uses: false, body_kind: NoBody } ] -// Python operator precedence (emission-relevant subset). -// Python uses word operators for boolean (and, or) and // for integer div. -// The // binding is retained only for the v2 AlgQuotient compatibility bridge -// consumed by legacy language emission tests. It is not v3 algebra authority; -// delete it with AlgQuotient when v2 Div dispatch is retired or moved behind a -// v2-local syntax authority. -// Ref: Python Reference §6.17 "Operator precedence" - data python_operators: List = [ OperatorSpec { symbol: "or", left_bp: 5, right_bp: 6, binop: Or, algebra_field: none }, OperatorSpec { symbol: "and", left_bp: 7, right_bp: 8, binop: And, algebra_field: none }, @@ -57,9 +39,7 @@ data python_operators: List = [ OperatorSpec { symbol: "+", left_bp: 13, right_bp: 14, binop: Add, algebra_field: none }, OperatorSpec { symbol: "-", left_bp: 13, right_bp: 14, binop: Sub, algebra_field: none }, OperatorSpec { symbol: "*", left_bp: 15, right_bp: 16, binop: Mul, algebra_field: none }, - // Div is algebra-aware for total reciprocal-shaped Field division and the - // v2-only AlgQuotient compatibility selector. - // Ref: Python Reference §6.7 "Binary arithmetic operations" + OperatorSpec { symbol: "/", left_bp: 15, right_bp: 16, binop: Div, algebra_field: Present { value: AlgReciprocal } }, OperatorSpec { symbol: "//", left_bp: 15, right_bp: 16, binop: Div, algebra_field: Present { value: AlgQuotient } }, OperatorSpec { symbol: "%", left_bp: 15, right_bp: 16, binop: Mod, algebra_field: none } diff --git a/dsl/extdeps/languages/python/types.dag b/dsl/extdeps/languages/python/types.dag index c4fa4954ca8..8cb87bfc6dc 100644 --- a/dsl/extdeps/languages/python/types.dag +++ b/dsl/extdeps/languages/python/types.dag @@ -1,34 +1,9 @@ -// extdeps/languages/python/types.dag -- Python coercion data. -// -// Declares which Python types inhabit which .dag algebraic structures. -// Python has garbage collection, so sharing is identity (no wrapper). -// -// FAIL-CLOSED CONTRACT: Missing inhabitant = compile error. -// -// SCHEMA: Type definitions live in std/coercion.dag (shared authority). -// This file instantiates data only — no local type families. -// -// Ref: Python Language Reference (docs.python.org/3/reference) -// PEP 484 "Type Hints", PEP 557 "Data Classes" -// std/algebra.dag, std/coercion.dag -// -// Consumers: -// v2/05_emit_python.dag -- coercion engine reads inhabitants - module extdeps.languages.python.types import std.coercion { TypeCheckpoint, InhabitantDecl, CallableRepr, CastSyntax } - -// ========================================================================= -// Type checkpoints -// -// Python has no Copy/Move distinction. All values are references to -// objects on the GC heap. is_copy is none for all entries. -// ========================================================================= - data python_type_checkpoints: List = [ { dag_name: "Int", target_type: "int", default_expr: "0", is_copy: none, literal_suffix: none }, { dag_name: "Float", target_type: "float", default_expr: "0.0", is_copy: none, literal_suffix: none }, @@ -40,16 +15,6 @@ data python_type_checkpoints: List = [ { dag_name: "Json", target_type: "dict", default_expr: "{}", is_copy: none, literal_suffix: none } ] - -// ========================================================================= -// Algebra inhabitants -// -// COMPARISON WITH RUST: -// FreeMonoid → list (Python) vs Vec (Rust) -// BooleanAlgebra → set (Python) vs BTreeSet (Rust) -// PartialFunction→ dict (Python) vs HashMap (Rust) -// ========================================================================= - data python_algebra_inhabitants: List = [ { algebra: "FreeMonoid", template: "list[\{0\}]", @@ -87,21 +52,6 @@ data python_algebra_inhabitants: List = [ is_copy: none } ] - -// ========================================================================= -// Optional: T | None (PEP 604) -// -// Authority: typing_optional and none_literal below. No separate optional -// declarations — they would duplicate the existing syntax facts. -// ========================================================================= - - -// ========================================================================= -// Callable: Callable[[T], U] (typing module) -// -// Python has no owned/shared/static distinction. GC handles everything. -// ========================================================================= - data python_callable: CallableRepr = CallableRepr { template: "Callable[[\{params\}], \{return\}]", param_separator: ", ", @@ -109,20 +59,6 @@ data python_callable: CallableRepr = CallableRepr { import_path: "from typing import Callable" } - -// ========================================================================= -// Sharing -// -// Python has GC. Sharing is structural identity — no wrapper needed. -// The emitter knows this from the target language, not from a declared -// SharingStrategy config surface. -// ========================================================================= - - -// ========================================================================= -// Retained Python type system facts -// ========================================================================= - type PythonTypeKind = DynamicType | AnnotatedType @@ -150,14 +86,6 @@ data pass_statement: String = "pass" data type_checker: String = "mypy" data type_checker_strict: String = "mypy --strict" -// Cast syntax: Python uses constructor calls (int(x), float(x), str(x)). -// fail_open=true models Python's actual semantics: constructor calls are -// always syntactically valid. Invalid casts (e.g., int("hello")) produce -// runtime errors, not syntax errors. The emitter faithfully renders the -// construct; the target language's runtime validates. -// Python constructor casts: int(x), float(x), bool(x), str(x). -// All numeric conversions are syntactically valid in Python. -// Runtime validates (e.g., int("hello") raises ValueError). data python_cast_syntax: CastSyntax = { template: "\{type\}(\{expr\})", cast_rules: [ diff --git a/dsl/extdeps/languages/rust/emit.dag b/dsl/extdeps/languages/rust/emit.dag index 02f675a68a3..d57f4e77f32 100644 --- a/dsl/extdeps/languages/rust/emit.dag +++ b/dsl/extdeps/languages/rust/emit.dag @@ -1,36 +1,13 @@ -// extdeps/languages/rust/emit.dag -- Rust language facts for the v2 emitter. -// -// Single source of truth for Rust-specific data consumed by the emitter. -// Imports only the shared SimpleMethodSpec carrier from std; the rest are -// leaf data declarations. -// -// Ref: The Rust Reference (doc.rust-lang.org/reference) -// Rust Standard Library (doc.rust-lang.org/std) -// -// Consumers: -// v2/05_emit.dag -- type mapping, keywords, container templates -// v2/05_emit_rust.dag -- reserved words, runtime function tables - module extdeps.languages.rust.emit import std.emit_model { SimpleMethodSpec } -// -- Keyword/operator translation ---------------------------------------- -// DAG keywords/operators -> Rust syntax. -// Ref: Rust Reference 8.2 "Expressions" data rust_keywords: Map = { "true": "true", "false": "false", "null": "None", "and": "&&", "or": "||", "not": "!", "div": "/" } -// -- Container type templates -------------------------------------------- -// {0} = element type, {1} = second type (maps). -// Ref: std::vec::Vec, std::collections::BTreeSet, std::option::Option, std::collections::HashMap -// NOTE: Templates are BARE types. Rc-wrapping is applied by the rendering -// layer (build_type_rendering + render_type) via rc_types, not baked into -// templates. This prevents Rc decisions from being duplicated between -// templates and the rc_types predicate. data rust_container_templates: Map = { "list": "Vec<\{0\}>", "set": "std::collections::BTreeSet<\{0\}>", "optional": "Option<\{0\}>", "map": "HashMap<\{0\}, \{1\}>", @@ -38,16 +15,6 @@ data rust_container_templates: Map = { "boolean_algebra": "bool" } -// -- Method templates -------------------------------------------------------- -// Named-placeholder templates for simple algebra method calls. -// Templates use {recv} (receiver) and {arg} (first argument). -// Applied via apply_named_template in shared emit. -// -// Single authority: SimpleMethodSpec carries both the template and -// wraps_result flag. Derived maps feed LanguageSpec (template only) -// and Rust emitter (wrapping). Same pattern as HigherOrderMethodSpec. -// The type itself lives in std.emit_model (shared by Python/Go too). - data rust_simple_method_specs: List = [ { method_name: "count", template: "(\{recv\}.len() as i64)", wraps_result: false }, { method_name: "join", template: "\{recv\}.join(&\{arg\})", wraps_result: false }, @@ -60,21 +27,17 @@ data rust_simple_method_specs: List = [ { method_name: "take", template: "\{recv\}.iter().cloned().take(\{arg\} as usize).collect::>()", wraps_result: true } ] -// Derived: template map for LanguageSpec consumption (backend-neutral). fn rust_method_templates() -> Map { rust_simple_method_specs |> fold(init: empty_map(), f: (acc, spec) => map_insert(acc, spec.method_name, spec.template)) } -// Derived: wraps_result map for Rust Rc-wrapping decisions. fn rust_method_wraps_result() -> Map { rust_simple_method_specs |> filter(s => s.wraps_result) |> fold(init: empty_map(), f: (acc, spec) => map_insert(acc, spec.method_name, true)) } -// -- Reserved words ------------------------------------------------------ -// Ref: Rust Reference, Appendix A: Keywords data rust_reserved: List = [ "as", "async", "await", "break", "const", "continue", "crate", "dyn", "else", "enum", "extern", "false", "fn", "for", "if", @@ -86,35 +49,24 @@ data rust_reserved: List = [ "virtual" ] -// -- Reserved word escape ------------------------------------------------ -// Mirrors rust_reserved_words.strategy.suffix from std.languages. data rust_reserved_escape_suffix: String = "_" -// -- String-like types --------------------------------------------------- -// Types that render as Rust &str/.as_str() for comparison operations. data rust_string_types: List = ["String", "Secret"] -// -- Derives -------------------------------------------------------------- -// Ref: Rust derive macros. Serde required for data defs with nested -// records (emitted via serde_json::from_value). serde is already a -// dependency so derives are free at the margin. data rust_struct_derives: String = "#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]" -// Copy variant: value-semantic types that don't need Rc wrapping. + data rust_struct_derives_copy: String = "#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]" data rust_enum_derives: String = "#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]" -// Copy variant: simple enums (all-unit variants). + data rust_enum_derives_copy: String = "#[derive(Debug, Clone, Copy, PartialEq, serde::Serialize, serde::Deserialize)]" -// Ref: serde docs — #[serde(tag = "...")] for internally tagged enums + data rust_serde_tag: String = "#[serde(tag = \"_variant\")]" -// Ref: serde docs — #[serde(rename_all = "...")] for std.serialization.VariantNaming wire policies. + data rust_serde_rename_all_snake_case: String = "#[serde(rename_all = \"snake_case\")]" data rust_serde_rename_all_screaming_snake_case: String = "#[serde(rename_all = \"SCREAMING_SNAKE_CASE\")]" -// {0} = field key name. Ref: serde docs — #[serde(rename = "...")] + data rust_serde_rename_template: String = "#[serde(rename = \"\{0\}\")]" -// -- Item definition facts ------------------------------------------------ -// Ref: Rust Reference §6 "Items" -// Each fact is a single language-specific token the emitter composes. data rust_func_keyword: String = "fn" data rust_async_prefix: String = "async " data rust_struct_keyword: String = "struct" @@ -127,45 +79,31 @@ data rust_module_keyword: String = "mod" data rust_import_keyword: String = "use" data rust_import_from_keyword: String = "" -// -- Expression syntax templates ------------------------------------------ -// {0} = params, {1} = body. Ref: Rust Reference §8.2.2 "Closure expressions" data rust_lambda_template: String = "|{0}| {1}" -// {0} = message string + data rust_error_expr_template: String = "panic!({0})" -// {0} = comma-separated elements + data rust_list_literal_empty: String = "Rc::new(vec![])" data rust_list_literal_template: String = "Rc::new(vec![{0}])" -// {0} = left expr, {1} = right expr + data rust_null_coalesce_template: String = "{0}.unwrap_or_else(|| {1})" -// {0} = error label + data rust_error_type_template: String = "compile_error!(\"{0}\")" -// -- Type argument brackets ----------------------------------------------- + data rust_type_arg_open: String = "<" data rust_type_arg_close: String = ">" -// -- Void type ------------------------------------------------------------ + data rust_void_type: String = "()" -// -- Tuple syntax --------------------------------------------------------- + data rust_tuple_empty: String = "()" data rust_tuple_pair_template: String = "({0}, {1})" data rust_tuple_multi_template: String = "({0})" data rust_tuple_separator: String = ", " -// -- Project scaffold ---------------------------------------------------- -// Ref: Cargo Reference (doc.rust-lang.org/cargo/reference) -// Mirrors rust_scaffold from std.languages. data rust_source_extension: String = ".rs" data rust_source_dir: String = "src/" data rust_visibility: String = "pub " -// -- Runtime function registry -------------------------------------------- -// Single authority for DAG functions backed by v1_rt at runtime. -// Each entry declares: the DAG-level name, the Rust bridge symbol (when -// it differs from the DAG name), and whether the first map argument is -// passed by reference. -// -// Consumers call is_rt_function / rt_bridge_name / rt_passes_by_ref -// instead of probing three separate maps. - type RuntimeFunction { name: String bridge_name: String @@ -215,14 +153,11 @@ data rt_function_registry: List = [ { name: "clamp", bridge_name: "clamp", passes_by_ref: false, wraps_result: false }, { name: "atom_identity_hash", bridge_name: "atom_identity_hash", passes_by_ref: false, wraps_result: false }, { name: "hash_combine", bridge_name: "hash_combine", passes_by_ref: false, wraps_result: false }, - // Identity hints: owned Rc args (cheap refcount bump preserves inner pointers), - // so emit through the normal clone path -- no all-args-by-ref borrow rule needed. + { name: "rc_ptr_eq", bridge_name: "rc_ptr_eq", passes_by_ref: false, wraps_result: false }, { name: "rc_vec_ptr_eq", bridge_name: "rc_vec_ptr_eq", passes_by_ref: false, wraps_result: false } ] -// Derived indexes from rt_function_registry — all computed, single authority. - fn rt_functions() -> Map { rt_function_registry |> fold(init: empty_map(), f: (acc, entry) => map_insert(acc, entry.name, true)) @@ -261,19 +196,6 @@ fn rt_passes_by_ref(name: String) -> Bool { map_contains_key(rt_ref_map_functions(), name) } -// -- Higher-order method templates ------------------------------------------ -// Templates for algebra methods that take lambda or function-ref arguments. -// filter, any, all, flat_map share the same structural pattern: -// inline case: extract lambda params/body, substitute into template -// fn_ref case: pass function reference through iterator adapter -// -// Placeholders (all named, processed by apply_named_template): -// {param} — rendered lambda parameter name -// {body} — rendered lambda body expression -// {iter} — receiver through sharing.iter_owned -// {inner_iter} — body through sharing.iter_owned (flat_map only) -// {arg} — rendered first argument (fn_ref case) - type HigherOrderMethodSpec { method_name: String inline_template: String diff --git a/dsl/extdeps/languages/rust/primitives.dag b/dsl/extdeps/languages/rust/primitives.dag index e07bc00d4f4..2120b38aefc 100644 --- a/dsl/extdeps/languages/rust/primitives.dag +++ b/dsl/extdeps/languages/rust/primitives.dag @@ -1,118 +1,8 @@ -// extdeps/languages/rust/primitives.dag -- Structural target-primitive -// declarations for the Rust target. -// -// PILOT SCOPE (T-Ground-Pilot): {i8, i16, i32, i64, i128, u8, u16, u32, u64, -// u128, f32, f64, bool, ()} only. No containers, no coercion paths. -// -// T-Int128 SLICE B1 / B2 (RESOLVED 2026-05-06): both signed `i128` and -// unsigned `u128` rows are present. The prior B2 deferral of `u128` -// (because `u128::MAX` exceeded the host `i128` representation used by -// `IntervalInt::ExactInterval` for range-fact storage) was closed by R3 -// Phase A widening the host repr to arbitrary-precision `BigInt` -// (commit `e7ba022c6`) under Director Path A RATIFIED at -// gunbc#1739 #issuecomment-4392731264; the `u128` row landed in Phase B-1 -// (commit `59511503e`). -// -// FOLLOW-ON DEFERRAL: `isize` / `usize` rows remain deferred to a separate -// substrate-fact-introduction follow-on (named cascade — `IntSize` / -// `UIntSize` kernel integer carriers in `dsl/std/integer.dag`). Director- -// level scope; not bundled with this brief per Mgr disposition Path 1 -// at gunbc#1761 #issuecomment-4393235461. -// -// PURPOSE: Each declaration says "Rust target type T is a target primitive -// inhabiting algebra A over carrier C." Selection by algebra-homomorphism -// match — the toy grounding-inhabitance engine reproduced -// today's name-keyed table-lookup routing on the pilot set, validating -// the target-grounding-proposal.md thesis that "the mapping should fall -// out from the algebra, not from a hand-maintained table." -// -// CONSUMER BOUNDARY (HONEST STATE): the engine does NOT yet read this -// .dag file directly. It mirrors the structural facts authored here as -// Rust constants, with this file as the documented authority. Wiring the -// engine to consume .dag declarations as parsed-data is T-Ground-Engine's -// production-walker job; until then the grounding-inhabitance mirror must -// be kept in sync by hand when declarations here change. The duplication -// is bounded — pilot scope is 12 rows (10 IntegerPrimitive + 2 -// NonIntegerPrimitive `target_name` entries). Multiset parity was -// additionally ratcheted by the grounding-engine validator -// (`validate_rust_grounding_primitives_target_name_multiset_matches_mirror`). -// Parallel-existence, deletable as a unit when T-Ground-Engine lands and -// removes both this file's parallel-existence status and the pilot crate -// together. -// -// LANES: -// This file is parallel-existence. Dissolution of -// dsl/extdeps/languages/rust/types.dag (TypeCheckpoint name-keyed table -// + InhabitantDecl algebra-keyed fallback) is T-Ground-Dissolve scope, -// not Pilot. -// -// SOURCE AUTHORITY: -// Rust Reference §Types — https://doc.rust-lang.org/reference/types.html -// §3.4 Numeric types (i8/i16/i32/i64, u8/u16/u32/u64) -// §3.5 Boolean type (bool) -// §3.7 Tuple types (() as the empty tuple / unit) -// This is language-level grounding (Rust Reference, not stdlib) — the -// two-authority discipline (language reference vs stdlib) starts here. -// -// SUBSTRATE-GAP FLAGS (DB-11 will sharpen): -// 1. `IntegerOverflow` carries two's-complement-wrap as a closed-enum -// value field on the `IntegerPrimitive` variant. Post-DB-11 this -// becomes a where-clause refinement on the algebra carrier (e.g. -// OrderedRing where overflow = TwoComplementWrap), and -// under T-Ground-Engine refinement is per-operator (debug vs -// release for +/-/*; `/` and `%` panic on int::MIN/-1 regardless; -// `wrapping_*`/`checked_*`/`saturating_*` are explicit operator -// selections per Rust Reference §"overflow"). Today the language -// doesn't yet support first-class refinement qualifiers on type -// aliases, so the cleanest structural shape is a per-variant -// carried enum, with the integer/non-integer split handled by -// sum-typing `RustPrimitive` so overflow is structurally absent -// where it would be nonsensical (no `bool: Some(TwoComplementWrap)`, -// no `i64: None`). -// 2. `IntegerAlgebra` / `NonIntegerAlgebra` / `TargetCarrier` enums -// identify std/algebra.dag and std/bit.dag concepts by structural -// tag rather than as first-class type-references-as-data. The .dag -// substrate doesn't yet expose type expressions as data values -// (data-table fields can't be `algebra: OrderedRing` with OrderedRing -// referenced as a -// type identity). When that closes — co-temporally with the -// types.dag/coercion.dag dissolution under T-Ground-Dissolve — these -// tag enums collapse into direct algebra-and-carrier references and -// this file shrinks accordingly. -// 3. Unit modeled with `TerminalAlgebra` / `TerminalCarrier` sentinels. -// Post-DB-11 this becomes Cardinality; the terminal -// object is the canonical inhabitant. Pilot uses the sentinel pair -// because cardinality-substrate is not yet available (out-of-scope -// per brief: "Container types — block on cardinality-substrate."). - module extdeps.languages.rust.primitives import std.algebra { OrderedRing, Semiring, BooleanAlgebra } import std.bit { Bit, Byte, Word16, Word32, Word64, Word128 } - -// ========================================================================= -// Algebra tags, partitioned by overflow-bearing class. -// -// Closed enumerations identifying which std/algebra.dag structure a target -// primitive inhabits. Partitioned into integer-bearing and non-integer- -// bearing subtypes so that overflow facts attach only where they have -// meaning — making `bool: Some(TwoComplementWrap)` and `i64: None` -// structurally unrepresentable rather than ruled out by convention -// (state-space modeling discipline; no validation passes). -// -// IntegerAlgebra -// OrderedRingAlgebra <-> std.algebra.OrderedRing (signed integers) -// SemiringAlgebra <-> std.algebra.Semiring (unsigned integers) -// -// NonIntegerAlgebra -// ApproximateFieldAlgebra<-> std.approximate_field.ApproximateField (Float) -// BooleanAlgebraAlgebra <-> std.algebra.BooleanAlgebra (Bool) -// TerminalAlgebra <-> single-inhabitant terminal (Unit; DB-11) -// -// Substrate-gap flag #2: these tags are bridges to algebra references. -// ========================================================================= - type IntegerAlgebra = OrderedRingAlgebra | SemiringAlgebra @@ -122,33 +12,6 @@ type NonIntegerAlgebra | BooleanAlgebraAlgebra | TerminalAlgebra - -// ========================================================================= -// Target carrier tag. -// -// Closed enumeration identifying which std/bit.dag carrier (or terminal) -// the target primitive's **algebra value-domain witness** corresponds to, -// per the std convention declared in `dsl/std/integer.dag:4` ("Int is a -// CARRIER (Word64) with EVIDENCE that it inhabits OrderedRing"): -// BitCarrier <-> std.bit.Bit (BooleanAlgebra value-domain: 2-element set) -// ByteCarrier <-> std.bit.Byte (Ring/Semiring value-domain over 2^8) -// Word16Carrier <-> std.bit.Word16 (Ring/Semiring value-domain over 2^16) -// Word32Carrier <-> std.bit.Word32 (Ring/Semiring or ApproximateField width axis) -// Word64Carrier <-> std.bit.Word64 (Ring/Semiring or ApproximateField width axis) -// Word128Carrier <-> std.bit.Word128 (Ring/Semiring value-domain over 2^128) -// TerminalCarrier<-> single inhabitant (Unit; DB-11 -> Cardinality 1) -// -// NOT target storage layout. Rust's `bool` storage is 1 byte with only -// 0x00 and 0x01 valid (Rust Reference §3.5), but its algebra value-domain -// is the 2-element {⊤, ⊥} carried by Bit. Storage layout, ABI, and -// validity bytes are a distinct axis the pilot deliberately doesn't -// model — they're target-codegen concerns scoped to T-Ground-Engine / -// emit-pipeline, not to the structural target-grounding routing the -// pilot probes. -// -// Substrate-gap flag #2: these tags are bridges to type references. -// ========================================================================= - type TargetCarrier = BitCarrier | ByteCarrier @@ -158,72 +21,30 @@ type TargetCarrier | Word128Carrier | TerminalCarrier - -// ========================================================================= -// Integer overflow semantics. -// -// All Rust integer primitives in release mode wrap on overflow per -// two's-complement; debug mode panics on overflow. This is uniform across -// i8..u64 and so does not affect routing within the pilot set, but is -// declared structurally rather than left implicit because the -// target-grounding-proposal.md worked example calls it out as a -// declared-fact (proposal lines 174-210). -// -// Substrate-gap flag #1: post-DB-11 this becomes a where-clause refinement -// on the algebra carrier rather than a separate enum field. -// ========================================================================= - type IntegerOverflow = TwoComplementWrap | Saturating | Trap - -// ========================================================================= -// Rust target-primitive declaration. -// -// Sum-typed so the integer/non-integer split is structural, not -// conventional: overflow is a field on IntegerPrimitive and structurally -// absent on NonIntegerPrimitive. State-space discipline — no -// `bool: Some(TwoComplementWrap)`, no `i64: None`. is_copy carries on -// both variants (target-specific Copy-trait fact consumed downstream by -// sharing/Rc decisions). overflow carries on IntegerPrimitive only -// (T-Ground L4-(C) witness consumer; substrate-gap flag #1 names DB-11 -// dissolution to a where-clause refinement on the algebra carrier). -// ========================================================================= - type RustPrimitive = IntegerPrimitive { - target_name: String // Rust syntactic token: "i8".."i64", "u8".."u64" + target_name: String algebra: IntegerAlgebra carrier: TargetCarrier - // Integer literal range narrowing walks `rust_grounding_primitives` - // (`ValueBody::List`) and matches this row's `algebra`/`carrier` - // variant identities to the std `OrderedRing` / `Semiring` - // witness on the user's type — single authority for bounds. + range_min_inclusive: String range_max_inclusive: String is_copy: Bool overflow: IntegerOverflow } | NonIntegerPrimitive { - target_name: String // Rust syntactic token: "bool", "()" + target_name: String algebra: NonIntegerAlgebra carrier: TargetCarrier is_copy: Bool } -// ========================================================================= -// Grounding mirror primitive set. -// -// Ordering: signed integers (i8..i128), unsigned integers (u8..u128), floats -// (f32, f64), bool, (). No other types in this bounded grounding scope. -// ========================================================================= - data rust_grounding_primitives: List = [ - // -- Signed integers : OrderedRing over machine-word carriers ---------- - // Rust Reference §3.4. signed = additive inverse exists (negate in - // OrderedRing). Wrap is the release-mode semantics. IntegerPrimitive { target_name: "i8", algebra: OrderedRingAlgebra, carrier: ByteCarrier, range_min_inclusive: "-128", range_max_inclusive: "127", @@ -241,18 +62,11 @@ data rust_grounding_primitives: List = [ range_min_inclusive: "-9223372036854775808", range_max_inclusive: "9223372036854775807", is_copy: true, overflow: TwoComplementWrap }, - // T-Int128 Slice B1: signed 128-bit. Symmetric u128 row follows in unsigned - // section (R3 Phase B-1; Phase A BigInt range storage — see header). IntegerPrimitive { target_name: "i128", algebra: OrderedRingAlgebra, carrier: Word128Carrier, range_min_inclusive: "-170141183460469231731687303715884105728", range_max_inclusive: "170141183460469231731687303715884105727", is_copy: true, overflow: TwoComplementWrap }, - - // -- Unsigned integers : Semiring over machine-word carriers ----------- - // Rust Reference §3.4. unsigned = no additive inverse (no negate in - // Semiring). Distinguished from signed by algebra tag, not by carrier. - IntegerPrimitive { target_name: "u8", algebra: SemiringAlgebra, carrier: ByteCarrier, range_min_inclusive: "0", range_max_inclusive: "255", is_copy: true, overflow: TwoComplementWrap }, @@ -269,46 +83,20 @@ data rust_grounding_primitives: List = [ range_min_inclusive: "0", range_max_inclusive: "18446744073709551615", is_copy: true, overflow: TwoComplementWrap }, - // R3 Phase B (Director Path A RATIFIED at gunbc#1739 #issuecomment-4392731264; - // Option (ii) confirmed at gunbc#1761 #issuecomment-4393145631): u128 row - // unblocked by Phase A's `IntervalInt::ExactInterval` BigInt host repr - // widening (commit `e7ba022c6`). Range is `[0, 2^128 - 1]`; the prior - // `i128` host repr forced this row deferred (Slice B2 marker now - // resolved). Symmetric to i128 above; `Word128Carrier` per Rust Reference §3.4. IntegerPrimitive { target_name: "u128", algebra: SemiringAlgebra, carrier: Word128Carrier, range_min_inclusive: "0", range_max_inclusive: "340282366920938463463374607431768211455", is_copy: true, overflow: TwoComplementWrap }, - - // -- Floats : ApproximateField over machine-width refinements ---------- - // Rust Reference §3.4. Floating-point types are IEEE 754 binary32/binary64. - // Substrate authority: `dsl/std/float.dag` declares Float32/Float64 as - // aliases of `Real32` / `Real64`, where each `Real*` is - // `Compose>` (literal-Nat slot-2); `Real` itself is - // `ApproximateField>`, keeping exact-rational carrier - // and approximate witness layers distinct. - NonIntegerPrimitive { target_name: "f32", algebra: ApproximateFieldAlgebra, carrier: Word32Carrier, is_copy: true }, NonIntegerPrimitive { target_name: "f64", algebra: ApproximateFieldAlgebra, carrier: Word64Carrier, is_copy: true }, - - // -- Bool : BooleanAlgebra over Bit ----------------------------------- - // Rust Reference §3.5. The canonical two-element Boolean algebra; carrier - // is a single Bit. - NonIntegerPrimitive { target_name: "bool", algebra: BooleanAlgebraAlgebra, carrier: BitCarrier, is_copy: true }, - - // -- Unit : terminal object ------------------------------------------- - // Rust Reference §3.7 (empty tuple). DB-11 substrate gap flag #3: - // TerminalAlgebra/TerminalCarrier are sentinels for the not-yet-modeled - // Cardinality refinement. - NonIntegerPrimitive { target_name: "()", algebra: TerminalAlgebra, carrier: TerminalCarrier, is_copy: true } ] diff --git a/dsl/extdeps/languages/rust/syntax.dag b/dsl/extdeps/languages/rust/syntax.dag index dc7a4a8a54b..ca9f838e6ac 100644 --- a/dsl/extdeps/languages/rust/syntax.dag +++ b/dsl/extdeps/languages/rust/syntax.dag @@ -1,10 +1,3 @@ -// Rust syntax specification — instance #2 of SyntaxSpec. -// -// Describes Rust surface syntax as data. Proves the SyntaxSpec -// abstraction is real: the parser can be driven by non-.dag spec data. -// This is a subset sufficient to recognize common Rust item forms, -// operators, and literal keywords. - module extdeps.languages.rust.syntax import std.syntax { @@ -17,9 +10,6 @@ import std.syntax { LiteralValue, LitBool } -// Rust item forms — the keyword-driven dispatch table. -// fn, struct, enum, type, trait, impl, const, static, use, mod - data rust_item_forms: List = [ ItemForm { kind: FuncForm, keyword: "fn", has_type_params: true, has_params: true, has_return_type: true, return_required: false, @@ -50,15 +40,11 @@ data rust_item_forms: List = [ has_uses: false, body_kind: BlockBody } ] -// Rust literal keywords - data rust_keyword_literals: Map = { "true": LitBool { value: true }, "false": LitBool { value: false } } -// Rust keyword set — all reserved words - data rust_keyword_set: Map = { "fn": true, "struct": true, "enum": true, "type": true, "trait": true, "impl": true, "const": true, "static": true, "mod": true, "use": true, @@ -70,10 +56,6 @@ data rust_keyword_set: Map = { "true": true, "false": true } -// Rust operator precedence (subset). -// Assignment not included (statement, not expression in .dag model). -// Range operators (.., ..=) not included (no BinOp mapping yet). - data rust_operators: List = [ OperatorSpec { symbol: "||", left_bp: 5, right_bp: 6, binop: Or, algebra_field: none }, OperatorSpec { symbol: "&&", left_bp: 7, right_bp: 8, binop: And, algebra_field: none }, diff --git a/dsl/extdeps/languages/rust/types.dag b/dsl/extdeps/languages/rust/types.dag index 90789229e7c..30bafa6a713 100644 --- a/dsl/extdeps/languages/rust/types.dag +++ b/dsl/extdeps/languages/rust/types.dag @@ -1,39 +1,9 @@ -// extdeps/languages/rust/types.dag -- Rust coercion data. -// -// Declares which Rust types inhabit which .dag algebraic structures. -// Type coercion is a sidecast: same algebra, different representation. -// -// FAIL-CLOSED CONTRACT: If this file does not declare an inhabitant for -// an algebra, the compiler REFUSES to emit code for any .dag type that -// requires that algebra. Missing inhabitant = compile error. -// -// SCHEMA: Type definitions live in std/coercion.dag (shared authority). -// This file instantiates data only — no local type families. -// -// Ref: The Rust Reference (doc.rust-lang.org/reference) -// The Rustonomicon (doc.rust-lang.org/nomicon) -// std/algebra.dag (algebraic structure definitions) -// std/coercion.dag (shared coercion vocabulary) -// -// Consumers: -// v2/05_emit.dag -- coercion engine reads inhabitants -// v2/05_emit_rust.dag -- Rust-specific emit (TypeRendering boundary) - module extdeps.languages.rust.types import std.coercion { TypeCheckpoint, InhabitantDecl, CallableRepr, CastSyntax, CastRule } - -// ========================================================================= -// Type checkpoints -// -// Checked FIRST before algebra resolution. Maps .dag names directly to -// Rust types. is_copy carries Copy trait status for the resolved type; -// the emitter uses this (via ValueContext) to decide Rc wrapping. -// ========================================================================= - data rust_type_checkpoints: List = [ { dag_name: "Int", target_type: "i64", default_expr: "0", is_copy: true, literal_suffix: none }, { dag_name: "Float", target_type: "f64", default_expr: "0.0", is_copy: true, literal_suffix: none }, @@ -49,24 +19,8 @@ data rust_type_checkpoints: List = [ { dag_name: "witness", target_type: "Witness", default_expr: none, is_copy: false, literal_suffix: none } ] - -// ========================================================================= -// Algebra inhabitants -// -// Fallback when no checkpoint matches. The compiler resolves through the -// type's algebra and applies the matching InhabitantDecl template. -// -// CROSS-LANGUAGE COMPARISON: -// FreeMonoid → Vec (Rust) vs list[T] (Python) vs []T (Go) -// BooleanAlgebra → BTreeSet (Rust) vs set[A] (Python) vs map[A]struct{} (Go) -// PartialFunction→ HashMap (Rust) vs dict[K,V] (Python) vs map[K]V (Go) -// ========================================================================= - data rust_algebra_inhabitants: List = [ - // FreeMonoid → Vec - // Ordered sequences: concat + empty + positional access. - // BTreeSet chosen over HashSet: Ord is derivable for all .dag types; - // Hash is not derivable for types containing f64. + { algebra: "FreeMonoid", template: "Vec<\{0\}>", arity: 1, @@ -74,10 +28,6 @@ data rust_algebra_inhabitants: List = [ import_path: none, is_copy: false }, - // BooleanAlgebra → BTreeSet - // Sets: union (join) + intersect (meet) + complement. - // HISTORICAL BUG: Set was mapped to FreeMonoidCollectionProfile, - // giving sets list operations instead of set operations. { algebra: "BooleanAlgebra", template: "std::collections::BTreeSet<\{0\}>", arity: 1, @@ -85,8 +35,6 @@ data rust_algebra_inhabitants: List = [ import_path: "use std::collections::BTreeSet;", is_copy: false }, - // PartialFunction → HashMap - // Keyed partial functions: lookup + insert + merge. { algebra: "PartialFunction", template: "HashMap<\{0\}, \{1\}>", arity: 2, @@ -94,9 +42,6 @@ data rust_algebra_inhabitants: List = [ import_path: "use std::collections::HashMap;", is_copy: false }, - // OrderedRing → i64 - // Algebra-level fallback for Int. Normally the checkpoint handles - // Int → i64 directly; this exists for user-defined OrderedRing types. { algebra: "OrderedRing", template: "i64", arity: 0, @@ -104,9 +49,6 @@ data rust_algebra_inhabitants: List = [ import_path: none, is_copy: true }, - // ApproximateField → f64 - // Extends OrderedRing with division. "Approximate" because IEEE 754 - // breaks exact associativity. { algebra: "ApproximateField", template: "f64", arity: 0, @@ -115,28 +57,10 @@ data rust_algebra_inhabitants: List = [ is_copy: true } ] - -// ========================================================================= -// Optional coercion -// .dag T? → Rust Option -// ========================================================================= - data rust_optional_template: String = "Option<\{0\}>" data rust_none_expr: String = "None" data rust_some_template: String = "Some(\{0\})" - -// ========================================================================= -// Callable coercion -// -// Base callable template. Context-dependent wrapping (Box for -// owned closures, Rc for stored closures) is derived from -// ValueContext at emit time, not declared here. -// -// HISTORICAL BUG: Callable was mapped to "String" in rust_type_map. -// This caused 9 E0425 errors in std_algebra.rs. -// ========================================================================= - data rust_callable: CallableRepr = CallableRepr { template: "fn(\{params\}) -> \{return\}", param_separator: ", ", @@ -144,58 +68,12 @@ data rust_callable: CallableRepr = CallableRepr { import_path: none } - -// ========================================================================= -// Sharing -// -// NOT declared as a configuration surface. Sharing is a COERCION EFFECT -// derived from ValueContext at the TypeRendering boundary: -// -// ValueContext.is_constant = true → no Rc (const data) -// ValueContext.has_fn_fields = true → skip PartialEq/Debug derives -// resolved type is_copy = true → no Rc (value semantics sufficient) -// otherwise → Rc wrapping -// -// Recursive types get Box for indirection. These decisions are -// structural facts already in the annotated graph, not language config. -// -// HISTORICAL BUG: lazy_static + Rc for constant data → E0277 Send/Sync. -// The sharing effect was applied uniformly instead of being gated on -// ValueContext. The fix: ValueContext carries the facts, emitter translates. -// ========================================================================= - - - -// ========================================================================= -// Test generation -// -// Test obligations are derived by the compiler from algebra definitions -// in std/algebra.dag crossed with the inhabitant declarations above: -// -// Refusal tests: auto-generated for every algebra WITHOUT an inhabitant. -// Positive tests: auto-generated only from explicit law metadata in -// std/algebra.dag (each algebra field → law assertion). -// Hand-written tests: reserved for exceptional cases only. -// -// See docs/coercion-design.md for the full algorithm. -// ========================================================================= - - -// ========================================================================= -// Ownership model -// ========================================================================= - type OwnershipKind = Owned | SharedRef | MutRef | RawPtr - -// ========================================================================= -// Additional Rust type system facts -// ========================================================================= - data pass_copy_by_value: Bool = true data pass_non_copy_by_ref: Bool = true data ref_prefix: String = "&" @@ -224,28 +102,18 @@ data integer_types: List = [ data float_types: List = ["f32", "f64"] -// Cast syntax: Rust uses `expr as type` for numeric casts. -// Rust Reference §8.2.4 — cast validity is a (source, target) relation. -// Valid pairs for .dag types (mapped to Rust target types): -// i64 → i64, f64 (Int → Int, Float) -// f64 → i64, f64 (Float → Int, Float) -// bool → i64 (Bool → Int) -// Invalid: -// bool → f64 (Bool → Float: not allowed) -// i64 → bool (Int → Bool: not allowed) -// f64 → bool (Float → Bool: not allowed) data rust_cast_syntax: CastSyntax = { template: "\{expr\} as \{type\}", cast_rules: [ - // Integer ↔ Integer + { from_type: "i64", to_type: "i64" }, - // Integer → Float + { from_type: "i64", to_type: "f64" }, - // Float → Integer + { from_type: "f64", to_type: "i64" }, - // Float ↔ Float + { from_type: "f64", to_type: "f64" }, - // Bool → Integer (bool as i64 = 0 or 1) + { from_type: "bool", to_type: "i64" } ] } diff --git a/dsl/extdeps/llm/anthropic.dag b/dsl/extdeps/llm/anthropic.dag index 5421ea95361..9149c20a2a7 100644 --- a/dsl/extdeps/llm/anthropic.dag +++ b/dsl/extdeps/llm/anthropic.dag @@ -1,16 +1,9 @@ -// extdeps/llm/anthropic.dag — Anthropic Messages API protocol (types + wire contracts). -// -// Handlers (REST + Claude CLI): `anthropic_rest.dag` (`module extdeps.llm.anthropic_rest`). -// Cross-provider facts: `llm.dag` (`module extdeps.llm.llm`). -// Error envelope: `anthropic_errors.dag`. -// module extdeps.llm.anthropic import extdeps.llm.llm { llm_snake_wire_contract } import std.serialization { CoproductWireContract, VariantEncoding } import std.types { NonEmptyStr } -// Wire contract: Anthropic API returns enum values as snake_case strings. data wire_contract: VariantEncoding = llm_snake_wire_contract data anthropic_chat_message_wire_contract: CoproductWireContract = { @@ -33,23 +26,16 @@ data anthropic_messages_200_content_block_wire_contract: CoproductWireContract = encoding: InternallyTaggedObject { tag_field: "type", naming: StripPrefixSuffixAndSnakeCase { prefix: "Messages", suffix: "Block" } } } -// Tool-result nested content: REST wire is either a scalar JSON string or a JSON -// array of typed content blocks (Messages API `tool_result.content`). data anthropic_tool_result_content_wire_contract: CoproductWireContract = { coproduct: "AnthropicToolResultContent", encoding: UntaggedVariant } -// Nested blocks inside `ToolResultBlocks`: each row is a flat `{"type": ...}` object -// (same tagging discipline as user message content blocks; distinct carrier so shared -// provider-local nested blocks; not a cross-provider carrier). data anthropic_tool_result_block_wire_contract: CoproductWireContract = { coproduct: "AnthropicToolResultBlock", encoding: InternallyTaggedObject { tag_field: "type", naming: StripPrefixSuffixAndSnakeCase { prefix: "Anthropic", suffix: "Block" } } } -// -- Models -------------------------------------------------------- - type AnthropicModel = ClaudeHaiku4_5 | ClaudeSonnet4_6 @@ -68,11 +54,6 @@ data models: List = [ { model: ClaudeOpus4_6, model_id: "claude-opus-4-6-20251101", context_window: 200000, max_output_tokens: 64000 } ] -// -- Anthropic content blocks (provider-specific) --------------------- -// Tool-use / tool-result surfaces are Anthropic-specific. `ImageSource` -// models Anthropic Messages API image `source` shapes (base64 / url; file deferred). - -// Anthropic Messages image `source` base64 media types (extensible registry). type AnthropicImageMediaType = ImageJpeg | ImagePng @@ -103,72 +84,33 @@ fn anthropic_image_media_type_label(kind: AnthropicImageMediaType) -> String { } } -// 🟡 SCAFFOLD provider-domain coproduct for Anthropic Messages image `source` -// (base64/url arms emittable via `llm.Anthropic.Messages`; dissolve on -// `structural_coverage_gap_anthropic_messages_file_image_beta_header`). type ImageSource = Base64Image { media_type: AnthropicImageMediaType, data: String } | UrlImage { url: String } -// 🟢 TERMINAL provider-domain coproduct for tool-result content. Anthropic accepts -// either a scalar JSON string (`ToolResultText`) or a JSON array of nested blocks -// (`ToolResultBlocks`), matching Messages API `tool_result.content`. Tuple carriers -// pair with `anthropic_tool_result_content_wire_contract: UntaggedVariant` so serde -// untagged emission maps directly (string vs block array) without an extra object -// wrapper around the array arm. -// -// Nested block shapes use `AnthropicToolResultBlock` (below). type AnthropicToolResultContent = ToolResultText(String) | ToolResultBlocks(List) -// Tool-result nested content blocks (provider-side carrier). Mirrors the union -// accepted inside `tool_result.content` arrays per Anthropic Messages API / -// generated SDK (`TextBlockParam | ImageBlockParam | DocumentBlockParam | -// SearchResultBlockParam | ToolReferenceBlockParam`). -// -// Singleton wire tag: nested `search_result.content[]` rows and plaintext document -// `source.type` both require the JSON string `"text"` (illegal states -// unrepresentable at the substrate boundary). type AnthropicToolResultWireTextTag = Text {} -// Singleton: `PlainTextSourceParam.media_type` is the literal `"text/plain"` on the wire -// (illegal states unrepresentable — https://github.com/anthropics/anthropic-sdk-python/blob/main/src/anthropic/types/plain_text_source_param.py). type AnthropicPlainTextDocumentMediaType = TextPlain {} -// Nested `search_result.content[]` rows per platform schema (each object carries -// wire `type: "text"` alongside `text` — https://platform.claude.com/docs/en/build-with-claude/search-results). type AnthropicToolResultTextBlock { type: AnthropicToolResultWireTextTag text: String } -// Optional `citations` object on `search_result` blocks (`enabled: Bool`). type AnthropicSearchResultCitationsConfig { enabled: Bool } -// 🟡 SCAFFOLD — nested `document` / `search_result` payloads are not full OpenAPI -// parity vs platform docs; honest residue on -// `structural_coverage_gap_anthropic_tool_result_nested_block_wire_payloads`. -// -// Dissolution trigger: promote to 🟢 TERMINAL when those residual rows are deleted or -// rewritten to explicit terminal closure on this authority **and** the five-arm -// `tool_result.content[]` discriminator surface is closed against the tracked public -// API / generated SDK (no remaining extension-only gap on this coproduct). -// -// Maintenance trigger (not dissolution): Anthropic adds a *sixth* top-level block kind -// beyond the five modeled arms → fold the new wire tag under -// `anthropic_tool_result_block_wire_contract` here, or escalate if the contract becomes -// non-additive. type AnthropicToolResultBlock = AnthropicTextBlock { text: String } | AnthropicImageBlock { source: ImageSource } - // Plaintext `source` only — not full DocumentBlockParam (extra document sources, - // title/context/citations/cache_control, …). Tracked under - // `structural_coverage_gap_anthropic_tool_result_nested_block_wire_payloads`. + | AnthropicDocumentBlock { source: AnthropicToolResultPlainTextDocumentSource } | AnthropicSearchResultBlock { source: String @@ -179,15 +121,6 @@ type AnthropicToolResultBlock } | AnthropicToolReferenceBlock { tool_name: String } -// Honest residue: nested tool-result **payload** fidelity vs generated SDK / -// OpenAPI (per-arm coordinates, not the five-way discriminator). Paid rows on -// `rest_request_wire_serde_alignment_receipt` cover coproduct discriminators + -// untagged `tool_result.content` dispatch — not every nested field on each arm. -// SDK witness (Stainless): `anthropic-sdk-python` `tool_result_block_param.Content` -// arms `TextBlockParam` / `ImageBlockParam` / `ToolReferenceBlockParam` carry optional -// `cache_control: CacheControlEphemeralParam`; `TextBlockParam` also carries optional -// `citations`; `CacheControlEphemeralParam` includes optional `ttl` literal (`5m`|`1h`) -// beyond our stringly `CacheControl.type` carrier — enumerate each omission below. data structural_coverage_gap_anthropic_tool_result_nested_block_wire_payloads: List = [ "closure:anthropic_tool_result_nested_wire_payload|AnthropicToolResultBlock.AnthropicTextBlock|missing:cache_control|missing:citations|sdk:https://raw.githubusercontent.com/anthropics/anthropic-sdk-python/main/src/anthropic/types/text_block_param.py|trigger:model TextBlockParam cache_control + citations structurally on nested tool_result text rows", "closure:anthropic_tool_result_nested_wire_payload|AnthropicToolResultBlock.AnthropicImageBlock|missing:cache_control|sdk:https://raw.githubusercontent.com/anthropics/anthropic-sdk-python/main/src/anthropic/types/image_block_param.py|trigger:model ImageBlockParam cache_control on nested tool_result image rows", @@ -197,32 +130,20 @@ data structural_coverage_gap_anthropic_tool_result_nested_block_wire_payloads: L "closure:anthropic_tool_result_nested_wire_payload|AnthropicToolResultBlock.AnthropicSearchResultBlock|external_spec_watch:search_result_block_optional_fields|trigger:citations.cache_control_shape_drift_or_additional_optional_keys_from_OpenAPI" ] -// Inline plaintext document source for tool-result document blocks (`source.type` -// is the fixed `"text"` wire slot — same singleton as nested search-result text rows). type AnthropicToolResultPlainTextDocumentSource { type: AnthropicToolResultWireTextTag media_type: AnthropicPlainTextDocumentMediaType data: String } -// 🟢 TERMINAL provider-domain coproduct for user-message content. `UserTextBlock` -// and `UserToolResultBlock` are role-legal Anthropic Messages content rows; the -// wire `type` keys are emitter/transport obligations, not caller-authored model -// state. Tool-result content is optional on the wire and, when present, is the -// explicit `AnthropicToolResultContent` coproduct above. type AnthropicUserContentBlock = UserTextBlock { text: String } | UserToolResultBlock { tool_use_id: String, content: AnthropicToolResultContent?, is_error: Bool? } -// 🟢 TERMINAL provider-domain coproduct for assistant-message content. -// Assistants can emit text or tool-use requests; tool results are user rows. type AnthropicAssistantContentBlock = AssistantTextBlock { text: String } | AssistantToolUseBlock { id: String, name: String, input: Json } -// -- System prompt ------------------------------------------------- - -// Anthropic API cache control: wire shape requires {"type": "ephemeral"}. type CacheControlType = CacheEphemeral {} @@ -243,8 +164,6 @@ type SystemPrompt { cache_control: CacheControl? } -// -- Extended thinking --------------------------------------------- - type ThinkingMode = Enabled | Disabled type ThinkingConfig { @@ -252,16 +171,12 @@ type ThinkingConfig { budget_tokens: Int? } -// -- Tool definitions ---------------------------------------------- - type AnthropicToolDefinition { name: String description: String input_schema: Json } -// -- API versioning ------------------------------------------------ - type AnthropicApiVersion { version: String header: String @@ -272,19 +187,10 @@ data current_api_version: AnthropicApiVersion = { header: "anthropic-version" } -// Messages API conversation row: the outer variant is the role discriminator, -// so role-specific content legality is structural. User rows can carry text or -// tool results; assistant rows can carry text or tool-use requests. -// 🟢 TERMINAL provider-domain coproduct for the modeled Messages row roles. -// Q4.5 P1 closure (#808 / #856 Substrate escalation). type AnthropicChatMessage = UserMessage { content: List } | AssistantMessage { content: List } -// Narrow 200-OK wire slice for Messages (text-only `content[0]` path). -// Tool-use / image assistant rows remain outside this carrier. -// 🟢 TERMINAL response citation coproduct. Each citation variant carries only -// the documented coordinates for that wire tag. type AnthropicMessages200Citation = CharLocation { cited_text: String, document_index: Int, document_title: String?, file_id: String?, start_char_index: Int, end_char_index: Int } | PageLocation { cited_text: String, document_index: Int, document_title: String?, file_id: String?, start_page_number: Int, end_page_number: Int } @@ -292,15 +198,6 @@ type AnthropicMessages200Citation | WebSearchResultLocation { cited_text: String, encrypted_index: String, title: String?, url: String } | SearchResultLocation { cited_text: String, source: String, title: String?, search_result_index: Int, start_block_index: Int, end_block_index: Int } -// 🟡 SCAFFOLD provider-domain coproduct for Anthropic Messages 200 `content[]` -// response rows. The outer wire shape is already stable and `type`-tagged, so -// these arms belong as a coproduct instead of optional coordinates on a text -// record. Scaffold triggers (also tracked in -// `structural_coverage_gap_anthropic_messages_200_residual` below): -// `MessagesWebSearchToolResultBlock.content` remains `Json` until the -// web-search result/error payload gains a structural payload coproduct, and -// `AnthropicMessages200Body.content/0/text` output projection needs -// variant-aware typed REST response-path support. type AnthropicMessages200ContentBlock = MessagesTextBlock { text: String, citations: List? } | MessagesThinkingBlock { thinking: String, signature: String } @@ -309,17 +206,8 @@ type AnthropicMessages200ContentBlock | MessagesServerToolUseBlock { id: String, name: AnthropicServerToolName, input: Json, caller: Json? } | MessagesWebSearchToolResultBlock { tool_use_id: String, content: Json, caller: Json? } -// 🟡 SCAFFOLD provider-domain enum for Anthropic `server_tool_use.name` -// values mirrored from Anthropic's generated OpenAPI SDK schema. Scaffold -// trigger: retire or extend this row when Anthropic publishes additional -// `server_tool_use.name` values; per-tool input payload typing remains tracked -// by `server_tool_input_payloads_unmodeled`. type AnthropicServerToolName = WebSearch | WebFetch | CodeExecution | BashCodeExecution | TextEditorCodeExecution | ToolSearchToolRegex | ToolSearchToolBm25 | Advisor -// 🟢 TERMINAL provider-domain enum for Anthropic Messages 200 `usage.service_tier`. -// Dissolution receipt: the field is a closed API string domain, not free-form -// metadata; fact placement would duplicate the usage field authority, algebraic -// form has no operator surface, and dimensional split has no independent axes. type AnthropicMessages200ServiceTier = Standard | Priority | Batch type AnthropicMessages200Usage { @@ -330,21 +218,11 @@ type AnthropicMessages200Usage { service_tier: AnthropicMessages200ServiceTier? } -// Anthropic Messages 200 response role. The API currently returns only -// "assistant"; keep the slot typed and let the module wire_contract serialize -// the unit variant as the required snake-case string. type AnthropicMessages200Role = Assistant {} -// 🟢 TERMINAL provider-domain coproduct for Anthropic Messages `stop_reason` -// wire values. Dissolution receipt: fact placement fails because every value is -// the same response-field fact consumed at `stop_reason`; variant-is-data would -// demote Anthropic's closed API enum into free-form text; algebraic form has no -// std operation/ref target; dimensional split has no independent axes beyond the -// documented reason-token domain. type AnthropicStopReason = EndTurn | MaxTokens | StopSequence | ToolUse | PauseTurn | Refusal | ModelContextWindowExceeded -// Message object envelope `type` — Anthropic returns only "message" today. type AnthropicMessagesObjectType = MessagesObjectMessage {} @@ -356,9 +234,6 @@ fn anthropic_messages_object_type_label(kind: AnthropicMessagesObjectType) -> St } } -// Message object envelope for POST /v1/messages 200 responses per Anthropic docs -// (https://docs.anthropic.com/en/api/messages): `id`, `type`, `role`, `content`, -// `model`, `stop_reason`, optional `stop_sequence`, `usage`. type AnthropicMessages200Body { id: String type: AnthropicMessagesObjectType @@ -380,12 +255,6 @@ data structural_coverage_gap_anthropic_messages_200_residual: List = [ "closure:anthropic_messages_200_residual|llm.Anthropic.Messages.output.content|blocked:variant_aware_typed_rest_response_projection|path:content/0/text|requires_arm:AnthropicMessages200ContentBlock.MessagesTextBlock|trigger:structural projection metadata carrier lands" ] -// Request wire: Messages API expects string `role` + flat `content[]` objects -// keyed by `type` (https://docs.anthropic.com/en/api/messages). These rows are -// now source-level `CoproductWireContract` authorities above; the v2 Rust -// emitter consumes them directly for serde attributes. Nested tool-result -// `content` uses `anthropic_tool_result_content_wire_contract` + -// `anthropic_tool_result_block_wire_contract` (paid below). data rest_request_wire_serde_alignment_receipt: List = [ "closure:rest_request_wire_serde_alignment|llm.Anthropic.Messages|AnthropicChatMessage|paid:role_internally_tagged_object_user_assistant", "closure:rest_request_wire_serde_alignment|llm.Anthropic.Messages|AnthropicUserContentBlock|paid:type_internally_tagged_object_text_tool_result", diff --git a/dsl/extdeps/llm/anthropic_errors.dag b/dsl/extdeps/llm/anthropic_errors.dag index c2fae29c11e..2694d497205 100644 --- a/dsl/extdeps/llm/anthropic_errors.dag +++ b/dsl/extdeps/llm/anthropic_errors.dag @@ -1,13 +1,7 @@ -// extdeps/llm/anthropic_errors.dag -- Anthropic Messages API error envelope shape. -// -// Spec: https://docs.anthropic.com/en/api/errors -// API version: 2023-06-01 (anthropic-version header) - module extdeps.llm.anthropic_errors import std.types { NonEmptyStr } -// Anthropic error envelope outer `type` — currently only "error" on the wire. type AnthropicErrorEnvelopeType = AnthropicErrorEnvelope {} @@ -19,7 +13,6 @@ fn anthropic_error_envelope_type_label(kind: AnthropicErrorEnvelopeType) -> Stri } } -// Anthropic error `error.type` registry (extensible — closed cited rows + Other). type AnthropicErrorType = AnthropicAuthenticationError | AnthropicInvalidRequestError diff --git a/dsl/extdeps/llm/anthropic_rest.dag b/dsl/extdeps/llm/anthropic_rest.dag index fcbae34500d..9d8eba8a900 100644 --- a/dsl/extdeps/llm/anthropic_rest.dag +++ b/dsl/extdeps/llm/anthropic_rest.dag @@ -1,9 +1,3 @@ -// extdeps/llm/anthropic_rest.dag — `llm.Anthropic` realization handlers (REST + Claude CLI). -// -// Protocol types and wire contracts live in `anthropic.dag` (`module extdeps.llm.anthropic`). -// One dependency interface (`llm.Anthropic`), multiple transports (DESIGN.md §3) — not a -// forked `llm.Claude` service in `cli.dag`. - module extdeps.llm.anthropic_rest import extdeps.llm.anthropic { @@ -15,20 +9,15 @@ import extdeps.llm.anthropic { import extdeps.llm.anthropic_errors { AnthropicErrorShape } import std.credentials { EnvVar } -// 🟡 dissolved — feature:llm-anthropic-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); the published corpus (extdeps.llm.mock_corpus) now governs WHICH -// llm.Anthropic ops are hermetically realizable, and the fixture store owns the payloads (§3). -// forbidden: reintroducing mock_response constants for Hermetic dispatch on these shapes. service llm.Anthropic { config { endpoint: "https://api.anthropic.com" auth: Header("x-api-key") auth_input: api_key auth_source: EnvVar { name: "ANTHROPIC_API_KEY" } - // Anthropic API rate limits: varies by tier (1000-4000 RPM), use conservative default + rate_limit: { requests: 1000, per: minute, scope: messages } - // Retry on overload and server errors with exponential backoff + retry: { max_attempts: 3, backoff: exponential, retry_on: [429, 500, 502, 503, 529] } } @@ -66,9 +55,6 @@ service llm.Anthropic { } } - // Claude Code CLI — shell realization of the same Anthropic dependency. - // Spec: https://docs.anthropic.com/en/docs/claude-code - // Auth: ANTHROPIC_API_KEY (CLI reads env; not wired through service config). operation CliPrompt { input { prompt: String diff --git a/dsl/extdeps/llm/cli.dag b/dsl/extdeps/llm/cli.dag index 342efc7c082..a9046dda3e8 100644 --- a/dsl/extdeps/llm/cli.dag +++ b/dsl/extdeps/llm/cli.dag @@ -1,31 +1,5 @@ -// extdeps/llm/cli.dag — non-Anthropic CLI LLM backends (shell transport). -// -// Spec: https://github.com/openai/codex (Codex CLI) -// Spec: https://github.com/google-gemini/gemini-cli (Gemini CLI) -// -// Anthropic (Claude Code CLI) lives on `llm.Anthropic.CliPrompt` in -// `anthropic_rest.dag` — one interface for REST + shell, not a forked `llm.Claude`. -// -// HONEST-MODELING DEBT (DESIGN.md §3, #5059 pattern): Gemini `CliPrompt` fuses -// `--output-format text` and `--approval-mode plan` as argv literals. The grammar -// supports `{var}` interpolation but not omitting flags when a value would disable -// them — parameterize when conditional argv lands (A1 transport-shape de-fusion). -// -// Consumers: -// gunbc/tools/review_codex.dag — Codex CLI PR review workflow - module extdeps.llm.cli -// -- Codex CLI -------------------------------------------------------- -// -// Codex reads prompt from stdin, executes in a working directory, -// writes structured output. Uses OpenAI auth (OPENAI_API_KEY env var). - -// 🟡 dissolved — feature:llm-codex-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); the published corpus (extdeps.llm.mock_corpus) now governs WHICH -// llm.Codex ops are hermetically realizable, and the fixture store owns the payloads (§3). -// forbidden: reintroducing mock_response constants for Hermetic dispatch on these shapes. service llm.Codex { operation Review { input { @@ -56,15 +30,6 @@ service llm.Codex { } } -// -- Gemini CLI ------------------------------------------------------- -// -// Gemini accepts prompt as a positional argument. Uses Google auth. - -// 🟡 dissolved — feature:llm-gemini-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); the published corpus (extdeps.llm.mock_corpus) now governs WHICH -// llm.Gemini ops are hermetically realizable, and the fixture store owns the payloads (§3). -// forbidden: reintroducing mock_response constants for Hermetic dispatch on these shapes. service llm.Gemini { operation CliPrompt { input { diff --git a/dsl/extdeps/llm/llm.dag b/dsl/extdeps/llm/llm.dag index ba1a99987a3..acb0b9caccb 100644 --- a/dsl/extdeps/llm/llm.dag +++ b/dsl/extdeps/llm/llm.dag @@ -1,19 +1,5 @@ -// extdeps/llm/llm.dag — cross-provider LLM facts only. -// -// Provider-shaped types live in discrete homes: -// extdeps/llm/anthropic.dag — Anthropic protocol (types + wire contracts) -// extdeps/llm/anthropic_rest.dag — Anthropic handlers (REST Messages + CLI CliPrompt) -// extdeps/llm/cli.dag — Codex / Gemini CLI only (Anthropic → anthropic_rest) -// extdeps/llm/openai.dag — OpenAI protocol -// extdeps/llm/openai_rest.dag — OpenAI REST transport -// -// Land a row here only when the fact is structurally shared across providers. - module extdeps.llm.llm import std.serialization { VariantEncoding, StringVariant, VariantNaming, SnakeCase } -// Wire contract: Anthropic and OpenAI APIs return enum values as snake_case strings. -// Single authority for the shared `VariantEncoding` value; each provider module binds -// its own module-scoped `wire_contract` name for the emitter (`05_emit_rust.dag`). data llm_snake_wire_contract: VariantEncoding = StringVariant { naming: SnakeCase } diff --git a/dsl/extdeps/llm/mock_corpus.dag b/dsl/extdeps/llm/mock_corpus.dag index 2ff70ac33b8..88eb028b60d 100644 --- a/dsl/extdeps/llm/mock_corpus.dag +++ b/dsl/extdeps/llm/mock_corpus.dag @@ -1,25 +1,3 @@ -// dsl/extdeps/llm/mock_corpus.dag -// Scope: the llm layer's PUBLISHED mock corpus as a closed, declared structural fact. -// Anchor: DESIGN.md §3 (single authority) / §6 (model-just-in-time, mark the carrier). -// -// SINGLE authority for WHICH llm.OpenAI / llm.Anthropic / llm.Codex / llm.Gemini operations are -// hermetically realizable. Read by BOTH the compile-time M2 mock_totality_lens -// (src/v2/lens/mock_totality.dag, via the per-layer witness) AND the v1 runtime's eval_service_call -// (the M4 hermetic-realization fold) — one model, not two. The v1 runtime loads the dsl/ tree via -// the M4.1 whole-tree corpus load (#5236), so no per-service co-location import is required. -// Modeled on the M4.0 filesystem pilot (dsl/extdeps/filesystem/mock_corpus.dag, #5188). -// -// Per-SERVICE governance spans four services across three realization homes: -// llm.OpenAI (openai_rest.dag) — REST ChatCompletion + Responses -// llm.Anthropic (anthropic_rest.dag) — REST Messages + shell CliPrompt -// llm.Codex / llm.Gemini (cli.dag) — shell CLI backends -// Every op that today carries an inline mock_response IS published below. -// -// Rows inhabit std.hermetic_replay.PublishedMockCase (all 4 fields: service, operation, -// operation_key, case_id). The operation set authority remains the service decls in -// dsl/extdeps/llm/{openai_rest,anthropic_rest,cli}.dag; per-case payloads live in the Phase-2 -// RecordedFixture store ONLY — rows carry the structural key. - module extdeps.llm.mock_corpus import std.hermetic_replay { PublishedMockCase } @@ -66,15 +44,6 @@ data llm_gemini_mock_case_cli_prompt: PublishedMockCase = PublishedMockCase { case_id: 0 } -// 🟡 gated — feature:llm-mock-corpus-from-service-decl — bind node://adhoc-55fafd83-c6d -// dissolve-on-arrival: project this corpus directly from the `service llm.*` operation sets in -// dsl/extdeps/llm/{openai_rest,anthropic_rest,cli}.dag (the SINGLE authority for WHICH operations -// exist), joined with the Phase-2 RecordedFixture store (the authority for WHICH recorded cases exist -// per operation), once a v2 lens can read a service decl's operation nodes and the fixture store's -// keys; this declared list then deletes in the same PR. forbidden: a row carrying a response VALUE -// (chat body / stdout / stderr / error shapes) — that would fork the payload authority, now owned -// by the fixture store (§3); rows mirror the structural key ONLY, and grow when a published -// operation/case is added upstream. data llm_published_mock_corpus: List = [ llm_openai_mock_case_chat_completion, llm_openai_mock_case_responses, diff --git a/dsl/extdeps/llm/openai.dag b/dsl/extdeps/llm/openai.dag index 6d328253bf5..280a55b55b0 100644 --- a/dsl/extdeps/llm/openai.dag +++ b/dsl/extdeps/llm/openai.dag @@ -1,18 +1,9 @@ -// extdeps/llm/openai.dag — OpenAI Chat Completions / Responses protocol (types + wire contracts). -// -// REST transport binding: `openai_rest.dag` (`module extdeps.llm.openai_rest`). -// Cross-provider facts: `llm.dag` (`module extdeps.llm.llm`). -// Error envelope: `openai_errors.dag`. -// module extdeps.llm.openai import extdeps.llm.llm { llm_snake_wire_contract } import std.serialization { CoproductWireContract, VariantEncoding } import std.types { NonEmptyStr } -// Wire contract: OpenAI API returns enum values as snake_case strings. -// Single authority: `extdeps.llm.llm` (`llm_snake_wire_contract`); module-local -// `wire_contract` is the per-module binding name the emitter resolves (`05_emit_rust.dag`). data wire_contract: VariantEncoding = llm_snake_wire_contract data openai_chat_message_wire_contract: CoproductWireContract = { @@ -30,8 +21,6 @@ data openai_chat_message_content_wire_contract: CoproductWireContract = { encoding: UntaggedVariant } -// -- Models -------------------------------------------------------- - type OpenAiModel = Gpt4o | Gpt4oMini @@ -56,34 +45,24 @@ data models: List = [ { model: O4Mini, model_id: "o4-mini", context_window: 200000, max_output_tokens: 100000 } ] -// -- Response format ----------------------------------------------- - type ResponseFormat = TextFormat | JsonObjectFormat | JsonSchemaFormat { schema: Json } -// -- Tool choice --------------------------------------------------- - type ToolChoice = ToolChoiceAuto | ToolChoiceNone | ToolChoiceRequired | ToolChoiceNamed { name: String } -// -- Finish reasons ------------------------------------------------ - type OpenAiFinishReason = Stop | Length | ToolCalls | ContentFilter -// -- Function calling ---------------------------------------------- - type FunctionCall { name: String arguments: String } -// OpenAI tool call: wire shape requires {"type": "function", ...}. -// Extensible registry: closed known row + Other escape (fail-open ingress). type OpenAiToolCallType = OpenAiToolCallFunction | OpenAiToolCallTypeOther { raw: NonEmptyStr } @@ -108,26 +87,8 @@ type ToolCall { function: FunctionCall } -// Roles on Chat Completions `messages[]`: system / developer / user / -// assistant / tool / function per OpenAI Chat Completions -// (https://platform.openai.com/docs/api-reference/chat/create). -// 🟢 TERMINAL provider-domain coproduct for modeled Chat Completions message -// roles. The value is projected from `OpenAiChatMessage` variant identity, not -// caller-authored as a free payload field. -// -// Request wire for this row (`messages[].role` as -// system/developer/user/assistant/tool/function) is ratcheted by pipeline tests -// in historical pipeline integration tests: -// `openai_chat_message_role_wire_matches_llm_snake_contract` (emitted serde attrs) -// and `openai_chat_message_row_json_matches_chat_completions_wire_tags` (golden JSON). type OpenAiChatMessageRole = System | Developer | User | Assistant | Tool | Function -// 🟡 SCAFFOLD provider-domain coproduct for request `messages[].content`. -// Chat Completions accepts either a scalar text string or typed content parts. -// Wire uses untagged string-or-array alternatives via -// `openai_chat_message_content_wire_contract`; `OpenAiChatMessagePart` carries -// the tagged part rows. Trigger: split this content carrier by message role if -// OpenAI role-specific content-part legality is modeled structurally. type OpenAiChatMessageContent = OpenAiChatMessageText { text: String } | OpenAiChatMessageParts { parts: List } @@ -137,21 +98,10 @@ type OpenAiChatMessageImageUrl { detail: String? } -// 🟡 SCAFFOLD provider-domain coproduct for Chat Completions request content -// parts. Text and image_url close the original multimodal-content gap; audio, -// refusal, and file-like additive parts remain gap-carried by -// `structural_coverage_gap_openai_chat_message_additive_content_parts`. type OpenAiChatMessagePart = OpenAiChatMessageTextPart { text: String } | OpenAiChatMessageImageUrlPart { image_url: OpenAiChatMessageImageUrl } -// Chat Completions API message row. Variant identity determines the wire `role` -// discriminator; role is deliberately not a payload field, so illegal rows like -// a tool payload with `role: User` are not structurally representable. -// 🟡 SCAFFOLD provider-domain coproduct for the current Chat Completions request -// message surface. Trigger: update this carrier when OpenAI request messages -// add new role variants or when assistant/tool custom-call payloads are lifted -// out of the residual rows below. type OpenAiChatMessage = OpenAiChatMessageSystem { content: OpenAiChatMessageContent } | OpenAiChatMessageDeveloper { content: OpenAiChatMessageContent } @@ -160,9 +110,6 @@ type OpenAiChatMessage | OpenAiChatMessageTool { content: OpenAiChatMessageContent, tool_call_id: String } | OpenAiChatMessageFunction { content: String, name: String } -// Narrow 200-OK wire slice for Chat Completions (`response { 200 => … }` + serde). -// Tool calls / multimodal message bodies remain outside this carrier (same narrow -// slice as the historical `from` JSON-pointer paths). type OpenAiChatCompletion200TopLogprob { token: String bytes: List? @@ -188,9 +135,6 @@ type OpenAiChatCompletion200UrlCitation { url: String } -// 🟢 TERMINAL response annotation coproduct for Chat Completions. The current -// provider wire exposes `type = "url_citation"` with required citation -// coordinates under `url_citation`. type OpenAiChatCompletion200Annotation = UrlCitation { url_citation: OpenAiChatCompletion200UrlCitation } @@ -228,12 +172,6 @@ type OpenAiChatCompletion200Usage { prompt_tokens_details: OpenAiChatCompletion200PromptTokenDetails? } -// Chat completion **object** envelope per OpenAI Chat Completions reference -// (https://platform.openai.com/docs/api-reference/chat/object): `id`, `object`, -// `created`, `model`, `choices`, `usage`. `OpenAiChatCompletion200Message` is -// still a narrow text/refusal slice of each `choices[].message`; richer -// tool-call, multimodal, and audio surfaces remain covered by downstream -// typed-carrier closure rows. type OpenAiChatCompletion200Body { id: String object: String @@ -245,10 +183,6 @@ type OpenAiChatCompletion200Body { system_fingerprint: String? } -// Residuals outside `OpenAiChatCompletion200Body` / nested narrow slices. The -// remaining entries are variant-shaped provider surfaces: tool/function calls, -// audio, and multimodal content need coproduct modeling rather than optional -// coordinates on the current text-message carrier. data structural_coverage_gap_openai_chat_completion_200_residual: List = [ "closure:openai_chat_completion_200_residual|OpenAiChatCompletion200Message|variant_pending:tool_calls|variant_pending:function_call|variant_pending:audio|variant_pending:non_string_content|variant_pending:refusal_without_content|trigger:model response content/tool/audio coproduct surface" ] @@ -258,7 +192,6 @@ data structural_coverage_gap_openai_chat_message_additive_content_parts: List … }`). type OpenAiResponsesOutputContentType = OpenAiResponsesOutputText | OpenAiResponsesOutputContentTypeOther { raw: NonEmptyStr } @@ -295,12 +228,6 @@ fn openai_responses_output_item_type_label(kind: OpenAiResponsesOutputItemType) } } -// The operation's current projections read text-output and usage token counts, -// so this carrier models the stable message/output_text path plus token-detail -// usage rows. Refusal content, tool, reasoning-detail, error, and multimodal -// output item variants remain outside this proof-of-shape slice. `text` is -// required here so the typed 200 body cannot inhabit this projection path -// without the string field the operation declares. type OpenAiResponses200OutputContent { type: OpenAiResponsesOutputContentType text: String @@ -312,8 +239,6 @@ data structural_coverage_gap_openai_responses_200_residual: List = [ "closure:openai_responses_200_residual|OpenAiResponses200OutputItem|variant_pending:tool_calls|variant_pending:reasoning|variant_pending:error|variant_pending:multimodal_output|trigger:Responses output item coproduct surface" ] -// 🟢 TERMINAL response annotation coproduct for the direct-coordinate -// Responses `output_text.annotations[]` wire tags modeled in this narrow slice. type OpenAiResponses200Annotation = FileCitation { file_id: String, filename: String, index: Int } | UrlCitation { start_index: Int, end_index: Int, title: String, url: String } @@ -354,36 +279,3 @@ type OpenAiResponses200Body { usage: OpenAiResponses200Usage service_tier: String? } - -// -- Tests ---------------------------------------------------------- -// Commented out until the v2 parser supports `fixture` and `test` items. -// See ROADMAP.md backlog. Move to openai_test.dag when fixture lands. -// -// fixture llm_cloud_env { -// mock cloud_env.config -> { provider: "gcp", runtime: "local-dev", audience: "local-dev", project_or_account: "mock-secrets" } -// mock cloud_env.request_url -> "https://example.com/oidc" -// mock cloud_env.credential -> { token: "", source_type: "static", scheme: "bearer" } -// } -// -// test openai_chat_completion : llm_cloud_env { -// input chat_completion/prepare.provider -> "openai" -// input chat_completion/prepare.model -> "gpt-4o" -// input chat_completion/prepare.messages -> [{ role: "user", content: "Hello" }] -// mock chat_completion/execute.response -> rest_response(200, { -// choices: [{ message: { content: "Hello!" }, finish_reason: "stop" }], -// model: "gpt-4o", usage: { prompt_tokens: 10, completion_tokens: 20 } -// }) -// expect result.content is String -// } -// -// test anthropic_chat_completion : llm_cloud_env { -// input chat_completion/prepare.provider -> "anthropic" -// input chat_completion/prepare.model -> "claude-sonnet-4-20250514" -// input chat_completion/prepare.messages -> [{ role: "user", content: "Hello" }] -// mock chat_completion/execute.response -> rest_response(200, { -// content: [{ type: "text", text: "Hello! I'm Claude." }], -// model: "claude-sonnet-4-20250514", stop_reason: "end_turn", -// usage: { input_tokens: 10, output_tokens: 15 } -// }) -// expect result.content is String -// } diff --git a/dsl/extdeps/llm/openai_errors.dag b/dsl/extdeps/llm/openai_errors.dag index bdddc6ccd5f..f4455d68bff 100644 --- a/dsl/extdeps/llm/openai_errors.dag +++ b/dsl/extdeps/llm/openai_errors.dag @@ -1,12 +1,7 @@ -// extdeps/llm/openai_errors.dag -- OpenAI API error envelope shape. -// -// Spec: https://platform.openai.com/docs/guides/error-codes/api-errors - module extdeps.llm.openai_errors import std.types { NonEmptyStr } -// OpenAI API error `error.type` registry (extensible — closed cited rows + Other). type OpenAiErrorType = OpenAiInvalidRequestError | OpenAiAuthenticationError diff --git a/dsl/extdeps/llm/openai_rest.dag b/dsl/extdeps/llm/openai_rest.dag index 4c6b0a0050e..c9681c0f200 100644 --- a/dsl/extdeps/llm/openai_rest.dag +++ b/dsl/extdeps/llm/openai_rest.dag @@ -1,8 +1,3 @@ -// extdeps/llm/openai_rest.dag — OpenAI Chat Completions / Responses REST transport. -// -// Protocol types and wire contracts live in `openai.dag` (`module extdeps.llm.openai`). -// This file binds the REST handler only (DESIGN.md §3: one shape, N realization handlers). - module extdeps.llm.openai_rest import extdeps.llm.openai { @@ -13,19 +8,14 @@ import extdeps.llm.openai { } import extdeps.llm.openai_errors { OpenAiErrorShape } -// 🟡 dissolved — feature:llm-openai-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); the published corpus (extdeps.llm.mock_corpus) now governs WHICH -// llm.OpenAI ops are hermetically realizable, and the fixture store owns the payloads (§3). -// forbidden: reintroducing mock_response constants for Hermetic dispatch on these shapes. service llm.OpenAI { config { endpoint: "https://api.openai.com" auth: Bearer auth_input: api_key - // OpenAI API rate limits: varies by tier (500-3500 RPM), use conservative default + rate_limit: { requests: 500, per: minute, scope: chat } - // Retry on rate limit and server errors with exponential backoff + retry: { max_attempts: 3, backoff: exponential, retry_on: [429, 500, 502, 503] } } diff --git a/dsl/extdeps/memory.dag b/dsl/extdeps/memory.dag index 7b4bdf2389e..3554d100036 100644 --- a/dsl/extdeps/memory.dag +++ b/dsl/extdeps/memory.dag @@ -1,16 +1,9 @@ -// extdeps/memory.dag — DRAM population projections over a vendor-agnostic catalog row. -// -// This owns only the general DRAM concept; per-vendor catalog data lives in -// extdeps/memory/. A populated row carries its own catalog module, so this -// module never dispatches on an owned SKU set and never imports a vendor catalog. - module extdeps.memory import std.measure { ByteSize, byte_size, byte_size_count } import extdeps.memory.types { HostMemoryPopulation, MemoryPopulationRow } import std.types { Int } -// nominal bytes for one populated row = per-module capacity × stick count. fn memory_population_row_bytes(row: MemoryPopulationRow) -> ByteSize { byte_size( byte_size_count(row.module.capacity_bytes) * row.stick_count, diff --git a/dsl/extdeps/memory/jedec.dag b/dsl/extdeps/memory/jedec.dag index e33ec501aae..20b7344e303 100644 --- a/dsl/extdeps/memory/jedec.dag +++ b/dsl/extdeps/memory/jedec.dag @@ -1,13 +1,3 @@ -// extdeps/memory/jedec.dag — JEDEC SDRAM generation catalog (cited spec authority). -// -// Per-generation monolithic die-density ceilings and standard document ids, as -// extdeps.memory.types.JedecDdrGenerationCatalogRow values. JEDEC publishes the spec; -// it is an external dependency: it lives in extdeps/, importing the catalog SHAPE -// from extdeps/memory. extdeps/memory owns only the shape + the generation taxonomy; it does -// not carry cited JEDEC document ids or per-generation ceiling magnitudes. -// -// Dispatch lives here (DESIGN §3: product → cited catalog row → std projection). - module extdeps.memory.jedec import std.measure { byte_size } @@ -22,23 +12,18 @@ import extdeps.memory.types { dram_generation_signaling_family, } -// JESD79-4 (DDR4 SDRAM): monolithic device densities 2/4/8/16 Gbit; 16 Gbit = 2 GiB max. -// Anchor: JEDEC JESD79-4 § device density organization. data ddr4_generation_catalog: JedecDdrGenerationCatalogRow = JedecDdrGenerationCatalogRow { generation: dram_generation_ddr4, max_monolithic_die_density: byte_size(count: 2147483648), jedec_standard: "JESD79-4", } -// JESD79-5 (DDR5 SDRAM): monolithic device densities up to 64 Gbit; 64 Gbit = 8 GiB max. -// Anchor: JEDEC JESD79-5 § device density organization. data ddr5_generation_catalog: JedecDdrGenerationCatalogRow = JedecDdrGenerationCatalogRow { generation: dram_generation_ddr5, max_monolithic_die_density: byte_size(count: 8589934592), jedec_standard: "JESD79-5", } -// Fail-closed dispatch fallback: unknown generation → zero ceiling so realizability rejects. data unknown_ddr_generation_catalog: JedecDdrGenerationCatalogRow = JedecDdrGenerationCatalogRow { generation: dram_generation_unknown, max_monolithic_die_density: byte_size(count: 0), diff --git a/dsl/extdeps/memory/sk_hynix.dag b/dsl/extdeps/memory/sk_hynix.dag index d3a416eaf2c..98e129b3b08 100644 --- a/dsl/extdeps/memory/sk_hynix.dag +++ b/dsl/extdeps/memory/sk_hynix.dag @@ -1,32 +1,11 @@ -// extdeps/memory/sk_hynix.dag — SK Hynix DDR4 module catalog (vendor data authority). -// -// SK Hynix's published DDR4 modules, as extdeps.memory DramModuleCatalogRow values. -// Vendor hardware is an external dependency: it lives in extdeps/, importing the -// catalog SHAPE from extdeps/memory. extdeps/memory owns only the shape + the manufacturer -// taxonomy; it does not enumerate any one vendor's parts. Which specific modules a -// given host is populated with is an operator deployment fact (ctrl), not a fact -// about SK Hynix. -// -// Operator DIMMs: HMA82GR7AFR4N-VK 16GB PC4-21300 @ 2666 MT/s. - module extdeps.memory.sk_hynix import std.measure { ByteSize, byte_size, bit_width } import extdeps.memory.types { DramModuleCatalogRow, dram_generation_ddr4 } import extdeps.vendor.sk_hynix { sk_hynix } -// 16 GiB per stick (1×16GB, 2Gx72). The "PC4-21300" / "PC4-2666V" JEDEC class is -// data_rate_mts (2666) × 8 bytes rounded to the label — derivable, so not stored. data stick_capacity_bytes: ByteSize = byte_size(17179869184) -// HMA82GR7AFR4N-VK, decoded position-by-position from the SK Hynix DDR4 module part -// number — so each axis is a grounded fact, not a marketplace listing label: -// [H] SK Hynix · [R] 288-pin Registered DIMM (RDIMM) · [7] x72 data width (ECC) · -// [4] x4 device organization · [-VK] DDR4-2666 19-19-19 (PC4-21300). -// The two prior rows ("...server_catalog" / "...ecc_reg_single_rank_catalog") were ONE -// JEDEC part under two marketplace listings — collapsed to this single grounded row. -// Anchor: SK Hynix DDR4 module decoder DDR4MODULE_20170623.fm (MODULE TYPE / DATA -// WIDTH / ORGANIZATION / SPEED fields); rank per datasheet Rev.1.7 ordering table. data hma82gr7afr4n_vk_catalog: DramModuleCatalogRow = DramModuleCatalogRow { part_number: "HMA82GR7AFR4N-VK", manufacturer: sk_hynix, @@ -36,10 +15,6 @@ data hma82gr7afr4n_vk_catalog: DramModuleCatalogRow = DramModuleCatalogRow { ecc: true, buffering: Registered, chip_width: bit_width(4), - // rank is NOT a part-number field — derived from the SK Hynix datasheet ordering - // table (16GB x4 = 1R) and CONFIRMED on live hardware 2026-06-17: - // sudo dmidecode --type 17 | grep -E 'Part Number:|Rank:' → every DIMM Rank: 1 - // on both srv1 (altrad8ud-1l2t-1) and srv2 (alstrad8d-1l2t-2), 8 sticks each. - // (Do NOT infer rank from the "...R4..." digit — that is device width x4, not rank=4.) + rank_count: 1, } diff --git a/dsl/extdeps/memory/types.dag b/dsl/extdeps/memory/types.dag index a20762baffa..72670f69293 100644 --- a/dsl/extdeps/memory/types.dag +++ b/dsl/extdeps/memory/types.dag @@ -1,10 +1,3 @@ -// extdeps/memory/types.dag — DRAM module taxonomy (shared types, no vendor data). -// -// DRAM is a hardware domain model, not a universal framework, so it lives downstream -// of std (extdeps), alongside the per-vendor catalog rows that inhabit this shape -// (extdeps/memory/.dag). std owns only the universal frameworks it builds on -// (measure, types). - module extdeps.memory.types import std.measure { ByteSize, BitWidth, byte_size_count, bit_width, bit_width_count } @@ -22,25 +15,14 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// SdramSignalingFamily — the SDRAM clock/signaling technology. DoubleDataRate is the DDR -// family (data transferred on both clock edges). A closed enum because SDR vs DDR vs LPDDR -// are genuinely categorical signaling regimes — not a magnitude. -// Anchor: JEDEC — "DDR" = double data rate (the signaling property the generation number -// qualifies: DDR4 = double-data-rate generation 4). type SdramSignalingFamily = | DoubleDataRate -// DramGeneration — decomposed SDRAM generation axis: signaling family × generation number. -// "DDR4" is NOT an opaque enum token — it is DoubleDataRate × 4, reusing the cardinal-Int -// pattern (like rank_count, CpuModelCatalogRow.cores) rather than minting Ddr4/Ddr5 variants -// that re-coin the magnitude the marketing label already names (§2 failed-decomposition). type DramGeneration { signaling_family: SdramSignalingFamily - // generation_number — the JEDEC ordinal in "DDR" (4, 5, …), as a grounded cardinal Int - // so derivations and cited-ceiling dispatch key on the magnitude directly. + generation_number: Int } -// Canonical DoubleDataRate generation rows — the magnitude lives once, not per-SKU enum tags. data dram_generation_ddr4: DramGeneration = DramGeneration { signaling_family: DoubleDataRate, generation_number: 4, @@ -50,7 +32,6 @@ data dram_generation_ddr5: DramGeneration = DramGeneration { generation_number: 5, } -// Fail-closed sentinel for uncited generations (dispatch fallback in extdeps/memory/jedec). data dram_generation_unknown: DramGeneration = DramGeneration { signaling_family: DoubleDataRate, generation_number: 0, @@ -68,130 +49,48 @@ fn dram_generation_signaling_family(gen: DramGeneration) -> SdramSignalingFamily gen.signaling_family } -// JedecDdrGenerationCatalogRow — the cited JEDEC standard row for one SDRAM generation. -// extdeps/memory owns the SHAPE; the per-generation ceilings and standard ids live in -// extdeps/memory/jedec (DESIGN §3: single authority — the spec is external, not re-coined). type JedecDdrGenerationCatalogRow { generation: DramGeneration - // max_monolithic_die_density — largest per-die DATA capacity a single monolithic DRAM device - // can have under this generation's JEDEC standard (bytes — the module taxonomy's native - // unit; datasheets quote density in bits but capacity_bytes and this ceiling are both bytes). + max_monolithic_die_density: ByteSize - // jedec_standard — the cited JEDEC document id (e.g. JESD79-4 for DDR4 SDRAM). + jedec_standard: NonEmptyStr } -// DimmBuffering — the command/address path between the host and the DRAM devices. -// Unbuffered (UDIMM) drives the DRAM directly; Registered (RDIMM) buffers the -// command/address lines through a register; Load-Reduced (LRDIMM) additionally -// buffers the data path. This is the buffering AXIS — electrical-loading-ceiling vs -// latency/power — one of three independent module trade-offs (with chip width and -// rank count). A bare `registered: Bool` could not tell RDIMM from LRDIMM (both are -// "registered"), so the axis is a closed enum, not a flag. -// Anchor: https://en.wikipedia.org/wiki/Registered_memory (RDIMM vs LRDIMM) type DimmBuffering = Unbuffered | Registered | LoadReduced -// A populated DIMM identifies itself by its catalog row — this owns the SHAPE; the -// manufacturer is the single Vendor authority (extdeps/vendor/) and the -// per-vendor rows live in extdeps/memory/. -// No enum of one vendor's SKUs (that would make the taxonomy a purchase -// order). One JEDEC part is ONE catalog row regardless of how many marketplace -// listings sell it: the row decomposes the part number into grounded axes. The two -// numeric organization axes carry their MAGNITUDE (not an opaque enum token) so -// derivations compute on them directly. Two DISTINCT per-rank device counts (conflating them -// is the §2 state-space trap): PHYSICAL dram_chips_per_rank = 72 / chip_width bits (incl ECC — -// the power divisor) vs DATA dram_data_chips_per_rank = 64 / chip_width bits (excl ECC — the -// capacity/die-density divisor, since marketed capacity_bytes does not count ECC silicon): -// capacity = die_density × dram_data_chips_per_rank × rank_count. type DramModuleCatalogRow { part_number: NonEmptyStr manufacturer: Vendor - // generation — decomposed SDRAM generation (signaling family × ordinal), not a stringly - // "DDR4" label or opaque enum that re-coins the magnitude. + generation: DramGeneration - // DERIVE-TRIGGER(P-CF-DIMM-CAPACITY): capacity_bytes stays stored until die_density - // is confirmed live (SPD) and a `derive_capacity_bytes` fn lands in extdeps.memory with - // a +/- claim — then capacity = die_density × (64 / bit_width_count(chip_width)) × - // rank_count (DATA chips only — marketed capacity excludes ECC silicon; see - // dram_data_chips_per_rank) and memory.dag's reader calls it. A PN-certain stored 16GB beats - // an inferred-die-density derivation today (fail-closed, §5). + capacity_bytes: ByteSize data_rate_mts: Int ecc: Bool - // buffering — command/address path (UDIMM/RDIMM/LRDIMM). A categorical axis with no - // magnitude, and a Bool could not tell RDIMM from LRDIMM, so it is a closed enum. + buffering: DimmBuffering - // chip_width — the "xN" DRAM device data width as a grounded BIT-WIDTH (x4 = 4 bits), - // reusing std.measure.BitWidth rather than minting a fresh enum (§2: map onto the - // concept that already exists). The power-vs-chipkill axis; NOT a rank count (the - // "...R4..." misread). Magnitude lets chips_per_rank = 72 / bit_width_count(chip_width). + chip_width: BitWidth - // rank_count — number of independently chip-selected device sets (1/2/4): the - // bandwidth-interleave-vs-electrical-loading axis, as a grounded cardinal Int (like - // CpuModelCatalogRow.cores), so interleave/capacity derivations multiply by it. - // Per-vendor part-number decode rules and live-host confirmation live in - // extdeps/memory/ — std owns only the cardinal axis shape. + rank_count: Int } -// The JEDEC DDR memory bus WORD widths — the single authority for the 64-vs-72 distinction, -// each a BitWidth (bits-in-parallel, the same width concept as chip_width — NOT a byte size). -// A rank presents 64 DATA bits in parallel to the channel; ECC adds 8 check bits → a 72-bit -// total word. Every per-rank device count AND the per-transfer byte width DERIVE from these, so -// the 64 / 72 live here ONCE rather than as scattered literals (DESIGN §2/§3: one fact, one home; -// this is also the data bus width product.hardware_selection's bandwidth math reads, killing the -// duplicate raw `64` / `8 bytes` that previously appeared in two layers). data dram_data_word_width: BitWidth = bit_width(count: 64) data dram_ecc_word_width: BitWidth = bit_width(count: 72) -// dram_chips_per_rank — the PHYSICAL DRAM devices in one rank: the 72-bit ECC word spread -// across (ecc-word / device-width) devices, INCLUDING the ECC device. This is the POWER divisor -// — an ECC chip draws power, so memory_power / devices_per_stick key on it. It is NOT the -// capacity divisor (see dram_data_chips_per_rank below — capacity excludes ECC silicon). -// 🟡 all current corpus parts are ECC, so the 72-bit word is exact; generalize to a per-module -// (ecc ? 72 : 64)-bit word if a non-ECC module ever enters (its physical count is also 64/width). fn dram_chips_per_rank(module: DramModuleCatalogRow) -> Int { bit_width_count(b: dram_ecc_word_width) / bit_width_count(b: module.chip_width) } -// dram_data_chips_per_rank — the DATA DRAM devices in one rank: the 64-bit DATA word spread -// across (data-word / device-width) devices, EXCLUDING ECC. This is the CAPACITY / die-density -// divisor: capacity_bytes is the MARKETED data capacity (a 16GB part is sold as 16 GiB of -// usable memory; its ECC chips are not counted), so the per-die density implied by that -// marketed capacity divides by data devices only. Splitting this from dram_chips_per_rank -// avoids the §2 state-space trap of one name meaning two distinct device counts: dividing the -// marketed capacity by the 72-bit word would compute a non-existent die density for EVERY real -// part (a 16GB 1Rx4 → 7.11 Gibit, a die that does not exist), defeating the §5 realizability guard. fn dram_data_chips_per_rank(module: DramModuleCatalogRow) -> Int { bit_width_count(b: dram_data_word_width) / bit_width_count(b: module.chip_width) } -// REALIZABILITY (the inverse of the DERIVE-TRIGGER(P-CF-DIMM-CAPACITY) relationship above, -// capacity = die_density × dram_data_chips_per_rank × rank_count). A stored capacity_bytes only -// describes a part that can PHYSICALLY exist: the per-die capacity it implies must not exceed -// the technology's monolithic ceiling. e.g. a 32GB 1Rx8 DDR4 RDIMM would need 4 GiB (32 Gibit) -// dies but DDR4 tops out at 2 GiB (16 Gibit) monolithic — there is no such part, so a candidate -// matrix carrying it is silently scoring a non-existent SKU. This is the §5 fail-closed guard: -// reject the impossible rather than emit a plausible-but-fake winner. -// -// Per-die capacity is carried in BYTES — the module taxonomy's native unit and the ready -// std.measure ByteSize carrier — NOT bits. Datasheets quote die DENSITY in bits (a "16 Gibit -// die"), but capacity_bytes is already bytes, so the per-die figure in bytes needs NO byte↔bit -// conversion: per-die bytes = capacity_bytes / (data chips × rank), directly — the inline ×8 a -// bit-denominated density would carry is gone. The per-generation monolithic ceiling is cited in -// extdeps/memory/jedec (JESD79-4 DDR4 → 16 Gbit = 2 GiB; JESD79-5 DDR5 → 64 Gbit = 8 GiB). - -// Per-die data capacity implied by the marketed capacity: total data bytes spread across the -// part's data dies (data chips per rank × ranks). In bytes — both sides already bytes, no ×8. fn dram_module_required_die_density(module: DramModuleCatalogRow) -> ByteSize { byte_size(count: byte_size_count(b: module.capacity_bytes) / (dram_data_chips_per_rank(module: module) * module.rank_count)) } -// A module is realizable iff (a) its generation matches the cited JEDEC row and (b) its implied -// per-die capacity fits that generation's monolithic ceiling. Used by selection-time candidate -// filtering (product.hardware_selection) so a Pareto front can never contain a physically -// non-existent part. Fail-closed on generation mismatch (§5): a DDR4 module scored against a -// DDR5 ceiling would silently pass impossible SKUs. fn dram_module_is_realizable(module: DramModuleCatalogRow, jedec: JedecDdrGenerationCatalogRow) -> Bool { if !dram_generation_eq(a: module.generation, b: jedec.generation) { false diff --git a/dsl/extdeps/object_storage/content_addressed.dag b/dsl/extdeps/object_storage/content_addressed.dag index 1399aaf5208..40855c1a3cd 100644 --- a/dsl/extdeps/object_storage/content_addressed.dag +++ b/dsl/extdeps/object_storage/content_addressed.dag @@ -1,34 +1,13 @@ -// extdeps/object_storage/content_addressed.dag — Content-Addressed Storage (CAS) -// -// Spec: https://en.wikipedia.org/wiki/Object_storage#Content-addressable_storage -// Secondary: https://en.wikipedia.org/wiki/Content-addressable_storage -// Sections referenced: -// §"Content-addressable storage" — identifier = hash(content); same content → -// same identifier; read-time hash verification; write-once per identifier -// -// CAS is a specialisation of object storage where the object identifier is the -// content hash. Inhabitants: git (SHA-1/SHA-256), IPFS (multihash), Perkeep, -// BuildBuddy remote CAS. The CAS invariant — identifier = ContentHash(content) — -// is expressed via KeyDerivationClass.ContentAddressedByValue from std.cache_interface -// (no re-mint of the key-derivation authority). - module extdeps.object_storage.content_addressed import std.types { ContentHash } import std.cache_interface { KeyDerivationClass, CacheWriteSemantics } import extdeps.object_storage { ObjectContainer } -// A CAS object identifier: the content hash IS the address. -// ContentHash is the Realization carrier; hash derivation is never hand-rolled. type CasObjectId { hash: ContentHash } -// Addressing configuration for a CAS store. -// CAS invariant: key_derivation must be ContentAddressedByValue; -// write_mode must be WriteOnce (same hash → same content; no overwrite). -// These are recorded as facts (not enforced by the type system at this layer — -// parametric where-clause constraints are a future substrate-feature gate). type CasAddressingConfig { container: ObjectContainer key_derivation: KeyDerivationClass diff --git a/dsl/extdeps/object_storage/object_storage.dag b/dsl/extdeps/object_storage/object_storage.dag index 794e18f50e4..6cc7e9e478f 100644 --- a/dsl/extdeps/object_storage/object_storage.dag +++ b/dsl/extdeps/object_storage/object_storage.dag @@ -1,56 +1,32 @@ -// extdeps/object_storage/object_storage.dag — Object Storage -// -// Spec: https://en.wikipedia.org/wiki/Object_storage -// Sections referenced: -// §"Architecture" — objects = data + metadata + globally unique identifier; -// flat namespace; no in-place partial update -// §"Characteristics" — operations: create/read/delete (+ copy, list, head) -// §"Comparison" — object vs file vs block storage taxonomy - module extdeps.object_storage import std.types { NonEmptyStr } import std.measure { ByteSize } import std.cache_interface { ConsistencyModel, PersistenceLocality, AtomicityModel, ValueShape } -// Storage architecture taxonomy (Wikipedia §"Comparison with other storage types"). -// 🟢 TERMINAL — the three canonical storage architectures; closed by the Wikipedia -// taxonomy (file/block/object are the three named categories in the spec). type StorageArchitecture = FileStorage | BlockStorage | ObjectStorage -// A flat namespace grouping objects. Called "bucket" (S3/GCS), "container" -// (Azure Blob / OpenStack Swift), or "namespace" (MinIO). type ObjectContainer { name: NonEmptyStr } -// A globally unique object identifier within a container. -// In key-addressed stores this is caller-chosen. -// In content-addressed stores it is derived from the content hash (see -// content_addressed.dag, which specialises this concept). type ObjectId { value: NonEmptyStr } -// A single user-defined or system metadata attribute (Wikipedia §"Object"). type ObjectMetadataEntry { key: NonEmptyStr value: String } -// Size and metadata — the HEAD (introspection) response shape. type ObjectAttributes { size: ByteSize metadata: List } -// The six canonical operations on an object store (Wikipedia §"Characteristics": -// create/read/delete; copy and list are standard extensions; head is introspection). -// 🟢 TERMINAL — closed by the REST protocol grammar shared by all object stores -// (S3, GCS, Azure Blob, OpenStack Swift); no 7th operation is expected. type ObjectOperation = GetObject | PutObject @@ -59,8 +35,6 @@ type ObjectOperation | ListObjects | CopyObject -// Lookup outcome for a single object by identifier. -// 🟢 TERMINAL — found/not-found; closed by single-object GET semantics. type ObjectGetResult = ObjectGetFound { id: ObjectId, attributes: ObjectAttributes } | ObjectGetNotFound diff --git a/dsl/extdeps/os/macos.dag b/dsl/extdeps/os/macos.dag index e5d8a9cbe3a..8d1373e291e 100644 --- a/dsl/extdeps/os/macos.dag +++ b/dsl/extdeps/os/macos.dag @@ -1,6 +1,3 @@ -// extdeps/os/macos.dag — macOS distribution catalog (cited facts). -// Scope: macOS 15 Sequoia. - module extdeps.os.macos import std.os.types { @@ -21,13 +18,12 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// Anchor: https://developer.apple.com/documentation/macos-release-notes/macos-15-release-notes data sequoia_15_catalog: MacosDistributionCatalogRow = MacosDistributionCatalogRow { distribution: Sequoia15, release_label: "macOS 15 Sequoia", - // M5: none — cited Apple macOS 15 release-notes page documents OS/SDK, not Darwin kernel version. + darwin_version: none, - // Anchor (de-facto dev PM; Apple ships no official CLI PM): https://docs.brew.sh/ + package_manager: HomebrewDeFacto, libc: LibSystem, libc_version: none, diff --git a/dsl/extdeps/os/os.dag b/dsl/extdeps/os/os.dag index a497b4bdfb9..35cb96f0559 100644 --- a/dsl/extdeps/os/os.dag +++ b/dsl/extdeps/os/os.dag @@ -1,6 +1,3 @@ -// extdeps/os/os.dag — OS catalog dispatch hub (per-distro modules under extdeps/os/*). -// Product → cited catalog row → std.os projection (P2: dispatch lives in extdeps/, not std/). - module extdeps.os.os import extdeps.os.macos { macos_distribution_catalog_row } diff --git a/dsl/extdeps/os/ubuntu.dag b/dsl/extdeps/os/ubuntu.dag index 4da8ace4c0e..ffda5f12d74 100644 --- a/dsl/extdeps/os/ubuntu.dag +++ b/dsl/extdeps/os/ubuntu.dag @@ -1,6 +1,3 @@ -// extdeps/os/ubuntu.dag — Ubuntu distribution catalog (cited facts). -// Scope: Noble Numbat 24.04 LTS. - module extdeps.os.ubuntu import std.os.types { @@ -21,7 +18,6 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// Anchor: https://documentation.ubuntu.com/release-notes/24.04/ data noble_numbat_2404_catalog: UbuntuDistributionCatalogRow = UbuntuDistributionCatalogRow { distribution: NobleNumbat2404Lts, release_label: "24.04 LTS (Noble Numbat)", diff --git a/dsl/extdeps/os/windows.dag b/dsl/extdeps/os/windows.dag index 98a781023f8..80f9e497317 100644 --- a/dsl/extdeps/os/windows.dag +++ b/dsl/extdeps/os/windows.dag @@ -1,6 +1,3 @@ -// extdeps/os/windows.dag — Windows distribution catalog (cited facts). -// Scope: Windows 11 24H2 (OS build 26100). - module extdeps.os.windows import std.os.types { @@ -21,7 +18,6 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// Anchor: https://learn.microsoft.com/en-us/windows/release-health/windows11-release-information data windows_11_24h2_catalog: WindowsDistributionCatalogRow = WindowsDistributionCatalogRow { distribution: Windows1124H2Build26100, release_label: "24H2", diff --git a/dsl/extdeps/package_managers/apt.dag b/dsl/extdeps/package_managers/apt.dag index 05871265364..af610d7f6b7 100644 --- a/dsl/extdeps/package_managers/apt.dag +++ b/dsl/extdeps/package_managers/apt.dag @@ -1,52 +1,14 @@ -// extdeps/package_managers/apt.dag — APT package manager (Debian/Ubuntu). -// -// Spec: https://manpages.debian.org/testing/apt/apt.8.en.html -// Version: APT 2.x+ -// -// This is a STUB. APT is the package manager for Debian, Ubuntu, and -// derivatives — used by most Linux dev environments and CI runners -// (GitHub Actions ubuntu-latest). When a CLI tool can be installed -// via apt, that path is declared in CliTool.installable_via with the -// package name. -// -// What we actually depend on from apt: -// - The `apt install PACKAGE` (or `apt-get install`) command -// - System-wide install to /usr/bin (no per-user prefixes) -// - The fact that PATH defaults include /usr/bin -// - Specific packages listed below -// -// What we do NOT currently depend on: -// - Custom apt sources (third-party PPAs) -// - apt update / repository management -// - apt remove / purge workflows -// - Pinning, holds, or version policies -// -// Future: When we model apt operations programmatically (preflight -// checks, install verification, etc.), this file gains service -// declarations. - module extdeps.apt import std.types { NonEmptyStr, FilePath } -// ── Install layout ────────────────────────────────────────────────── - -// System binaries land here on Debian/Ubuntu. data apt_bin_dir: FilePath = "/usr/bin" data apt_local_bin_dir: FilePath = "/usr/local/bin" -// ── Packages we know about ────────────────────────────────────────── - -// The apt packages that install tools gunbc actually uses. -// On Debian/Ubuntu, coreutils ships in the base system — these are -// the package names you'd `apt install` if for some reason they -// weren't already present (or in minimal containers). -data package_coreutils: NonEmptyStr = "coreutils" // cp, rm, mv, ls, ... -data package_grep: NonEmptyStr = "grep" // grep, egrep, fgrep -data package_diffutils: NonEmptyStr = "diffutils" // diff, cmp, sdiff -data package_cargo: NonEmptyStr = "cargo" // cargo + rustc -data package_rustc: NonEmptyStr = "rustc" // standalone Rust compiler - -// ── Spec citations ────────────────────────────────────────────────── +data package_coreutils: NonEmptyStr = "coreutils" +data package_grep: NonEmptyStr = "grep" +data package_diffutils: NonEmptyStr = "diffutils" +data package_cargo: NonEmptyStr = "cargo" +data package_rustc: NonEmptyStr = "rustc" data apt_man_url: NonEmptyStr = "https://manpages.debian.org/testing/apt/apt.8.en.html" diff --git a/dsl/extdeps/package_managers/brew.dag b/dsl/extdeps/package_managers/brew.dag index c846f788457..90307cce618 100644 --- a/dsl/extdeps/package_managers/brew.dag +++ b/dsl/extdeps/package_managers/brew.dag @@ -1,52 +1,17 @@ -// extdeps/package_managers/brew.dag — Homebrew package manager (macOS). -// -// Spec: https://docs.brew.sh/ -// Version: Homebrew 4.x+ -// -// This is a STUB. Homebrew is the de facto package manager on macOS -// dev machines. When a CLI tool can be installed via brew, that path -// is declared in CliTool.installable_via with the formula name. -// -// What we actually depend on from brew: -// - The `brew install FORMULA` command -// - The `/opt/homebrew/bin/` install prefix (Apple Silicon) -// - The fact that homebrew puts binaries on PATH automatically -// - Specific formulae listed below (rust, coreutils, ...) -// -// What we do NOT currently depend on: -// - Custom taps (third-party repositories) -// - Cask installation (GUI applications) -// - Bottles vs source builds -// - Brew services (background daemons) -// - Bundle (Brewfile) workflows -// -// Future: When we model brew operations programmatically, this file -// gains service declarations like extdeps/rust/cargo.dag. - module extdeps.brew import std.types { NonEmptyStr, FilePath } -// ── Brew install prefixes ─────────────────────────────────────────── - -// Apple Silicon (M1+) — most modern macOS dev machines. data brew_prefix_apple_silicon: FilePath = "/opt/homebrew" data brew_bin_apple_silicon: FilePath = "/opt/homebrew/bin" -// Intel macOS — legacy but still in use. data brew_prefix_intel: FilePath = "/usr/local" data brew_bin_intel: FilePath = "/usr/local/bin" -// ── Formulae we know about ───────────────────────────────────────── - -// The Homebrew formulae that install tools gunbc actually uses. -// Adding a new tool that ships via brew = add its formula here. -data formula_rust: NonEmptyStr = "rust" // installs cargo, rustc -data formula_coreutils: NonEmptyStr = "coreutils" // GNU coreutils as g-prefixed binaries -data formula_diffutils: NonEmptyStr = "diffutils" // GNU diff as gdiff -data formula_grep: NonEmptyStr = "grep" // GNU grep as ggrep - -// ── Spec citations ────────────────────────────────────────────────── +data formula_rust: NonEmptyStr = "rust" +data formula_coreutils: NonEmptyStr = "coreutils" +data formula_diffutils: NonEmptyStr = "diffutils" +data formula_grep: NonEmptyStr = "grep" data brew_install_url: NonEmptyStr = "https://brew.sh" data brew_docs: NonEmptyStr = "https://docs.brew.sh/" diff --git a/dsl/extdeps/realization/cache_purity.dag b/dsl/extdeps/realization/cache_purity.dag index 65b6e4acf08..e779f605d21 100644 --- a/dsl/extdeps/realization/cache_purity.dag +++ b/dsl/extdeps/realization/cache_purity.dag @@ -1,46 +1,18 @@ -// extdeps/realization/cache_purity.dag — warm==cold cache-purity verdict (DESIGN §5; ROADMAP §2 P1). -// -// The §5 principle (caching-via-realization): a cache that changes a verdict is not a cache bug, -// it is a PURITY bug the cache EXPOSED. A content-keyed realization promises -// `output = f(declared key inputs)`. If an input is READ during realization but is NOT in the -// content-key, a WARM hit (addressed by the now-stale key) serves a result a fresh COLD recompute -// would no longer produce: warm != cold. So the cache IS the purity falsifier. -// -// This carrier models the falsifier's typed VERDICT: warm==cold ⟹ Pure; warm!=cold ⟹ Impure, -// LOCATED at the read-but-unkeyed axis. It is the durable artifact v2 inherits; the executable -// oracle (the realizer handler that performs the cold/warm byte comparison) is the v1 seed -// `src/v1/stage0/src/cache_purity_oracle.rs` (§7 Rust→zero). The realization it audits is the -// lone correct content-keyed realization — `resolved_graph_cache` (this directory's sibling). -// -// Relationship to extdeps.cache.key_completeness: that lens validates the DECLARE side (a cited -// key's `inputs_considered` must cover what it promises to invalidate on). This carrier is the -// RUN side — the executable oracle that catches an input which is read at realization time yet -// absent from the key. Declared-completeness and run-time-purity are the two ends of the same -// single authority (the content-key); this models the run-time end. - module extdeps.realization.cache_purity import std.types { NonEmptyStr, ContentHash, Bool } -// The located violation: under a FIXED content-key the realization output diverged, so an input -// is read-but-unkeyed. A warm hit under `content_key` serves `warm_digest`, but a fresh cold -// recompute now yields `cold_digest`; `unkeyed_axis` names the impure input (the §5 locus). type CachePurityViolation { - content_key: ContentHash // the key held FIXED across the perturbation - unkeyed_axis: NonEmptyStr // the read-but-unkeyed input — the §5 locus - warm_digest: ContentHash // what a warm cache hit serves (the cached baseline) - cold_digest: ContentHash // what a fresh cold recompute now yields + content_key: ContentHash + unkeyed_axis: NonEmptyStr + warm_digest: ContentHash + cold_digest: ContentHash } -// The warm==cold purity verdict. Pure = a hit serves exactly what cold would; Impure carries the -// located violation. No silent "warning" state — divergence is fail-closed (DESIGN §5). type CachePurityVerdict = Pure | Impure { violation: CachePurityViolation } -// The warm==cold rule. The realizer handler performs the cold/warm canonical-byte comparison and -// supplies the result (`warm_equals_cold`) plus, on divergence, the located violation naming the -// read-but-unkeyed axis. This fn fixes the verdict mapping: equal ⟹ Pure, else ⟹ Impure. fn cache_purity_verdict(warm_equals_cold: Bool, violation: CachePurityViolation) -> CachePurityVerdict { if warm_equals_cold { Pure @@ -48,7 +20,3 @@ fn cache_purity_verdict(warm_equals_cold: Bool, violation: CachePurityViolation) Impure { violation: violation } } } - -// (No `is_pure` Bool projection: that would restate the `CachePurityVerdict` coproduct as a -// predicate — the §5 predicate-dissolution anti-pattern. Consumers `match` the verdict directly -// so the located violation stays in hand on the Impure arm, never flattened to a bare Bool.) diff --git a/dsl/extdeps/realization/hermetic_fixture.dag b/dsl/extdeps/realization/hermetic_fixture.dag index 70ec90a3e1c..845dae48c63 100644 --- a/dsl/extdeps/realization/hermetic_fixture.dag +++ b/dsl/extdeps/realization/hermetic_fixture.dag @@ -1,26 +1,3 @@ -// extdeps/realization/hermetic_fixture.dag — the hermetic fixture store as TWO -// content-addressed-cache handlers of ONE kernel (DESIGN.md §2 horizontal / §3 single authority). -// -// The fixture store is forked across the two seeds: -// - v1 RecordedFixture (src/v1/stage0/src/recorded_fixture.rs): on-disk -// `{root}/{op_slug}/{input_hash}.json`, keyed by content_hash(inputs), value-verified on read. -// - v2 EffectIoFixtureStore (src/v2/extdeps/runtimes/v2_effect_io_pure.dag): in-process -// `Map`, keyed by a degenerate Symbol pin (today fail-open). -// -// They are not two concepts — they are ONE artifact kind (a wet-captured effect response, -// keyed by the content hash of the operation inputs) realized at two placements. This file -// cites both as `CacheInterfaceCatalogFacts` rows (parallel to parse_table_memo.dag / -// resolved_graph.dag), so the shared kernel (std.cache_interface) sees the fork as a -// key_derivation divergence on ONE artifact-kind family — the §3 census the M5 fold rewiring -// then closes (v1/v2 lookup folds return std.cache_interface.CacheLookupResult). -// -// MODEL-FIRST SPIKE (node://adhoc-3efc6449-ec5): these rows + the witness are additive and -// touch no load-bearing fold. The load-bearing bridge (v1 eval_service_call, v2 05_eval -// effect dispatch, recorded_fixture.rs) is escalated separately — see -// docs/plans/m5-fixture-store-consolidation.md. -// -// Authority: this module, cited in tests. Do NOT fork or duplicate. - module extdeps.realization.hermetic_fixture import extdeps.cache.types { CacheInterfaceCatalogFacts, ContentAddressed } @@ -53,19 +30,12 @@ import std.cache_interface { data hermetic_fixture_file_store_id: CacheInterfaceId = "hermetic_fixture_file_store" data hermetic_fixture_in_process_id: CacheInterfaceId = "hermetic_fixture_in_process" -// --- Handler 1: v1 RecordedFixture (on-disk, content-addressed reference) ----------- -// -// recorded_fixture.rs: input_hash = content_hash_service_inputs(op, inputs); the store -// keeps the faithful `inputs` and verifies them on lookup (collision safety → -// content_verified_on_read). WriteOnce: a re-record returning a different response for the -// same input_hash is ResponseDrift, the cache-purity oracle. Ttl: FIXTURE_FRESHNESS_SECS -// (30 days) → expiry is a loud fail-closed refusal, not a silent miss (MissIsDiagnostic). data hermetic_fixture_file_facts: CacheInterfaceCatalogFacts = { identity: hermetic_fixture_file_store_id backing_surface: "gunbc-recorded-fixture-on-disk" transport_encoding: CasContentEncoding key_derivation: { - // OUR content-addressed cache: inputs DERIVED from invalidation_triggers (no toolchain). + key_inputs: ContentAddressed overwritable: false prefix_fallback_allowed: false @@ -105,23 +75,12 @@ data hermetic_fixture_file_facts: CacheInterfaceCatalogFacts = { ] } -// --- Handler 2: v2 EffectIoFixtureStore (in-process; CONVERGED key derivation) -------- -// -// v2_effect_io_pure.dag: Map. CONVERGED (node://adhoc-7e32be31-47c): the -// locator identity is now content_hash(runtime_value_node_projection(arg)) — the SAME content -// digest authority the v1 on-disk handler keys on — so this handler is ContentAddressedByValue + -// content_verified_on_read (the content-addressed key IS the read verification: a hit means the -// reified-input digests matched). The key-derivation fork the M5 design called out is GONE; the -// remaining differences (InProcess locality, Never eviction, OverwriteAllowed) are genuine -// placement facts, not the fork. Proven BY EXECUTION in effect_io_handler_claims_test.dag -// (effect_io_pure_value_derived_key_discriminates_holds — distinct resources → distinct keys, RED -// if reverted to the constant pin) and asserted in hermetic_fixture_realization_test.dag. data hermetic_fixture_in_process_facts: CacheInterfaceCatalogFacts = { identity: hermetic_fixture_in_process_id backing_surface: "gunbc-effect-io-fixture-in-memory" transport_encoding: CasContentEncoding key_derivation: { - // OUR content-addressed cache: inputs DERIVED from invalidation_triggers (no toolchain). + key_inputs: ContentAddressed overwritable: true prefix_fallback_allowed: false diff --git a/dsl/extdeps/realization/parse_table_memo.dag b/dsl/extdeps/realization/parse_table_memo.dag index 0590ff549bd..d582eca52a0 100644 --- a/dsl/extdeps/realization/parse_table_memo.dag +++ b/dsl/extdeps/realization/parse_table_memo.dag @@ -1,7 +1,3 @@ -// extdeps/realization/parse_table_memo.dag — gunbc in-process parse-table memo (operator facts). -// -// Realization carrier for v2.compiler.parse ParseTable — dissolves hand-rolled Map threading. - module extdeps.realization.parse_table_memo import extdeps.cache.types { CacheInterfaceCatalogFacts, ContentAddressed } @@ -25,17 +21,12 @@ import std.cache_interface { data parse_table_memo_id: CacheInterfaceId = "parse_table_memo_cache" -// In-process parse memo: content-addressed (grammar_digest × token_stream_digest × position × production). -// Grammar scopes the in-process store; token_stream_digest prevents cross-source cell reuse. data parse_table_memo_facts: CacheInterfaceCatalogFacts = { identity: parse_table_memo_id backing_surface: "gunbc-parse-table-in-process" transport_encoding: CasContentEncoding key_derivation: { - // OUR content-addressed cache: inputs DERIVED from invalidation_triggers. NOTE the - // parse table depends on the PARSER (a transform): when this scaffold is wired and its - // triggers gain ToolchainChange, content_addressed_inputs auto-adds ToolchainSpec — the - // key completes BY CONSTRUCTION, no separate inputs edit (the §0 fork stays dissolved). + key_inputs: ContentAddressed overwritable: true prefix_fallback_allowed: false diff --git a/dsl/extdeps/realization/resolved_graph.dag b/dsl/extdeps/realization/resolved_graph.dag index 26da79e89df..2742bd14a4e 100644 --- a/dsl/extdeps/realization/resolved_graph.dag +++ b/dsl/extdeps/realization/resolved_graph.dag @@ -1,8 +1,3 @@ -// extdeps/realization/resolved_graph.dag — gunbc resolved-graph per-host cache (operator facts). -// -// Realization handler for v1 resolved_graph_cache.rs; cited rows graduate from -// std.cache_interface per realization.dag dissolution trigger. - module extdeps.realization.resolved_graph import extdeps.cache.types { CacheInterfaceCatalogFacts, ContentAddressed } @@ -26,7 +21,6 @@ import std.cache_interface { } import std.measure { ByteSize, byte_size } -// Operator deployment default — not a substrate literal (§3 business-policy). data resolved_graph_cache_cap_bytes: ByteSize = byte_size(count: 10737418240) data resolved_graph_cache_id: CacheInterfaceId = "resolved_graph_cache" @@ -36,14 +30,7 @@ data resolved_graph_cache_facts: CacheInterfaceCatalogFacts = { backing_surface: "gunbc-resolved-graph-per-host-cache" transport_encoding: CasContentEncoding key_derivation: { - // OUR content-addressed cache: the inputs are DERIVED from invalidation_triggers, not - // authored. Because invalidation_triggers promises ToolchainChange, the derived input - // set is [UpsertSubject, ToolchainSpec] (content_addressed_inputs) — the transform is - // keyed BY CONSTRUCTION, and declaring ToolchainChange WITHOUT keying the toolchain (or - // vice versa) is UNWRITABLE: there is no inputs field to author out of agreement. This - // dissolves the model side of the model↔realizer fork PR #5423 false-greened (a - // spec-only lens over a hand-authored list). The realizer (resolved_graph_cache.rs) - // folds the same set; the two Rust/.dag impls unify at v2/realize (subgraph-hash). + key_inputs: ContentAddressed overwritable: false prefix_fallback_allowed: false diff --git a/dsl/extdeps/realization/v1_handler.dag b/dsl/extdeps/realization/v1_handler.dag index 93bd6eedd24..8f7fbcfd1ea 100644 --- a/dsl/extdeps/realization/v1_handler.dag +++ b/dsl/extdeps/realization/v1_handler.dag @@ -1,18 +1,5 @@ -// extdeps/realization/v1_handler.dag — v1 interpreter realization handler binding (§3). -// -// Dispatch constants for peripheral realization handlers: these bind the std interface -// (RealizationMeasureEffect shape) to host-effect implementations. §3 requires -// dispatch to live in extdeps/, never in std/ (the interface must be agnostic). -// -// SCAFFOLD — v1 bootstrap seed handler (Rust shrinking toward zero, §7). -// dissolve-on: delete when v2 eval fold subsumes RealizationMeasureEffect.ObserveElapsedAtSubject. -// -// Authority: this module, cited in tests. Do NOT fork or duplicate. - module extdeps.realization.v1_handler import std.types { String } -// v1 eval_expr measurement handler ID — pins the v1 interpreter's self-time tap. -// Identity: "host:v1-interpreter.eval_expr_self_time" (the realization's dispatch key). data v1_eval_expr_measure_handler_id: String = "host:v1-interpreter.eval_expr_self_time" diff --git a/dsl/extdeps/render/ansi.dag b/dsl/extdeps/render/ansi.dag index df18b55d628..d4e34a96e0d 100644 --- a/dsl/extdeps/render/ansi.dag +++ b/dsl/extdeps/render/ansi.dag @@ -1,13 +1,3 @@ -// extdeps/render/ansi.dag — ANSI escape / SGR color realization for SemanticColor. -// -// Anchor: https://ecma-international.org/publications-and-standards/standards/ecma-48/ -// (ISO/IEC 6429 Select Graphic Rendition CSI sequences: ESC [ m) -// -// Provenance: gunb.ai/pkg/fermi/colors.go — project palette-index choices per SemanticColor. -// -// P2 split: std.symbols owns the agnostic SemanticColor concept; the cited SGR -// realization lives here. - module extdeps.render.ansi import std.symbols { SemanticColor } @@ -22,11 +12,9 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// ECMA-48 CSI framing — emitted once via emit_sgr_csi, not repeated per mapping row. data csi_esc: String = "\x1b[" data csi_end: String = "m" -// ISO 8613-6 / xterm 256-color palette index (0..255). type PaletteIndex = Int type SgrStyle @@ -62,7 +50,6 @@ fn emit_sgr_csi(style: SgrStyle) -> String { concat(concat(csi_esc, format_sgr_params(style: style)), csi_end) } -// Lookup via fold + structural == (filter+field-equality hits a v1 interpreter bug). fn ansi_code(c: SemanticColor) -> String? { fold(ansi_mappings, init: none, diff --git a/dsl/extdeps/render/ascii_glyph.dag b/dsl/extdeps/render/ascii_glyph.dag index 0372c24e68d..13a44528a58 100644 --- a/dsl/extdeps/render/ascii_glyph.dag +++ b/dsl/extdeps/render/ascii_glyph.dag @@ -1,10 +1,3 @@ -// extdeps/render/ascii_glyph.dag — ASCII-tier glyph carrier (ECMA-6 repertoire). -// -// Anchor: https://www.ecma-international.org/publications-and-standards/standards/ecma-6/ -// (ECMA-6 / ISO 646 7-bit coded character set; RFC 20 is the IETF mirror) -// -// dissolve-on: Q-Regex repertoire refinement — ASCII printable 0x20–0x7E. - module extdeps.render.ascii_glyph import extdeps.external_authority { ExternalAuthority } diff --git a/dsl/extdeps/render/emoji_glyph.dag b/dsl/extdeps/render/emoji_glyph.dag index c2415b0eaad..031b45b1377 100644 --- a/dsl/extdeps/render/emoji_glyph.dag +++ b/dsl/extdeps/render/emoji_glyph.dag @@ -1,9 +1,3 @@ -// extdeps/render/emoji_glyph.dag — Emoji-tier glyph carrier (UTS #51). -// -// Anchor: https://www.unicode.org/reports/tr51/ (UTS #51 Unicode Emoji) -// -// dissolve-on: Q-Regex UTS #51 emoji-sequence validity. - module extdeps.render.emoji_glyph import extdeps.external_authority { ExternalAuthority } diff --git a/dsl/extdeps/render/glyphs.dag b/dsl/extdeps/render/glyphs.dag index ae9e393bc35..4d0c87bd5fc 100644 --- a/dsl/extdeps/render/glyphs.dag +++ b/dsl/extdeps/render/glyphs.dag @@ -1,9 +1,3 @@ -// extdeps/render/glyphs.dag — Glyph realization table + encoding-tier dispatch. -// -// Project visual vocabulary: three-tier encodings (Emoji / Unicode / Ascii) per -// SymbolId. Dispatch lives in extdeps/, not std/ (DESIGN.md §3): std.symbols -// owns only the agnostic glyph identity vocabulary (SymbolId, Tier, SemanticColor). - module extdeps.render.glyphs import extdeps.render.ascii_glyph { ascii_glyph } @@ -18,14 +12,8 @@ type SymbolEntry { color: SemanticColor } -// --- Standard symbol set --- -// -// The canonical symbol table. Each entry maps a SymbolId to its -// three-tier visual encoding and semantic color. - data standard_symbols: List = [ - // Node lifecycle - // NOTE: emoji/unicode tiers collapsed to ASCII -- restore when tokenizer handles UTF-8 + { id: NodePending, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "[ ]"), unicode: unicode_glyph(text: "o"), ascii: ascii_glyph(text: "[ ]")), color: Dim }, { id: NodeRunning, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "[~]"), unicode: unicode_glyph(text: "O"), ascii: ascii_glyph(text: "[~]")), color: Active }, { id: NodeCompleted, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "[x]"), unicode: unicode_glyph(text: "*"), ascii: ascii_glyph(text: "[x]")), color: Success }, @@ -33,22 +21,18 @@ data standard_symbols: List = [ { id: NodeSkipped, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "[-]"), unicode: unicode_glyph(text: "o"), ascii: ascii_glyph(text: "[-]")), color: Dim }, { id: NodeIntercepted, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "[m]"), unicode: unicode_glyph(text: "<>"), ascii: ascii_glyph(text: "[m]")), color: Info }, - // Edge states { id: EdgeIdle, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "-"), unicode: unicode_glyph(text: "-"), ascii: ascii_glyph(text: "-")), color: Dim }, { id: EdgeFlowing, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "="), unicode: unicode_glyph(text: "="), ascii: ascii_glyph(text: "=")), color: Accent }, { id: EdgeDone, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "-"), unicode: unicode_glyph(text: "-"), ascii: ascii_glyph(text: "-")), color: Success }, { id: EdgeDead, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "."), unicode: unicode_glyph(text: "."), ascii: ascii_glyph(text: ".")), color: Dim }, - // DAG phases { id: DagNotStarted, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "[ ]"), unicode: unicode_glyph(text: "[ ]"), ascii: ascii_glyph(text: "[ ]")), color: Dim }, { id: DagRunning, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "[>]"), unicode: unicode_glyph(text: ">"), ascii: ascii_glyph(text: "[>]")), color: Active }, { id: DagCompleted, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "[X]"), unicode: unicode_glyph(text: "#"), ascii: ascii_glyph(text: "[X]")), color: Success }, { id: DagFailed, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "[!]"), unicode: unicode_glyph(text: "#"), ascii: ascii_glyph(text: "[!]")), color: Error }, - // Structural { id: BoundaryMarker, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "[B]"), unicode: unicode_glyph(text: "<>"), ascii: ascii_glyph(text: "[B]")), color: Info }, - // Spinners (ASCII fallback -- restore braille when tokenizer handles UTF-8) { id: Spinner0, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "|"), unicode: unicode_glyph(text: "|"), ascii: ascii_glyph(text: "|")), color: Active }, { id: Spinner1, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "/"), unicode: unicode_glyph(text: "/"), ascii: ascii_glyph(text: "/")), color: Active }, { id: Spinner2, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "-"), unicode: unicode_glyph(text: "-"), ascii: ascii_glyph(text: "-")), color: Active }, @@ -60,20 +44,17 @@ data standard_symbols: List = [ { id: Spinner8, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "|"), unicode: unicode_glyph(text: "|"), ascii: ascii_glyph(text: "|")), color: Active }, { id: Spinner9, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "/"), unicode: unicode_glyph(text: "/"), ascii: ascii_glyph(text: "/")), color: Active }, - // Status indicators { id: StatusSuccess, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "OK"), unicode: unicode_glyph(text: "v"), ascii: ascii_glyph(text: "OK")), color: Success }, { id: StatusFailure, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "FAIL"), unicode: unicode_glyph(text: "x"), ascii: ascii_glyph(text: "FAIL")), color: Error }, { id: StatusWarning, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "WARN"), unicode: unicode_glyph(text: "!"), ascii: ascii_glyph(text: "WARN")), color: Warning }, { id: StatusInfo, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "INFO"), unicode: unicode_glyph(text: "i"), ascii: ascii_glyph(text: "INFO")), color: Info }, - // Data type indicators { id: DataList, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "[L]"), unicode: unicode_glyph(text: "="), ascii: ascii_glyph(text: "[L]")), color: Default }, { id: DataMap, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "[M]"), unicode: unicode_glyph(text: "[+]"), ascii: ascii_glyph(text: "[M]")), color: Default }, { id: DataSecret, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "[*]"), unicode: unicode_glyph(text: "*"), ascii: ascii_glyph(text: "[*]")), color: Warning }, { id: DataUrl, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "[U]"), unicode: unicode_glyph(text: ">"), ascii: ascii_glyph(text: "[U]")), color: Info }, { id: DataTimer, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "[T]"), unicode: unicode_glyph(text: "[T]"), ascii: ascii_glyph(text: "[T]")), color: Dim }, - // Connectors { id: ConnectorHorizontal, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "--"), unicode: unicode_glyph(text: "--"), ascii: ascii_glyph(text: "--")), color: Dim }, { id: ConnectorVertical, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "|"), unicode: unicode_glyph(text: "|"), ascii: ascii_glyph(text: "|")), color: Dim }, { id: ConnectorTeeDown, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "+"), unicode: unicode_glyph(text: "+"), ascii: ascii_glyph(text: "+")), color: Dim }, @@ -82,7 +63,6 @@ data standard_symbols: List = [ { id: ConnectorCornerTopLeft, glyphs: glyphs_for_tiers(emoji: emoji_glyph(text: "+"), unicode: unicode_glyph(text: "+"), ascii: ascii_glyph(text: "+")), color: Dim } ] -// Lookup via fold + structural == (filter+field-equality hits a v1 interpreter bug). fn lookup_symbol_entry(id: SymbolId) -> SymbolEntry? { fold(standard_symbols, init: none, diff --git a/dsl/extdeps/render/terminal.dag b/dsl/extdeps/render/terminal.dag index 799a2b42242..583fee080e4 100644 --- a/dsl/extdeps/render/terminal.dag +++ b/dsl/extdeps/render/terminal.dag @@ -1,11 +1,3 @@ -// extdeps/render/terminal.dag — Terminal width composition over glyph realization. -// -// Anchor: https://www.unicode.org/reports/tr11/ (UAX #11 East Asian Width; sibling to std.unicode) -// -// Width-constrained frame/line composition depends on resolve_symbol (encoding-tier -// dispatch in extdeps.render.glyphs). Lives in extdeps so std.render stays -// realization-free (DESIGN.md §3). - module extdeps.render.terminal import extdeps.render.glyphs { resolve_symbol } diff --git a/dsl/extdeps/render/tier_glyphs.dag b/dsl/extdeps/render/tier_glyphs.dag index 499303425f6..24aa273c6b6 100644 --- a/dsl/extdeps/render/tier_glyphs.dag +++ b/dsl/extdeps/render/tier_glyphs.dag @@ -1,8 +1,3 @@ -// extdeps/render/tier_glyphs.dag — Total Tier→glyph product (one field per variant). -// -// Each field is a distinct encoding authority (ascii_glyph / unicode_glyph / emoji_glyph). -// Illegal states (missing/duplicate tier) are unrepresentable. - module extdeps.render.tier_glyphs import extdeps.render.ascii_glyph { AsciiGlyph, ascii_glyph_text } diff --git a/dsl/extdeps/render/unicode_glyph.dag b/dsl/extdeps/render/unicode_glyph.dag index eaee6538d8e..f07d9f02e18 100644 --- a/dsl/extdeps/render/unicode_glyph.dag +++ b/dsl/extdeps/render/unicode_glyph.dag @@ -1,11 +1,3 @@ -// extdeps/render/unicode_glyph.dag — Unicode-tier glyph carrier. -// -// Anchor: https://www.unicode.org/versions/latest/ -// (Unicode Standard — same authority as std.unicode UCD 15.x; no parallel model) -// -// dissolve-on: Q-Regex repertoire refinement — cited blocks (U+2500 Box Drawing, -// U+2800 Braille Patterns, …). - module extdeps.render.unicode_glyph import std.unicode { string_display_width } @@ -30,7 +22,6 @@ fn unicode_glyph_text(g: UnicodeGlyph) -> String { g } -// Display-width dispatch for Unicode-tier glyphs defers to std.unicode (UAX #11). fn unicode_glyph_display_width(g: UnicodeGlyph) -> Int { string_display_width(s: unicode_glyph_text(g: g)) } diff --git a/dsl/extdeps/runtime/abi/aapcs64.dag b/dsl/extdeps/runtime/abi/aapcs64.dag index 0fe92de3068..e80acc808a8 100644 --- a/dsl/extdeps/runtime/abi/aapcs64.dag +++ b/dsl/extdeps/runtime/abi/aapcs64.dag @@ -1,15 +1,3 @@ -// extdeps/runtime/abi/aapcs64.dag — AArch64 AAPCS64 ABI facts (Linux syscall subset). -// -// Scope: Slice-1 Linux aarch64 syscall register convention cited to the real kernel/AAPCS64 docs. -// Args flow x0 → x1 → x2 → x3 → x4 → x5; syscall NR in x8; return value in x0 (same register as arg0). -// -// Anchor: https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst -// (Procedure Call Standard for the ARM 64-bit Architecture — register roles / stack) -// Anchor: https://github.com/torvalds/linux/v6.8/arch/arm64/kernel/syscall.c -// (do_el0_svc: syscall number from regs->regs[8]; return via syscall_set_return_value → x0) -// Anchor: https://github.com/torvalds/linux/v6.8/include/uapi/asm-generic/unistd.h -// (Linux aarch64 syscall numbers via asm-generic unistd) - module extdeps.runtime.abi.aapcs64 import std.abi { ArchitecturalRegister, CallingConvention } @@ -25,10 +13,8 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// 🟢 terminal — cited AArch64 GPR names are irreducible spec atoms (AAPCS64 / kernel entry). type Aarch64Gpr = X0 | X1 | X2 | X3 | X4 | X5 | X8 -// Aarch64Gpr atoms inhabit ArchitecturalRegister (existential at the SyscallAbi boundary). data aarch64_inhabitant_x0: ArchitecturalRegister = X0 data aarch64_inhabitant_x1: ArchitecturalRegister = X1 data aarch64_inhabitant_x2: ArchitecturalRegister = X2 @@ -48,7 +34,6 @@ data aapcs64_linux_syscall_convention: CallingConvention = { return_value: aarch64_inhabitant_x0, } -// Falsifier stub: wrong syscall-number register (x0) — distinct from the cited convention. data aapcs64_wrong_syscall_number_convention: CallingConvention = { arg0: aarch64_inhabitant_x0, arg1: aarch64_inhabitant_x1, @@ -60,8 +45,6 @@ data aapcs64_wrong_syscall_number_convention: CallingConvention = { return_value: aarch64_inhabitant_x0, } -// Witnesses: typed+reviewed via `gunbc run --source-root dsl --claim-run` (PR receipt). -// 🟡 consumer:dsl-rooted-claim-run-gate — not CI-enrolled until swift-stag dsl corpus gate lands. fn witness_convention_arg0_identity() -> Bool { aapcs64_linux_syscall_convention.arg0 == aarch64_inhabitant_x0 } diff --git a/dsl/extdeps/runtime/abi/sysv_amd64.dag b/dsl/extdeps/runtime/abi/sysv_amd64.dag index e1de88625ab..9749939cf96 100644 --- a/dsl/extdeps/runtime/abi/sysv_amd64.dag +++ b/dsl/extdeps/runtime/abi/sysv_amd64.dag @@ -1,15 +1,3 @@ -// extdeps/runtime/abi/sysv_amd64.dag — AMD64 System V ABI facts (Linux syscall subset). -// -// Scope: Slice-1 Linux x86-64 syscall register convention cited to the real kernel/psABI docs. -// Args flow rdi → rsi → rdx → r10 → r8 → r9; syscall NR and return value in rax. The fourth -// argument uses r10 (not rcx) because SYSCALL saves rip to rcx and rflags to r11 — both clobbered. -// -// Anchor: https://refspecs.linuxfoundation.org/elf/x86_64-abi-0.99.pdf (x86-64 psABI register roles) -// Anchor: https://github.com/torvalds/linux/blob/v6.8/arch/x86/entry/entry_64.S -// (entry_SYSCALL_64 header comment: rax=nr, rdi/rsi/rdx/r10/r8/r9=args, rcx/r11 clobbered) -// Anchor: https://github.com/torvalds/linux/blob/v6.8/arch/x86/entry/syscalls/syscall_64.tbl -// (Linux x86-64 syscall number table) - module extdeps.runtime.abi.sysv_amd64 import std.abi { ArchitecturalRegister, CallingConvention } @@ -25,10 +13,8 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// 🟢 terminal — cited AMD64 GPR names are irreducible spec atoms (x86-64 psABI / kernel entry). type Amd64Gpr = Rdi | Rsi | Rdx | R10 | R8 | R9 | Rax | Rcx -// Amd64Gpr atoms inhabit ArchitecturalRegister (existential at the SyscallAbi boundary). data amd64_inhabitant_rdi: ArchitecturalRegister = Rdi data amd64_inhabitant_rsi: ArchitecturalRegister = Rsi data amd64_inhabitant_rdx: ArchitecturalRegister = Rdx @@ -49,7 +35,6 @@ data sysv_amd64_linux_syscall_convention: CallingConvention = { return_value: amd64_inhabitant_rax, } -// Falsifier stub: wrong arg3 (rcx) — distinct from the cited convention (not a second arch yet). data sysv_amd64_wrong_arg3_convention: CallingConvention = { arg0: amd64_inhabitant_rdi, arg1: amd64_inhabitant_rsi, @@ -61,8 +46,6 @@ data sysv_amd64_wrong_arg3_convention: CallingConvention = { return_value: amd64_inhabitant_rax, } -// Witnesses: typed+reviewed via `gunbc run --source-root dsl --claim-run` (PR receipt). -// 🟡 consumer:dsl-rooted-claim-run-gate — not CI-enrolled until swift-stag dsl corpus gate lands. fn witness_convention_arg3_identity() -> Bool { sysv_amd64_linux_syscall_convention.arg3 == amd64_inhabitant_r10 } diff --git a/dsl/extdeps/runtime/api/darwin.dag b/dsl/extdeps/runtime/api/darwin.dag index d6c3421de09..17e0b9b6991 100644 --- a/dsl/extdeps/runtime/api/darwin.dag +++ b/dsl/extdeps/runtime/api/darwin.dag @@ -1,12 +1,3 @@ -// extdeps/runtime/api/darwin.dag — macOS libSystem stable API boundary (cited facts). -// -// Scope: Slice-2 inhabitant of std.os.invocation.LibraryApiBoundary — POSIX-facing libSystem -// exports are the stable contract; raw Mach/Darwin syscall numbers are not a public ABI. -// -// Anchor: https://developer.apple.com/documentation/macos-release-notes/macos-15-release-notes -// Anchor: https://github.com/apple-oss-distributions/Libc/blob/main/gen/posix.defs -// Anchor: https://github.com/apple-oss-distributions/xnu/blob/main/bsd/kern/syscalls.master - module extdeps.runtime.api.darwin import std.os.invocation { @@ -51,8 +42,6 @@ data macos_15_library_api_surface: StableInvocationSurface = LibraryApiBoundaryS boundary: macos_libsystem_boundary, } -// Witnesses: typed+reviewed via `gunbc run --source-root dsl --entry … --function … --claim-run`. -// 🟡 consumer:dsl-rooted-claim-run-gate — not CI-enrolled until dsl corpus gate lands. fn witness_libsystem_read_exported() -> Bool { libsystem_read.symbol == "read" } diff --git a/dsl/extdeps/runtime/api/windows.dag b/dsl/extdeps/runtime/api/windows.dag index 0c403005818..4c65c74ab72 100644 --- a/dsl/extdeps/runtime/api/windows.dag +++ b/dsl/extdeps/runtime/api/windows.dag @@ -1,22 +1,3 @@ -// extdeps/runtime/api/windows.dag — Windows stable API boundary (cited facts). -// -// Scope: Slice-2 inhabitant of std.os.invocation.LibraryApiBoundary — the Win32/NT API is the -// stable contract; NT syscall numbers are deliberately unstable across Windows builds. -// -// Anchor: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew -// Anchor: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-readfile -// Anchor: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-writefile -// Anchor: https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-exitprocess -// Anchor: https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryw -// Anchor: https://learn.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getprocaddress -// Anchor: https://learn.microsoft.com/en-us/windows/win32/api/memoryapi/nf-memoryapi-virtualalloc -// Anchor: https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntreadfile -// Anchor: https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntwritefile -// Anchor: https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntcreatefile -// Anchor: https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntallocatevirtualmemory -// Anchor: https://learn.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntterminateprocess -// Anchor: https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/using-system-services - module extdeps.runtime.api.windows import std.os.invocation { @@ -80,7 +61,6 @@ data windows_ntdll_boundary: LibraryApiBoundary = { exports: windows_ntdll_exports, } -// Win32 user-mode stable contract spans kernel32 + ntdll exports (per-entry module names the DLL). data windows_11_user_mode_exports: List = [ kernel32_create_file_w, kernel32_read_file, @@ -100,13 +80,10 @@ data windows_11_user_mode_boundary: LibraryApiBoundary = { exports: windows_11_user_mode_exports, } -// Composite stable surface for Windows 11 — apps bind to kernel32 + ntdll, not raw syscall numbers. data windows_11_library_api_surface: StableInvocationSurface = LibraryApiBoundarySurface { boundary: windows_11_user_mode_boundary, } -// Witnesses: typed+reviewed via `gunbc run --source-root dsl --entry … --function … --claim-run`. -// 🟡 consumer:dsl-rooted-claim-run-gate — not CI-enrolled until dsl corpus gate lands. fn witness_kernel32_create_file_w_exported() -> Bool { kernel32_create_file_w.symbol == "CreateFileW" } diff --git a/dsl/extdeps/runtime/architecture/aarch64_linux.dag b/dsl/extdeps/runtime/architecture/aarch64_linux.dag index 118aac855cd..1e5cf1a438f 100644 --- a/dsl/extdeps/runtime/architecture/aarch64_linux.dag +++ b/dsl/extdeps/runtime/architecture/aarch64_linux.dag @@ -1,12 +1,3 @@ -// extdeps/runtime/architecture/aarch64_linux.dag — aarch64 Linux architecture profile (cited facts). -// -// Scope: Slice-1 inhabitant #2 of extdeps.toolchain.architecture_profile.ArchitectureProfile — Architecture::Aarch64 -// with cited machine facts, aapcs64 syscall convention, and downward stack. -// -// Anchor: https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst (§5.4.2 stack; §4.1 alignment) -// Anchor: https://github.com/torvalds/linux/v6.8/arch/arm64/include/asm/page-def.h (PAGE_SIZE via PAGE_SHIFT) -// Anchor: https://github.com/torvalds/linux/v6.8/arch/arm64/kernel/syscall.c - module extdeps.runtime.architecture.aarch64_linux import extdeps.runtime.abi.aapcs64 { @@ -66,8 +57,6 @@ data aarch64_linux_deployment_target: DeploymentTarget = { invocation: SyscallAbiSurface { abi: linux_aarch64_syscall_abi }, } -// Witnesses: typed+reviewed via `gunbc run --source-root dsl --claim-run` (PR receipt). -// 🟡 consumer:dsl-rooted-claim-run-gate — not CI-enrolled until dsl corpus gate lands. fn witness_architecture_is_aarch64() -> Bool { aarch64_linux_architecture_profile.architecture == Aarch64 } diff --git a/dsl/extdeps/runtime/architecture/x86_64_linux.dag b/dsl/extdeps/runtime/architecture/x86_64_linux.dag index bc1e2c477fd..a56170c3b2e 100644 --- a/dsl/extdeps/runtime/architecture/x86_64_linux.dag +++ b/dsl/extdeps/runtime/architecture/x86_64_linux.dag @@ -1,12 +1,3 @@ -// extdeps/runtime/architecture/x86_64_linux.dag — x86-64 Linux architecture profile (cited facts). -// -// Scope: Slice-1 inhabitant of extdeps.toolchain.architecture_profile.ArchitectureProfile — Architecture::X86_64 -// with cited machine facts, sysv_amd64 syscall convention, and downward stack. -// -// Anchor: https://refspecs.linuxfoundation.org/elf/x86_64-abi-0.99.pdf (§3.2.2 stack; §3.4.1 alignment) -// Anchor: https://github.com/torvalds/linux/blob/v6.8/arch/x86/include/asm/page_types.h (PAGE_SIZE 4096) -// Anchor: https://github.com/torvalds/linux/blob/v6.8/arch/x86/entry/entry_64.S - module extdeps.runtime.architecture.x86_64_linux import extdeps.runtime.abi.sysv_amd64 { @@ -68,8 +59,6 @@ data x86_64_linux_deployment_target: DeploymentTarget = { invocation: SyscallAbiSurface { abi: linux_x86_64_syscall_abi }, } -// Witnesses: typed+reviewed via `gunbc run --source-root dsl --claim-run` (PR receipt). -// 🟡 consumer:dsl-rooted-claim-run-gate — not CI-enrolled until dsl corpus gate lands. fn witness_architecture_is_x86_64() -> Bool { x86_64_linux_architecture_profile.architecture == X86_64 } diff --git a/dsl/extdeps/runtime/local.dag b/dsl/extdeps/runtime/local.dag index 9e43303bb4c..0380d041ab8 100644 --- a/dsl/extdeps/runtime/local.dag +++ b/dsl/extdeps/runtime/local.dag @@ -1,5 +1,3 @@ -// extdeps/runtime/local.dag -- local developer runtime facts. - module extdeps.runtime.local import std.types { NonEmptyStr } diff --git a/dsl/extdeps/runtime/syscalls/linux.dag b/dsl/extdeps/runtime/syscalls/linux.dag index c57f5bd8d51..68244a98ea1 100644 --- a/dsl/extdeps/runtime/syscalls/linux.dag +++ b/dsl/extdeps/runtime/syscalls/linux.dag @@ -1,8 +1,3 @@ -// extdeps/runtime/syscalls/linux.dag — Linux system-call surfaces (cited facts). -// Scope: Slice-1 subsets inhabiting std.os.invocation.SyscallAbi (x86-64 + aarch64). -// Anchor: https://github.com/torvalds/linux/blob/v6.8/arch/x86/entry/syscalls/syscall_64.tbl -// Anchor: https://github.com/torvalds/linux/v6.8/include/uapi/asm-generic/unistd.h - module extdeps.runtime.syscalls.linux import extdeps.runtime.abi.aapcs64 { aapcs64_linux_syscall_convention } @@ -50,8 +45,6 @@ data linux_aarch64_syscall_abi: SyscallAbi = { convention: aapcs64_linux_syscall_convention, } -// Witnesses: typed+reviewed via `gunbc run --source-root dsl --claim-run` (PR receipt). -// 🟡 consumer:dsl-rooted-claim-run-gate — not CI-enrolled until swift-stag dsl corpus gate lands. fn witness_read_number_is_0() -> Bool { sys_read.number == 0 } fn witness_write_number_is_1() -> Bool { sys_write.number == 1 } fn witness_mmap_number_is_9() -> Bool { sys_mmap.number == 9 } diff --git a/dsl/extdeps/rust/cargo.dag b/dsl/extdeps/rust/cargo.dag index d8f6c82fba4..0de65e83ab7 100644 --- a/dsl/extdeps/rust/cargo.dag +++ b/dsl/extdeps/rust/cargo.dag @@ -1,24 +1,8 @@ -// extdeps/rust/cargo.dag -- "What is Cargo?" -// -// Rust's build system and package manager: packages, targets, profiles, -// features, and command behaviors. -// -// Consumers: -// tools/clippy.dag -- clippy lint workflow -// config/build_commands.dag -- build command composition -// tools/build.dag -- build workflow - module extdeps.cargo import extdeps.cargo_version { CargoPackageVersion, CargoVersionRequirement, CargoToolVersionFloor } import std.types { FilePathParts } -// -- Edition ------------------------------------------------------- -// Rust edition is a CLOSED set (Cargo Reference: "The edition field"), not an -// arbitrary String. Single authority: this is the one place the edition values -// live — `languages/rust/imports.dag` imports `default_rust_edition` rather than -// re-coining `default_edition: String = "2021"` (that fork is the §3 violation -// this collapses). `rust_edition_str` renders the canonical manifest token. type RustEdition = Edition2015 | Edition2018 @@ -36,12 +20,8 @@ fn rust_edition_str(edition: RustEdition) -> String { data default_rust_edition: RustEdition = Edition2021 -// Minimum cargo for edition 2021 (Cargo Reference: "The edition field"). -// Pinned toolchain stays rust-toolchain.toml — this is the honest floor. data min_cargo_version: CargoToolVersionFloor = ">= 1.56" -// -- Package model ------------------------------------------------- - type CargoPackage { name: String version: CargoPackageVersion @@ -49,12 +29,6 @@ type CargoPackage { path: String } -// -- Dependencies -------------------------------------------------- -// Cargo.toml dependency entry (Cargo Reference: Specifying Dependencies). -// -// A dependency names a crate and a source. A registry dependency pins a -// version (with optional features); a path dependency points at a local -// crate directory. (Git/other sources extend this coproduct when needed.) type CargoDepSource = RegistryDep { version: CargoVersionRequirement, features: List } | LocalPathDep { path: String } @@ -64,8 +38,6 @@ type CargoDependency { source: CargoDepSource } -// -- Targets ------------------------------------------------------- - type CargoTarget = Lib | Bin { name: String } @@ -73,21 +45,6 @@ type CargoTarget | Example { name: String } | Bench { name: String } -// The per-CargoTarget DEFAULT source-file path — Cargo's target auto-discovery -// rule, modeled as DATA so the file set DERIVES from the crate model rather than -// being a hand-declared path list (DESIGN §2 deep). SINGLE AUTHORITY: this is the -// one place the target→file rule lives; the content-addressed CI gate and (later) -// the stage0_crates emitter both reuse it instead of re-coining `src/lib.rs` / -// `src/main.rs` literals. (Cargo Reference: "Package Layout" / "Target -// auto-discovery".) Returns the structured `FilePathParts` (the grounded path -// authority), not the `String` alias. -// -// Lib → src/lib.rs -// Bin{name} where name == package → src/main.rs (the package-named bin) -// Bin{name} → src/bin/{name}.rs -// CargoTest{name} → tests/{name}.rs -// Example{name} → examples/{name}.rs -// Bench{name} → benches/{name}.rs fn cargo_target_source_path(target: CargoTarget, package_name: String) -> FilePathParts { match target { Lib => FilePathParts { segments: ["src", "lib.rs"] } @@ -103,11 +60,6 @@ fn cargo_target_source_path(target: CargoTarget, package_name: String) -> FilePa } } -// A Rust module stem resolves to one of two candidate files (Cargo/rustc module -// rule): `src/{stem}.rs` OR `src/{stem}/mod.rs`. Modeled as data (the rule, not a -// resolution — which of the two exists on disk is a host read at gate time, the -// §3(b) seam). Single authority for the {mod}.rs vs {mod}/mod.rs rule that is -// today prose in `languages/rust/imports.dag`. fn rust_module_candidate_paths(stem: String) -> List { [ FilePathParts { segments: ["src", concat(stem, ".rs")] }, @@ -115,34 +67,15 @@ fn rust_module_candidate_paths(stem: String) -> List { ] } -// -- Profiles ------------------------------------------------------ -// Cargo allows arbitrary user-defined profiles in Cargo.toml -// (e.g., [profile.ci-optimized]). Use String to avoid a closed-world -// enum that cannot represent valid workspaces. - type CargoProfile = String data canonical_profiles: List = ["dev", "release", "test", "bench"] -// -- Features ------------------------------------------------------ - type CargoFeature { name: String dependencies: List } -// -- Test harness -------------------------------------------------- - type TestHarness = Harness | NoHarness -// -- Constants ----------------------------------------------------- -// (Edition default is `default_rust_edition: RustEdition` above — the single -// authority; the old `default_edition: String` lived here and was the fork.) - data default_profile: CargoProfile = "dev" - -// -- Service: shell transport wiring ----------------------------- -// The `cargo.Build` command service (build/test/clippy/doc/run) lives in -// `extdeps.cargo_build` so this pure model can be imported by the compiler -// (e.g. v1.compiler.stage0_crates) without dragging a shell-transport service -// into the bootstrap seed. The model here carries no transport. diff --git a/dsl/extdeps/rust/cargo_build.dag b/dsl/extdeps/rust/cargo_build.dag index 2eb0d2b9fde..08ededec636 100644 --- a/dsl/extdeps/rust/cargo_build.dag +++ b/dsl/extdeps/rust/cargo_build.dag @@ -1,22 +1,7 @@ -// extdeps/rust/cargo_build.dag -- the `cargo` command service (shell transport). -// -// Split out of `extdeps.cargo` (the pure Cargo model) so the model can be -// imported by compiler modules / the bootstrap seed without pulling a -// shell-transport service into the compiled set. Consumers that actually run -// cargo (e.g. tools/build.dag) import this module. -// -// §3 shape/transport/policy: argv is a faithful list-of-strings; policy flags are -// caller-supplied `List` parameters (workflow), not hardcoded literals. - module extdeps.cargo_build -// Default input values for the cargo ops below. Build references `env` in its input -// block (not yet wired into shell argv). Clippy and Test are invoked from rust_gates_ci -// and must not carry a Map input — RecordedFixture cannot serialize Map (fail-closed §5). data cargo_compile_env: Map = empty_map() -// -- Service: shell transport wiring ----------------------------- - service cargo.Build { operation Build { input { extra_args: List = [], env: Map = cargo_compile_env } @@ -39,11 +24,7 @@ service cargo.Build { stdout: String from "stdout" stderr: String from "stderr" } - // No `--features` here: the `text_lookup_work_counter` feature is a property of the - // `v1-compiler` dependency, declared in v1-compiler-tests/Cargo.toml and applied via - // cargo workspace feature-unification. Passing it on the command line at - // `-p v1-compiler-tests` scope errors ("package does not contain this feature"), so the - // gate carries only `extra_args` policy flags (same shape as Build). + transport shell { argv: ["cargo", "test", extra_args] } exit { 0 => Unit @@ -104,7 +85,7 @@ service cargo.Build { stdout: String from "stdout" stderr: String from "stderr" } - // Note: args are appended to the command by the transport layer. + transport shell { argv: ["cargo", "run", "-p", package, "--bin", bin, args] } exit { 0 => Unit diff --git a/dsl/extdeps/rust/rustup.dag b/dsl/extdeps/rust/rustup.dag index 3692ccb76d7..7c5e27fb47d 100644 --- a/dsl/extdeps/rust/rustup.dag +++ b/dsl/extdeps/rust/rustup.dag @@ -1,50 +1,11 @@ -// extdeps/rust/rustup.dag — The Rust toolchain installer. -// -// Spec: https://rust-lang.github.io/rustup/ -// Version: rustup 1.27+ (current stable as of 2026) -// -// This is a STUB. It documents the rustup-managed dependencies our -// workflows actually rely on. Cargo itself is modeled separately in -// extdeps/rust/cargo.dag — this file describes how cargo gets onto a -// system in the first place. -// -// What we actually depend on from rustup: -// - cargo binary, installed by default with the stable toolchain -// - rustc, installed by default -// - Pinned toolchain channel: **single authority** is `rust-toolchain.toml` -// `[toolchain].channel` only (this stub does not duplicate that string). -// -// What we do NOT currently depend on: -// - Extra rustup components beyond rust-toolchain.toml (rustfmt + clippy today) -// - Cross-compilation targets (gunbc only builds for the host) -// - Multiple toolchains (no toolchain switching) -// -// CI uses actions-rust-lang/setup-rust-toolchain (see .github/workflows/ci.yml), which -// reads rust-toolchain.toml. Local dev uses rust-toolchain.toml when present, else -// whatever rustup ships as stable. -// -// Future: -// When we model toolchain switching, channels, components, or -// cross-targets, this file gets full coverage. For now it's the -// dependency declaration. - module extdeps.rustup import std.types { NonEmptyStr } -// ── Channel ───────────────────────────────────────────────────────── - -// Closed set of well-known channels. Custom date-pinned channels -// (e.g., "nightly-2025-01-15") are out of scope until we need them. type RustChannel = Stable | Beta | Nightly -// ── Documented dependencies ───────────────────────────────────────── - -// Where to install rustup if missing. Used by extdeps.tools install_hint. data rustup_install_url: NonEmptyStr = "https://rustup.rs" -// Default channel we expect when "rustup default" is queried. data default_channel: RustChannel = Stable -// Rustup docs URL for reference. data rustup_docs: NonEmptyStr = "https://rust-lang.github.io/rustup/" diff --git a/dsl/extdeps/rust/version.dag b/dsl/extdeps/rust/version.dag index 17d9435441b..feca6831988 100644 --- a/dsl/extdeps/rust/version.dag +++ b/dsl/extdeps/rust/version.dag @@ -1,36 +1,15 @@ -// extdeps/rust/version.dag — Cargo version carriers (SemVer scheme + requirements). -// -// Fidelity — extdeps invariant (cite source; DESIGN.md §3): -// Spec: https://doc.rust-lang.org/cargo/reference/manifest.html -// Package version field: SemVer 2.0.0 (manifest.md#the-version-field). -// Dependency version field: semver version requirement -// (specifying-dependencies.md#specifying-dependencies) — caret/tilde/comparator -// syntax, not a bare published version. -// -// Authority: extdeps.version.semver (semver.org), not std.types.SemVer. -// -// Consumers: -// extdeps/rust/cargo.dag — `CargoPackage`, `RegistryDep` - module extdeps.cargo_version import extdeps.version.semver { SemVerIdentity, SemVerConstraint } -// Published crate version in `[package].version` (crates.io / workspace manifests). type CargoPackageVersion = SemVerIdentity -// Dependency version requirement in `[dependencies].crate = "…"`. type CargoVersionRequirement = SemVerConstraint -// Minimum supported `cargo` binary for edition/workspace policy (Cargo Reference: -// "The edition field"). Inhabits SemVerConstraint — distinct use site from -// `[dependencies]` requirements (§3 distinct facts). type CargoToolVersionFloor = SemVerConstraint where brand("CargoToolVersionFloor") -// Single authority for the stage0/bootstrap crate package version token. data default_stage0_package_version: CargoPackageVersion = "0.1.0" -// Render helpers exercised by witnesses (manifest emission reuses these tokens). fn render_cargo_package_version_field(version: CargoPackageVersion) -> String { concat("version = \"", version, "\"") } @@ -39,8 +18,6 @@ fn render_cargo_version_requirement_toml(req: CargoVersionRequirement) -> String concat("\"", req, "\"") } -// `[package]` header through default_stage0_package_version — shared by -// `stage0_crates.emit_stage0_crate_manifest` and `emit_rust.emit_cargo_toml`. fn render_cargo_package_header_prefix(name: String) -> String { concat( "[package]\nname = \"", name, "\"\n", diff --git a/dsl/extdeps/shell/credentials.dag b/dsl/extdeps/shell/credentials.dag index 642f02f27c6..4b1811dc7ca 100644 --- a/dsl/extdeps/shell/credentials.dag +++ b/dsl/extdeps/shell/credentials.dag @@ -1,25 +1,8 @@ -// extdeps/shell/credentials.dag -- Shell-backed credential materializers. -// -// The realization handler for the agnostic `std.credentials.CredentialSource.EnvVar` -// source: acquire a credential by reading the named environment variable via the host -// shell. Per DESIGN.md §3 a transport/realization handler "sits peripheral (extdeps/), -// never in the interface" — std declares the source SHAPE, this module REALIZES it. Homed -// in extdeps (not gunbc.auth) because its consumer is the extdeps layer -// (extdeps.github.auth); gunbc is downstream, so a gunbc home would invert the import arrow. - module extdeps.shell.credentials import extdeps.shell import std.types { NonEmptyStr } -// Acquire a credential from an environment variable. -// -// Simplest materialization strategy: reads the named env var and -// returns its value as a Secret. -// -// Used by service-specific credential functions that still source -// credentials from the process environment. - pattern env_credential(env_var: NonEmptyStr) -> { token: Secret } { result = shell.Env.Get(name: env_var) return { token: result.value as Secret } diff --git a/dsl/extdeps/shell/gnu_coreutils.dag b/dsl/extdeps/shell/gnu_coreutils.dag index 725d86e70c6..351b52e0b57 100644 --- a/dsl/extdeps/shell/gnu_coreutils.dag +++ b/dsl/extdeps/shell/gnu_coreutils.dag @@ -1,59 +1,16 @@ -// extdeps/shell/gnu_coreutils.dag — GNU coreutils we actually depend on. -// -// Spec: https://www.gnu.org/software/coreutils/manual/coreutils.html -// Version: GNU coreutils 8.x+ -// -// This is a STUB. It documents the specific commands and flags that -// gunbc workflows rely on, so we have a single place to record the -// honest dependency surface. We do not yet wire service operations -// here — workflows still construct command strings directly. -// -// Why coreutils, not POSIX: -// Several flags we use are GNU extensions, not POSIX: -// - grep -r (recursive) — GNU/BSD, not POSIX -// - diff -r (recursive directory) — GNU/BSD, not POSIX -// - diff --exclude=PATTERN — GNU only -// On macOS, BSD coreutils is the default; GNU coreutils is via -// `brew install coreutils` (which prefixes with `g`: ggrep, gdiff). -// The cargo-installed compiler runs inside macOS shell, so we rely -// on whatever grep/diff is on PATH first. macOS BSD diff supports -// -r and --exclude despite not being GNU. macOS BSD grep also -// supports -r and -E. -// -// Future: -// When we model service operations for these tools, this file -// gets full coverage like cargo.dag and git.dag. For now it's -// the dependency declaration. - module extdeps.gnu_coreutils import std.types { NonEmptyStr, FilePath } import extdeps.version { VersionConstraint } -// ── Documented dependencies ───────────────────────────────────────── - -// The specific grep flag combinations our workflows depend on. -// These are recorded as data so the dependency surface is queryable -// instead of buried in comments. data grep_recursive_quiet_flags: NonEmptyStr = "-rqE" data grep_recursive_numbered_flags: NonEmptyStr = "-rnE" -// The specific diff flag combinations our workflows depend on. data diff_recursive_flags: NonEmptyStr = "-r" data diff_recursive_brief_flags: NonEmptyStr = "-rq" -// Note: diff --exclude=NAME is a GNU extension, also supported by -// macOS BSD diff. We rely on it for hand_maintained_src exclusion. -// rm flags we depend on. data rm_force_recursive_flags: NonEmptyStr = "-rf" -// cp: we rely on shell glob expansion (cp PATH/*.EXT DEST/), which -// is a shell feature, not a cp feature. cp itself just copies files. - -// ── Spec citations ────────────────────────────────────────────────── - data coreutils_docs: NonEmptyStr = "https://www.gnu.org/software/coreutils/manual/coreutils.html" -// Minimum coreutils constraint for the flag semantics above. GNU coreutils -// 8.0 (2009) is well past every modern distro's base. data min_coreutils_version: VersionConstraint = ">= 8.0" diff --git a/dsl/extdeps/shell/mock_corpus.dag b/dsl/extdeps/shell/mock_corpus.dag index f46a2a88a83..fa6c304d7e4 100644 --- a/dsl/extdeps/shell/mock_corpus.dag +++ b/dsl/extdeps/shell/mock_corpus.dag @@ -1,26 +1,3 @@ -// dsl/extdeps/shell/mock_corpus.dag -// Scope: the shell layer's PUBLISHED mock corpus as a closed, declared structural fact. -// Anchor: DESIGN.md §3 (single authority) / §6 (model-just-in-time, mark the carrier). -// -// SINGLE authority for WHICH shell.* operations are hermetically realizable. Read by BOTH the -// compile-time M2 mock_totality_lens (src/v2/lens/mock_totality.dag, via the per-layer witness) -// AND the v1 runtime's eval_service_call (the M4 hermetic-realization fold) — one model, not two. -// The v1 runtime loads the dsl/ tree, so this corpus lives in dsl/ for the runtime to reach the -// SAME model the lens reads. Modeled on the M4.0 filesystem pilot -// (dsl/extdeps/filesystem/mock_corpus.dag, #5188). -// -// Per-SERVICE governance: eval_service_call splits an operation_key on its last `.`, so each of -// shell.Find / shell.Which / shell.Exec is governed independently. A service is corpus-governed -// iff it publishes at least one case; shell.Env publishes NONE here on purpose — it is already -// fail-closed fixtureless-hermetic (its mock_response was dissolved earlier) and replays via the -// RecordedFixture seam, so it stays UNgoverned by this corpus with its behavior unchanged. Every -// shell op that today carries an inline mock IS published below, so no governed op's sibling is -// silently fail-closed. -// -// Rows inhabit std.hermetic_replay.PublishedMockCase. The operation set authority remains -// dsl/extdeps/shell/shell.dag (`service shell.Find/Which/Exec`); per-case payloads live in the -// Phase-2 RecordedFixture store ONLY — rows carry the (operation_key, case_id) structural key. - module extdeps.shell.mock_corpus import std.hermetic_replay { PublishedMockCase } @@ -53,15 +30,6 @@ data shell_exec_mock_case_check: PublishedMockCase = PublishedMockCase { case_id: 0 } -// 🟡 gated — feature:shell-mock-corpus-from-service-decl — bind node://adhoc-aeaa1c56-be5 -// dissolve-on-arrival: project this corpus directly from the `service shell.*` operation sets in -// dsl/extdeps/shell/shell.dag (the SINGLE authority for WHICH operations exist), joined with the -// Phase-2 RecordedFixture store (the authority for WHICH recorded cases exist per operation), once -// a v2 lens can read a service decl's operation nodes and the fixture store's keys; this declared -// list then deletes in the same PR. forbidden: a row carrying a response VALUE (dirs/exit_success/ -// stdout/exit_code/stderr/exists) — that would fork the payload authority, now owned by the -// fixture store (§3); rows mirror the (operation_key, case_id) structural key ONLY, and grow when -// a published operation/case is added upstream. data shell_published_mock_corpus: List = [ shell_find_mock_case_list_dirs, shell_which_mock_case_check, diff --git a/dsl/extdeps/shell/shell.dag b/dsl/extdeps/shell/shell.dag index 50517f1260b..c717cca43ae 100644 --- a/dsl/extdeps/shell/shell.dag +++ b/dsl/extdeps/shell/shell.dag @@ -1,27 +1,7 @@ -// extdeps/shell/shell.dag -- Host shell utilities (POSIX utilities + bash-compatible Exec). -// -// find, printenv: POSIX.1 utilities. -// which: common extension (not POSIX; POSIX uses `command -v`). -// Exec: `sh -c` — POSIX subprocess. (Formerly `sh -lc`; login shell dropped CI PATH.) -// -// These are facts about the host OS, not about any specific -// external service. -// -// Consumers: -// tools/bootstrap.dag -- find directories -// tools/clippy.dag -- which command -// tools/deps.dag -- run install scripts, check commands - module extdeps.shell import std.types { FilePath, NonEmptyStr } -// 🟡 dissolved — feature:shell-mock-response — scaffold:hand-authored mock_response — -// dissolve-on-arrival: Phase-2-hermetic RecordedFixture replay from claim_batch --fixture-store -// (recorded wet via --record); extdeps.shell.mock_corpus (whole-tree loaded by M4.1) governs WHICH -// shell.* ops are hermetically realizable, and the fixture store owns the payloads (§3). forbidden: -// reintroducing mock_response constants for Hermetic dispatch on these shapes. (shell.Env already -// dissolved its mock earlier — same target end-state.) service shell.Find { operation ListDirs { input { path: FilePath, max_depth: Int = 1, min_depth: Int = 1 } @@ -45,9 +25,7 @@ service shell.Env { 0 => Unit 1 => Unit "Variable not set" } - // 🟡 dissolved — feature:env-mock-response — dissolve-on-arrival: Phase-2-hermetic - // RecordedFixture replay from claim_batch --fixture-store; forbidden: reintroducing - // mock_response for Hermetic dispatch on this shape. + } } @@ -67,19 +45,14 @@ service shell.Which { service shell.Exec { operation Run { input { script: String } - // exit_code is the actual subprocess exit code (0 = success, 1, 2, ...). - // success is the convenience bool (exit_code == 0). Workflows that - // need tri-state semantics (grep: 0=match, 1=no-match, 2=error; - // diff: 0=same, 1=different, 2=error) match on exit_code, not success. + output { exit_code: Int from "exit_code" success: Bool from "exit_success" stdout: String from "stdout" stderr: String from "stderr" } - // Use `sh -c` (not `-lc`): login shells reset PATH on CI runners and break - // nested floor gates when the parent process already inherited GITHUB_ENV - // (cargo/rustup). `-c` preserves the interpreter's environment. + transport shell { argv: ["sh", "-c", "{script}"] } exit { 0 => Unit @@ -91,7 +64,7 @@ service shell.Exec { input { command: String } output { exists: Bool from "exit_success" } readonly - // `-l`: login-shell flag (bash/zsh); not POSIX sh — see file header. + transport shell { argv: ["sh", "-c", "{command}"] } exit { 0 => Unit diff --git a/dsl/extdeps/sql/migration.dag b/dsl/extdeps/sql/migration.dag index 0ef8955def2..d90e23c3833 100644 --- a/dsl/extdeps/sql/migration.dag +++ b/dsl/extdeps/sql/migration.dag @@ -1,22 +1,5 @@ -// extdeps/sql/migration.dag -- SQL migration emission target surface. -// -// Specs: -// ISO/IEC 9075 SQL overview -// https://www.iso.org/standard/76583.html -// PostgreSQL transactional DDL behavior -// https://www.postgresql.org/docs/current/sql-commands.html -// SQLite ALTER TABLE behavior -// https://www.sqlite.org/lang_altertable.html -// -// Ctrl-Migration Phase 3 authority for generated database migration artifacts. -// This file models migration-script shape and ordering constraints; the SQL -// transport execution config remains in extdeps.transports.sql. - module extdeps.sql.migration -// Coproduct dissolution classification (DESIGN.md §2 decompress->map->reduce): -// 🟢 GREEN (terminal). Ctrl migration projections target exactly three dialect -// backends today; variants are 1:1 with externally named SQL engines. type SqlDialect = Postgres | Mysql | Sqlite fn sql_dialect_wire_label(dialect: SqlDialect) -> String { @@ -27,10 +10,6 @@ fn sql_dialect_wire_label(dialect: SqlDialect) -> String { } } -// Coproduct dissolution classification: -// GREEN (terminal). Migration operations have distinct externally visible -// schema effects and rollback constraints. Keeping them as variants preserves -// the operation class without requiring SQL string inspection downstream. type SqlMigrationOperationKind = CreateTable | AlterTable @@ -39,11 +18,7 @@ type SqlMigrationOperationKind | DropIndex | AddColumn | DropColumn - // YELLOW scaffold. This variant is only for dialect-specific DDL that cannot - // yet be represented by the bounded operation variants above. Consumers must - // carry the `dialect` field on `SqlMigrationStep`; dissolve this variant once - // the first ctrl migration projection identifies the missing structural - // operation kind and adds it here. + | RawSqlStep type SqlMigrationStep { @@ -60,9 +35,6 @@ type SqlMigrationScript { steps: List } -// STAGED. This target is consumed by ctrl subsystem projections before any -// generated migration becomes authority over the current TypeScript-backed DB -// behavior. type SqlMigrationEmissionTarget { database_name: String migrations: List diff --git a/dsl/extdeps/test/http_pilot.dag b/dsl/extdeps/test/http_pilot.dag index f64974902ae..26e34bce1d5 100644 --- a/dsl/extdeps/test/http_pilot.dag +++ b/dsl/extdeps/test/http_pilot.dag @@ -1,11 +1,3 @@ -// extdeps/test/http_pilot.dag -- REST hermetic pilot (P4b M1). -// -// Spec: JSONPlaceholder posts API (public test HTTP, no auth) -// https://jsonplaceholder.typicode.com/posts -// -// Wet path: live GET via dispatch_rest (ureq). Hermetic path: RecordedFixture -// replay only — inline mock_response dissolved (forbidden to reintroduce). - module extdeps.test.http_pilot type HttpPilotPost { @@ -34,8 +26,6 @@ service test.HttpPilot { response { 200 => HttpPilotPost } - // 🟡 dissolved — feature:http-pilot-mock-response — dissolve-on-arrival: Phase-2-hermetic - // RecordedFixture replay from claim_batch --fixture-store (recorded wet via --record); - // forbidden: reintroducing mock_response for Hermetic dispatch on this shape. + } } diff --git a/dsl/extdeps/test/mock_corpus.dag b/dsl/extdeps/test/mock_corpus.dag index 4e3f4958c07..167b7a4b77c 100644 --- a/dsl/extdeps/test/mock_corpus.dag +++ b/dsl/extdeps/test/mock_corpus.dag @@ -1,19 +1,3 @@ -// dsl/extdeps/test/mock_corpus.dag -// Scope: the REST http_pilot layer's PUBLISHED mock corpus as a closed structural fact. -// Anchor: DESIGN.md §3 (single authority) / §6 (model-just-in-time, mark the carrier). -// -// SINGLE authority for WHICH http_pilot operations are hermetically realizable. Read by BOTH the -// compile-time M2 mock_totality_lens (src/v2/lens/mock_totality.dag) AND the v1 runtime's -// eval_service_call (the M4 hermetic-realization fold) — one model, not two. The v1 runtime loads -// the dsl/ tree, so this corpus must live in dsl/ for the runtime to reach the SAME model the lens -// reads; the v2 mirror (src/v2/extdeps/test/mock_corpus.dag) is dissolved by this PR. The v2 -// lens imports this dsl module directly — cross-tree v2->dsl import is the EXISTING pattern (cf. -// filesystem / git / shell mock corpora). -// -// Rows inhabit std.hermetic_replay.PublishedMockCase. The operation set authority remains -// dsl/extdeps/test/http_pilot.dag (`service test.HttpPilot`); per-case payloads live in the -// Phase-2 RecordedFixture store ONLY — rows carry the (operation_key, case_id) structural key. - module extdeps.test.mock_corpus import std.hermetic_replay { PublishedMockCase } @@ -25,13 +9,6 @@ data http_pilot_mock_case_get_post: PublishedMockCase = PublishedMockCase { case_id: 0 } -// 🟡 gated — feature:http-pilot-mock-corpus-from-service-decl — bind node://adhoc-3dfa917b-5f9 -// dissolve-on-arrival: project this corpus directly from the `service test.HttpPilot` operation set -// in dsl/extdeps/test/http_pilot.dag, joined with the Phase-2 RecordedFixture store (the authority -// for WHICH recorded cases exist per operation), once a v2 lens can read a service decl's operation -// nodes and the fixture store's keys; this declared list then deletes in the same PR. forbidden: a -// row carrying a response VALUE — that would fork the payload authority, now owned by the fixture -// store (§3); rows mirror the (operation_key, case_id) structural key ONLY. data http_pilot_published_mock_corpus: List = [ http_pilot_mock_case_get_post ] diff --git a/dsl/extdeps/toolchain/architecture_profile.dag b/dsl/extdeps/toolchain/architecture_profile.dag index 47d0473cf41..58c1bd6bb52 100644 --- a/dsl/extdeps/toolchain/architecture_profile.dag +++ b/dsl/extdeps/toolchain/architecture_profile.dag @@ -1,12 +1,3 @@ -// extdeps/toolchain/architecture_profile.dag — arch + ABI substrate for the §10 execution-contract layer. -// -// Scope: cited machine facts + CallingConvention + StackLayout — the arch-specific execution -// substrate before format and invocation-surface composition (exec-contract §4). -// M9: `architecture` attaches to extdeps.toolchain.types.Architecture (no parallel arch notion). -// Per-arch cited inhabitants live in extdeps/runtime/architecture/*.dag (M3). -// -// Lives in extdeps/toolchain (not std) — std must not import extdeps (DESIGN §3 layer DAG). - module extdeps.toolchain.architecture_profile import extdeps.toolchain.types { Architecture } @@ -14,13 +5,11 @@ import std.abi { ArchitecturalRegister, CallingConvention, StackLayout } import std.measure { BitWidth, ByteSize } import std.os.invocation { StableInvocationSurface } -// 🟢 TERMINAL coproduct — irreducible machine byte-order distinction (little vs big endian). type Endianness = LittleEndian | BigEndian type ArchitectureProfile { architecture: Architecture - // 🟡 feature:L-8-fixed-width-words — bind os-exec-contract-layer L-8 — dissolve-on: enforced - // fixed-width word carriers in std.bit replace Measure width fields. + word_width: BitWidth pointer_width: BitWidth endianness: Endianness @@ -31,8 +20,6 @@ type ArchitectureProfile { stack_layout: StackLayout } -// DeploymentTarget composes profile + invocation surface (zesty ruling §5). -// operating_system attach is 🟡-gated on std.os.types v2 catalog flip (Option + single-variant enum). type DeploymentTarget { profile: ArchitectureProfile invocation: StableInvocationSurface diff --git a/dsl/extdeps/toolchain/types.dag b/dsl/extdeps/toolchain/types.dag index 04d3cd65852..42075738842 100644 --- a/dsl/extdeps/toolchain/types.dag +++ b/dsl/extdeps/toolchain/types.dag @@ -1,12 +1,3 @@ -// extdeps/toolchain/types.dag — GNU/LLVM triple vocabulary (single Architecture authority). -// -// Toolchain target facts are domain models downstream of std, not universal frameworks. -// Dissolves former std Arch/TargetArchitecture, extdeps.cpu.types.CpuArchitecture, and -// extdeps.container.oci.types.ImageConfigArchitecture nicknames into one 11-variant axis. -// -// Anchor: https://wiki.debian.org/ArchitectureSpecificsMemo -// Anchor: https://clang.llvm.org/docs/CrossCompilation.html#target-triple - module extdeps.toolchain.types import std.types { String } @@ -21,10 +12,8 @@ data extdeps_external_authority_anchor: ExternalAuthority = ExternalAuthority { } } -// Single ISA authority — hardware cpu rows, OCI GOARCH wire, and target triples share this axis. type Architecture = X86_64 | X86 | Aarch64 | Arm | Armv7 | Mips | Mipsel | Mips64 | Mips64el | Riscv64 | Wasm32 -// Triple vendor axis (renamed from std.types.Vendor — distinct from extdeps.vendor.Vendor). type TripleVendor = UnknownVendor | Pc | Apple | W64 type Os = Linux | Macos | Windows | Freebsd | Android | Ios | Wasi type AbiEnv = NoneAbi | Gnu | GnuEabi | GnuEabihf | Musl | Msvc | AndroidAbi | Eabi | Eabihf diff --git a/dsl/extdeps/tools/tools.dag b/dsl/extdeps/tools/tools.dag index 543e700fc8a..7c1187d0ab4 100644 --- a/dsl/extdeps/tools/tools.dag +++ b/dsl/extdeps/tools/tools.dag @@ -1,24 +1,3 @@ -// extdeps/tools/tools.dag — Holistic CLI tool modeling. -// -// Every .dag program that shells out depends on external CLI binaries -// (cargo, grep, diff, cp, ...). This file models those binaries as -// explicit declared facts with install sources, and provides a -// fail-closed upsert that resolves tool → absolute path via `which`. -// -// Each tool can be installed via multiple paths (rustup OR brew OR -// apt OR system) — installable_via is a list, not a single value. -// This is honest: the same tool reaches different developers via -// different package managers depending on platform. The resolver -// doesn't care which one was used; it just runs `which`. The list -// is for install hints when the tool is missing, and for documenting -// the supported environments. -// -// Faithful modeling (DESIGN.md §3): every InstallSource variant -// references a proper extdeps file. Adding a new variant requires -// modeling the install source first. -// -// Pattern reference: gunb.ai/tools/toolpaths/toolpaths.go (Ensure upsert). - module extdeps.tools import std.types { FilePath, NonEmptyStr } @@ -29,54 +8,27 @@ import extdeps.brew { brew_install_url } import extdeps.apt import extdeps.version { VersionConstraint } -// ── Install source ────────────────────────────────────────────────── - -// Closed set of install paths. Each variant references its backing -// extdeps file. Adding a new variant means modeling that source first. -// -// SourceCoreutils → extdeps/shell/gnu_coreutils.dag (cp, rm, grep, diff, ...) -// SourceRustup → extdeps/rust/rustup.dag (cargo, rustc) -// SourceBrew → extdeps/package_managers/brew.dag (macOS Homebrew) -// SourceApt → extdeps/package_managers/apt.dag (Debian/Ubuntu APT) type InstallSource = SourceCoreutils | SourceRustup | SourceBrew { formula: NonEmptyStr } | SourceApt { package: NonEmptyStr } -// ── Tool declaration and resolution ──────────────────────────────── - -// A required external CLI tool. installable_via is a list of all -// known install paths — the same tool reaches macOS via brew, Linux -// via apt or rustup, CI via rustup, etc. The resolver just runs -// `which` and uses whatever's first on PATH; install_hint enumerates -// all paths when the tool is missing. type CliTool { name: NonEmptyStr min_version: VersionConstraint? installable_via: List } -// A resolved tool: the declared CliTool paired with its actual absolute -// filesystem path (from `which`). Workflows build command strings from -// resolved.path, never from the bare name. type ResolvedTool { tool: CliTool path: FilePath } -// The outcome of attempting to resolve a tool. Fail-closed: if the -// tool isn't found, the hint enumerates ALL known install paths so -// the user can pick the one for their platform. type ResolveResult = Resolved { resolved: ResolvedTool } | NotFound { tool: CliTool, hint: String } -// ── Install hints ────────────────────────────────────────────────── - -// Recovery instruction for a single install source. Each variant -// references its backing extdeps file's install URL or canonical -// command form. fn one_hint(source: InstallSource) -> String { match source { SourceCoreutils => "expected from system coreutils (GNU on Linux, BSD on macOS)" @@ -86,18 +38,10 @@ fn one_hint(source: InstallSource) -> String { } } -// Enumerate ALL install paths for a tool. The user picks the one for -// their platform. Joined with " | " so the hint reads: -// "install rustup from https://rustup.rs | brew install rust | apt install cargo" fn install_hint(sources: List) -> String { sources |> map(s => one_hint(source: s)) |> join(separator: " | ") } -// ── Resolution workflow ───────────────────────────────────────────── - -// Fail-closed upsert: check if the tool is on PATH via `which`, return -// Resolved with the absolute path if found, NotFound with the -// enumerated install hint if not. func resolve(tool: CliTool) -> ResolveResult { let check = shell.Which.Check(command: tool.name) match check.path { diff --git a/dsl/extdeps/transports/fidelity.dag b/dsl/extdeps/transports/fidelity.dag index 903f9250a79..ddcc81f90cf 100644 --- a/dsl/extdeps/transports/fidelity.dag +++ b/dsl/extdeps/transports/fidelity.dag @@ -1,17 +1,3 @@ -// extdeps/transports/fidelity.dag -- Transport fidelity dispatch hub. -// -// §3 SEAM (pattern: extdeps/os/os.dag): the dispatch that selects a -// realization is itself realization, so it sits peripheral (extdeps/), never -// in the std interface. std/fidelity.dag holds the agnostic shape -// (TransportFidelity / DerivedClassification) and the dispatch-free fold -// (classify_fidelities); this file holds the per-realization catalog rows and -// the `match` over TransportClass that names them. -// -// transport_depth / transport_hermetic kept here as the realization API -// (their match bodies moved out of std). classify_transports is the -// List entry point — it dispatches each class to its cited -// fidelity row, then defers to the std fold. - module extdeps.transports.fidelity import std.types { FermiDepth } @@ -26,18 +12,10 @@ import extdeps.transports.shell { shell_transport_fidelity } import extdeps.transports.file { file_transport_fidelity } import extdeps.transports.rest { rest_transport_fidelity } -// Degenerate (non-externally-cited) transport classes have no dedicated -// transport file — their rows live with the dispatch they belong to. -// LocalDirect — in-process direct call: negligible cost, hermetic. -// InterfaceStub — test/interface stub: negligible cost, hermetic. -// Unknown — unclassified: fail-closed (max cost, non-hermetic). data local_direct_transport_fidelity: TransportFidelity = TransportFidelity { depth: Xs, hermetic: true } data interface_stub_transport_fidelity: TransportFidelity = TransportFidelity { depth: Xs, hermetic: true } data unknown_transport_fidelity: TransportFidelity = TransportFidelity { depth: Xl, hermetic: false } -// The dispatch: realization-name -> cited fidelity row. This `match` is why -// the row catalog lives here and not in std (naming a realization is -// realization; std cannot import extdeps). fn transport_fidelity(tc: TransportClass) -> TransportFidelity { match tc { LocalDirect => local_direct_transport_fidelity @@ -49,18 +27,14 @@ fn transport_fidelity(tc: TransportClass) -> TransportFidelity { } } -// Transport -> magnitude (the cost projection of the dispatched row). fn transport_depth(tc: TransportClass) -> FermiDepth { transport_fidelity(tc: tc).depth } -// Transport -> hermetic flag (the hermeticity projection of the dispatched row). fn transport_hermetic(tc: TransportClass) -> Bool { transport_fidelity(tc: tc).hermetic } -// List entry point: dispatch each class to its fidelity row, -// then defer to the std dispatch-free fold (the "big-O" max-dominates rule). fn classify_transports(transports: List) -> DerivedClassification { classify_fidelities(fidelities: map(transports, tc => transport_fidelity(tc: tc))) } diff --git a/dsl/extdeps/transports/file.dag b/dsl/extdeps/transports/file.dag index 9c92b9e8776..2d9d221dc25 100644 --- a/dsl/extdeps/transports/file.dag +++ b/dsl/extdeps/transports/file.dag @@ -1,24 +1,9 @@ -// extdeps/transports/file.dag -- Filesystem transport definition -// -// Spec: POSIX.1-2017 File I/O -// https://pubs.opengroup.org/onlinepubs/9699919799/functions/read.html -// https://pubs.opengroup.org/onlinepubs/9699919799/functions/write.html -// -// Configuration schema for service operations bound to filesystem access. -// A service operation with `transport file { ... }` executes via -// filesystem read/write at the configured path. - module extdeps.transports.file import std.fidelity { TransportFidelity } -// Fidelity row for the filesystem realization (§3: cited specifics live with -// the realization, not in std). A local read/write (POSIX.1-2017 read/write, -// no network) is sub-second and hermetic — a local-path boundary is -// deterministic and replayable without a remote dependency. data file_transport_fidelity: TransportFidelity = TransportFidelity { depth: S, hermetic: true } -// Configuration type for file transport bindings. type FileTransportConfig { - base_path: String // POSIX pathname prefix for operation paths + base_path: String } diff --git a/dsl/extdeps/transports/rest.dag b/dsl/extdeps/transports/rest.dag index fac24d2069d..65bf2fbca00 100644 --- a/dsl/extdeps/transports/rest.dag +++ b/dsl/extdeps/transports/rest.dag @@ -1,36 +1,15 @@ -// extdeps/transports/rest.dag -- HTTP REST transport definition -// -// Spec: RFC 9110 (HTTP Semantics) -// https://www.rfc-editor.org/rfc/rfc9110 -// Auth: RFC 7235 (HTTP/1.1 Authentication) -// https://www.rfc-editor.org/rfc/rfc7235 -// URI: RFC 3986 (Uniform Resource Identifier) -// https://www.rfc-editor.org/rfc/rfc3986 -// -// Configuration schema for service operations bound to REST endpoints. -// A service operation with `transport rest { ... }` executes via -// HTTP request to the configured endpoint. - module extdeps.transports.rest import std.types { HttpMethod, Url } import std.serialization { WireFormat } import std.fidelity { TransportFidelity } -// Fidelity row for the HTTP REST realization (§3: cited specifics live with -// the realization, not in std). A network round-trip (RFC 9110 over the -// network) is the large cost bucket, and it is NOT hermetic by this coarse -// classifier — fail-closed; per-op hermetic replay is proven by execution -// (record→replay witnesses), not assumed here. data rest_transport_fidelity: TransportFidelity = TransportFidelity { depth: L, hermetic: false } -// Configuration type for REST transport bindings. -// The parser validates transport blocks labeled "rest" against this schema. -// Fields match HTTP semantics from RFC 9110 and RFC 7235. type RestTransportConfig { base_url: Url - auth_token: String? // RFC 7235 Section 4.2: credentials - auth_header: String? // Header field name; default "Authorization" per RFC 7235 - headers: Map // Custom request headers (RFC 9110 Section 6.3) - response_format: WireFormat // How to parse response body; default Json + auth_token: String? + auth_header: String? + headers: Map + response_format: WireFormat } diff --git a/dsl/extdeps/transports/shell.dag b/dsl/extdeps/transports/shell.dag index e48b6037e2d..354e70a8bfd 100644 --- a/dsl/extdeps/transports/shell.dag +++ b/dsl/extdeps/transports/shell.dag @@ -1,38 +1,16 @@ -// extdeps/transports/shell.dag -- Subprocess transport definition -// -// Spec: POSIX.1-2017 Shell Command Language -// https://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html -// Exec: POSIX.1-2017 exec family -// https://pubs.opengroup.org/onlinepubs/9699919799/functions/exec.html -// -// Configuration schema for service operations bound to subprocess execution. -// A service operation with `transport shell { ... }` executes via -// subprocess invocation with captured stdout/stderr. - module extdeps.transports.shell import std.fidelity { TransportFidelity } -// Fidelity row for the shell realization (§3: cited specifics live with the -// realization, not in std). A local subprocess fork/exec is sub-second -// (POSIX.1-2017 exec family, no network) and hermetic — stdout/stderr are -// captured deterministically from a local process, replayable without a -// remote dependency. data shell_transport_fidelity: TransportFidelity = TransportFidelity { depth: S, hermetic: true } -// Process output channels (POSIX.1-2017). -// Each variant names the source a shell output field reads from. -// Output fields declare their channel via `from "VariantName"`. type ShellOutputChannel - = Stdout // fd 1 captured as String (POSIX.1-2017 Section 2.5.1) - | Stderr // fd 2 captured as String (POSIX.1-2017 Section 2.5.1) - | StdoutLines // fd 1 split by newline into List - | ExitSuccess // waitpid(2) WEXITSTATUS == 0 as Bool + = Stdout + | Stderr + | StdoutLines + | ExitSuccess -// Configuration type for shell transport bindings. -// argv is the command + arguments (POSIX.1-2017 Section 2.9.2). -// env is additional environment variables (POSIX.1-2017 Section 8.1). type ShellTransportConfig { - working_dir: String? // POSIX PWD; none = inherit from parent process - env: Map // Additional environment variables + working_dir: String? + env: Map } diff --git a/dsl/extdeps/transports/sql.dag b/dsl/extdeps/transports/sql.dag index 8cc34c9d3e1..3a41b872247 100644 --- a/dsl/extdeps/transports/sql.dag +++ b/dsl/extdeps/transports/sql.dag @@ -1,26 +1,7 @@ -// extdeps/transports/sql.dag -- SQL database transport definition -// -// Spec: ISO/IEC 9075 SQL overview -// https://www.iso.org/standard/76583.html -// SQLite bind parameters -// https://www.sqlite.org/lang_expr.html#parameters -// PostgreSQL PREPARE / EXECUTE -// https://www.postgresql.org/docs/current/sql-prepare.html -// MySQL prepared statements -// https://dev.mysql.com/doc/refman/8.4/en/sql-prepared-statements.html -// -// Configuration schema for service operations bound to relational database -// access. A service operation with `transport sql { ... }` executes a -// parameterized SQL statement through the configured database connection. - module extdeps.transports.sql import std.serialization { WireFormat } -// 🟢 TERMINAL. SQL statement classes used by common relational engines. -// These variants name the statement's externally observable behavior, not an -// emitter preference. The partition is retained because SELECT / mutation / DDL -// / transaction-control statements have distinct transport behavior. type SqlStatementKind = Select | Insert @@ -29,25 +10,18 @@ type SqlStatementKind | Ddl | TransactionControl -// 🟢 TERMINAL. Prepared statement parameter styles used by SQLite, PostgreSQL, -// and MySQL. This is a transport fact because client libraries need to render -// bind sites without turning SQL strings into target-language policy. The -// variants are externally specified marker syntaxes, not local aliases. type SqlParameterStyle - = QuestionMark // SQLite/MySQL: ? - | NumberedDollar // PostgreSQL: $1, $2, ... - | NamedColon // SQLite: :name - | NamedAt // SQLite: @name - | NamedDollar // SQLite: $name + = QuestionMark + | NumberedDollar + | NamedColon + | NamedAt + | NamedDollar -// 🟢 TERMINAL. Transaction boundary expected by an operation. These variants are -// the irreducible transport-level ownership modes for transaction scope. type SqlTransactionMode = Autocommit | ExistingTransaction | BeginCommit -// Configuration type for SQL transport bindings. type SqlTransportConfig { connection_name: String statement_kind: SqlStatementKind diff --git a/dsl/extdeps/uri.dag b/dsl/extdeps/uri.dag index e99c72a7b4e..626feedf288 100644 --- a/dsl/extdeps/uri.dag +++ b/dsl/extdeps/uri.dag @@ -1,22 +1,7 @@ -// extdeps/uri.dag — RFC 3986 URI carrier (scheme + locator). -// -// Spec anchors (intersubjective grounding — §1 A3): -// RFC 3986 URI generic syntax: https://www.rfc-editor.org/rfc/rfc3986 -// IANA URI scheme registry: https://www.rfc-editor.org/rfc/rfc7595 -// -// Uri is an extdeps concept (external authority), not std business logic. -// Carrier caveat (§3): shares the RFC3986 anchor with v2.std.network.Url; different -// layer (extdeps citation) + purpose (closed-sum scheme axis for anchor grounding). -// §6 dissolution: locator is opaque NonEmptyStr for now; fuller RFC 3986 -// authority / path / query / fragment decomposition deferred until field-level -// FactAuthorityOverride needs granular fragments (e.g. #page=12 on a PDF). - module extdeps.uri import std.types { NonEmptyStr, Url } -// Closed sum — categorical axis for URI scheme (§2). Add variants as we cite -// new IANA schemes; never string-match "https://" in lens or gate logic. type UriScheme = Http | Https @@ -28,10 +13,6 @@ type Uri { locator: NonEmptyStr } -// 🟢 TERMINAL — closed-sum membership: Http|Https vs File|Ftp (discriminating witness -// surface for the extdeps.uri carrier; scheme recognition for live anchors lives in -// scheme recognition for live anchors lives in -// v2.lens.extdeps_external_authority.decode_uri_scheme over projected constructor identity). fn uri_scheme_is_http(s: UriScheme) -> Bool { match s { Http => true @@ -41,8 +22,6 @@ fn uri_scheme_is_http(s: UriScheme) -> Bool { } } -// 🟢 TERMINAL — documents [Url] ⊂ { uri | uri_scheme_is_http(uri.scheme) } relation only; -// Url=String consumer migration is a separate follow-up. fn uri_is_url(uri: Uri) -> Bool { uri_scheme_is_http(s: uri.scheme) } diff --git a/dsl/extdeps/vendor.dag b/dsl/extdeps/vendor.dag index f25dbba104f..61b16324bbf 100644 --- a/dsl/extdeps/vendor.dag +++ b/dsl/extdeps/vendor.dag @@ -1,21 +1,3 @@ -// extdeps/vendor.dag — Vendor: a party that supplies goods or services. -// -// A vendor (supplier/seller) is an enterprise that contributes goods or services to -// another party. This is the agnostic SHAPE — generic over the DOMAIN of goods via a -// phantom type parameter, so a single Vendor concept spans every domain (a hardware -// maker is `Vendor`, a hypothetical software maker `Vendor`, …). -// The domain is a type ARGUMENT, never a forked per-domain enum — DESIGN §2 (one -// concept, every breadth) and §3 (single authority; this dissolves the former -// CpuVendor / GpuVendor / DramManufacturer fork — three name-lists for one concept). -// -// The specific companies are cited external entities, one file each, in -// extdeps/vendor/.dag — referencing a company means grounding it as a real -// upstream entity (cite the source, keep the legal name), not minting an enum nickname. -// Anchor: https://en.wikipedia.org/wiki/Vendor -// -// Identity is the cited legal name; further axes (country of incorporation, ticker, …) -// decompose here only when a consumer needs to dispatch on one (DESIGN §6). - module extdeps.vendor import std.types { NonEmptyStr } diff --git a/dsl/extdeps/vendor/amd.dag b/dsl/extdeps/vendor/amd.dag index 527741588ad..2650d5553a6 100644 --- a/dsl/extdeps/vendor/amd.dag +++ b/dsl/extdeps/vendor/amd.dag @@ -1,5 +1,3 @@ -// extdeps/vendor/amd.dag — AMD as a cited hardware-vendor entity. -// Anchor: https://en.wikipedia.org/wiki/AMD module extdeps.vendor.amd import extdeps.vendor { Vendor } diff --git a/dsl/extdeps/vendor/ampere.dag b/dsl/extdeps/vendor/ampere.dag index e9a131ccab4..d8bc51f3eb1 100644 --- a/dsl/extdeps/vendor/ampere.dag +++ b/dsl/extdeps/vendor/ampere.dag @@ -1,5 +1,3 @@ -// extdeps/vendor/ampere.dag — Ampere Computing as a cited hardware-vendor entity. -// Anchor: https://en.wikipedia.org/wiki/Ampere_Computing module extdeps.vendor.ampere import extdeps.vendor { Vendor } diff --git a/dsl/extdeps/vendor/apple.dag b/dsl/extdeps/vendor/apple.dag index 6e0e90569dc..cf5b1992edd 100644 --- a/dsl/extdeps/vendor/apple.dag +++ b/dsl/extdeps/vendor/apple.dag @@ -1,5 +1,3 @@ -// extdeps/vendor/apple.dag — Apple as a cited hardware-vendor entity. -// Anchor: https://en.wikipedia.org/wiki/Apple_Inc. module extdeps.vendor.apple import extdeps.vendor { Vendor } diff --git a/dsl/extdeps/vendor/arm.dag b/dsl/extdeps/vendor/arm.dag index ef7b93ff1ee..604efaaa80d 100644 --- a/dsl/extdeps/vendor/arm.dag +++ b/dsl/extdeps/vendor/arm.dag @@ -1,5 +1,3 @@ -// extdeps/vendor/arm.dag — Arm as a cited hardware-vendor entity. -// Anchor: https://en.wikipedia.org/wiki/Arm_Holdings module extdeps.vendor.arm import extdeps.vendor { Vendor } diff --git a/dsl/extdeps/vendor/intel.dag b/dsl/extdeps/vendor/intel.dag index 2898ae1f0ec..bdf221a24e4 100644 --- a/dsl/extdeps/vendor/intel.dag +++ b/dsl/extdeps/vendor/intel.dag @@ -1,5 +1,3 @@ -// extdeps/vendor/intel.dag — Intel as a cited hardware-vendor entity. -// Anchor: https://en.wikipedia.org/wiki/Intel module extdeps.vendor.intel import extdeps.vendor { Vendor } diff --git a/dsl/extdeps/vendor/nvidia.dag b/dsl/extdeps/vendor/nvidia.dag index b3283df2797..a1d7d5c6563 100644 --- a/dsl/extdeps/vendor/nvidia.dag +++ b/dsl/extdeps/vendor/nvidia.dag @@ -1,5 +1,3 @@ -// extdeps/vendor/nvidia.dag — Nvidia as a cited hardware-vendor entity. -// Anchor: https://en.wikipedia.org/wiki/Nvidia module extdeps.vendor.nvidia import extdeps.vendor { Vendor } diff --git a/dsl/extdeps/vendor/qualcomm.dag b/dsl/extdeps/vendor/qualcomm.dag index 59fe8e4ef20..5723f64e348 100644 --- a/dsl/extdeps/vendor/qualcomm.dag +++ b/dsl/extdeps/vendor/qualcomm.dag @@ -1,5 +1,3 @@ -// extdeps/vendor/qualcomm.dag — Qualcomm as a cited hardware-vendor entity. -// Anchor: https://en.wikipedia.org/wiki/Qualcomm module extdeps.vendor.qualcomm import extdeps.vendor { Vendor } diff --git a/dsl/extdeps/vendor/sk_hynix.dag b/dsl/extdeps/vendor/sk_hynix.dag index df506c14c43..1e668c79607 100644 --- a/dsl/extdeps/vendor/sk_hynix.dag +++ b/dsl/extdeps/vendor/sk_hynix.dag @@ -1,5 +1,3 @@ -// extdeps/vendor/sk_hynix.dag — SK hynix as a cited hardware-vendor entity. -// Anchor: https://en.wikipedia.org/wiki/SK_Hynix module extdeps.vendor.sk_hynix import extdeps.vendor { Vendor } diff --git a/dsl/extdeps/version.dag b/dsl/extdeps/version.dag index d4db3ae5dc8..3fe52846b6c 100644 --- a/dsl/extdeps/version.dag +++ b/dsl/extdeps/version.dag @@ -1,40 +1,12 @@ -// extdeps/version.dag — base versioning model (DESIGN.md §3). -// -// Spec anchors (intersubjective grounding — §1 A3): -// Wikipedia "Software versioning": https://en.wikipedia.org/wiki/Software_versioning -// Wikipedia "Version (computing)": https://en.wikipedia.org/wiki/Version_(computing) -// -// Models version IDENTITY and ORDERING only — not any specific scheme. -// -// Key invariants: -// VersionIdentity — opaque label as the upstream ecosystem names it; no parsing here. -// VersionScheme — the ordering interface each scheme must supply: -// compare(VersionIdentity, VersionIdentity) -> std.algebra.Ordering. -// VersionConstraint — a predicate or range *over* identities; structurally distinct -// from VersionIdentity (">= 1.0.0" is not a version). -// -// Do NOT use std.types.SemVer as the authority for VersionIdentity. -// std.types.SemVer remains a String alias; structured SemVer lives in extdeps.version.semver. - module extdeps.version import std.types { NonEmptyStr } import std.algebra { Ordering } -// A version label as the upstream ecosystem declares it — opaque. -// Schemes project structure onto this label; the label is not parsed or -// ordered here. Each scheme carries its own VersionIdentity values. type VersionIdentity = NonEmptyStr where brand("VersionIdentity") -// Interface contract for ordering versions within a scheme. -// Follows std.algebra.OrderedRing's compare/Ordering pattern (Ordering reused, not re-minted). -// Concrete schemes supply a data row: `data _scheme: VersionScheme = { compare: ... }`. type VersionScheme { compare: fn(VersionIdentity, VersionIdentity) -> Ordering } -// A version constraint — a predicate or range over VersionIdentity values. -// Structurally distinct from VersionIdentity: a constraint is not a version. -// Scheme-specific constraint syntax (">= 1.0.0", "^1.2", "~= 2.3.4") lives -// in the respective slice; this is the base carrier. type VersionConstraint = NonEmptyStr where brand("VersionConstraint") diff --git a/dsl/extdeps/version/pep440.dag b/dsl/extdeps/version/pep440.dag index 37aa5f76005..6b99e1f92e0 100644 --- a/dsl/extdeps/version/pep440.dag +++ b/dsl/extdeps/version/pep440.dag @@ -1,23 +1,3 @@ -// extdeps/version/pep440.dag — Python PEP 440 version identification scheme. -// -// Fidelity — extdeps invariant (cite source + declare version; DESIGN.md §3): -// Spec: https://packaging.python.org/en/latest/specifications/version-specifiers/ -// (canonical PyPA spec; PEP 440 is the historical document) -// Version: PEP 440 (Final, Distutils-SIG, 2014-08-22) -// -// Canonical public identifier grammar (PEP 440 §Public version identifiers): -// [N!]N(.N)*[{a|b|rc}N][.postN][.devN] -// Local version (PEP 440 §Local version identifiers): -// [+] -// -// Scheme slice for `extdeps.version` — decomposed PEP 440 carriers, canonical -// wire labels, and projection onto `VersionIdentity` / `VersionConstraint`. -// Do NOT alias to `std.types.SemVer`. -// -// Consumers: -// dsl/test/claim/python_pep440_version_witness_test.dag — render witnesses -// (future) package metadata / dependency rows when pip/setuptools modeling lands - module extdeps.version.pep440 import extdeps.version { VersionConstraint, VersionIdentity } @@ -26,22 +6,13 @@ import std.integer { NonNegativeInt } import std.list { List } import std.types { NonEmptyStr } -// -- Spec citation ------------------------------------------------- - data pep440_spec_url: NonEmptyStr = "https://packaging.python.org/en/latest/specifications/version-specifiers/" data pep440_spec_label: NonEmptyStr = "PEP 440 (Final, 2014-08-22)" -// PEP 440 version-specifier wire text — predicate over identities, not a version. type Pep440Constraint = VersionConstraint -// Minimum CPython for workflows invoking python3 on PATH (typechecker rows). data min_python_interpreter: Pep440Constraint = ">= 3.11" -// -- Public version segments --------------------------------------- -// -// Coproduct dissolution: `Pep440PreReleasePhase` — alpha/beta/rc are mutually -// exclusive pre-release phases with distinct wire spellings and sort order. - type Pep440PreReleasePhase = Pep440Alpha | Pep440Beta @@ -52,18 +23,10 @@ type Pep440PreRelease { number: NonNegativeInt } -// Local version label segment (PEP 440 §Local version identifiers): each dot- -// separated piece is either all-ASCII-digits (numeric, compared as int) or -// contains a letter (lexicographic, case-insensitive on wire). type Pep440LocalSegment = Pep440LocalNumeric { value: NonNegativeInt } | Pep440LocalLexicographic { label: NonEmptyStr } -// Decomposed public version identifier. `epoch` is the implicit-0 epoch when -// omitted on the wire. `release_segments` is the N(.N)* segment — structurally -// non-empty via `first` + `rest` (PEP 440 requires ≥1 release integer). -// Optional suffix segments model the PEP 440 ordering chain: pre-release, -// post-release, developmental release. type Pep440ReleaseSegments { first: NonNegativeInt rest: List @@ -77,38 +40,28 @@ type Pep440PublicVersion { dev_release: NonNegativeInt? } -// Full version: public identifier plus optional local label (+segment...). type Pep440Version { public: Pep440PublicVersion local: List } -// -- Version specifiers (PEP 440 §Version specifiers) -------------- -// -// Dependency clauses use these operators against public versions. Wildcard -// matching (`== 1.3.4.*`) is deferred — carriers hold a concrete public -// version today. - type Pep440SpecifierOp - = Pep440CompatibleRelease // ~= - | Pep440VersionMatching // == - | Pep440VersionExclusion // != - | Pep440InclusiveAtLeast // >= - | Pep440InclusiveAtMost // <= - | Pep440ExclusiveLess // < - | Pep440ExclusiveGreater // > - | Pep440ArbitraryEquality // === + = Pep440CompatibleRelease + | Pep440VersionMatching + | Pep440VersionExclusion + | Pep440InclusiveAtLeast + | Pep440InclusiveAtMost + | Pep440ExclusiveLess + | Pep440ExclusiveGreater + | Pep440ArbitraryEquality type Pep440VersionClause { op: Pep440SpecifierOp version: Pep440PublicVersion } -// Comma-separated specifier: candidate must satisfy every clause (logical AND). type Pep440VersionSpecifier = List -// -- Base-layer projection ----------------------------------------- - fn pep440_version_identity(v: Pep440Version) -> VersionIdentity { pep440_version_label(v: v) } @@ -117,9 +70,6 @@ fn pep440_version_specifier_constraint(spec: Pep440VersionSpecifier) -> VersionC pep440_version_specifier_label(spec: spec) } -// Slice-1 ordering on structured public carriers. `VersionScheme.compare` on opaque -// `VersionIdentity` values is gated to slice-2 (parse ingress) — installing a stub -// comparator would violate DESIGN.md §5 fail-closed semantics. fn pep440_compare_non_negative_int(a: NonNegativeInt, b: NonNegativeInt) -> Ordering { if a < b { Less } else if a > b { Greater } @@ -136,7 +86,7 @@ fn pep440_compare_release_segments(a: Pep440ReleaseSegments, b: Pep440ReleaseSeg fn pep440_compare_release_rest(a_rest: List, b_rest: List) -> Ordering { if a_rest.length() == 0 && b_rest.length() == 0 { Equal } else if a_rest.length() == 0 { - // PEP 440: shorter release tuples are zero-padded before comparison. + if b_rest.first() == 0 { pep440_compare_release_rest(a_rest: a_rest, b_rest: b_rest.skip(n: 1)) } else { @@ -257,8 +207,6 @@ fn pep440_compare_public(a: Pep440PublicVersion, b: Pep440PublicVersion) -> Orde } } -// -- Wire labels --------------------------------------------------- - fn pep440_pre_release_phase_label(phase: Pep440PreReleasePhase) -> String { match phase { Pep440Alpha => "a" diff --git a/dsl/extdeps/version/semver.dag b/dsl/extdeps/version/semver.dag index 9e51d5156c6..9ef9ef01b3e 100644 --- a/dsl/extdeps/version/semver.dag +++ b/dsl/extdeps/version/semver.dag @@ -1,15 +1,3 @@ -// extdeps/version/semver.dag — Semantic Versioning scheme (slice 2 + 2b). -// -// Spec: https://semver.org/ -// -// Inhabits extdeps.version carriers — not std.types.SemVer (String alias; OCI migration -// is a separate escalation-gated PR). Ecosystem consumers (Cargo package version, etc.) -// import SemVerIdentity / SemVerConstraint from here. -// -// Slice 2b: structured MAJOR.MINOR.PATCH decomposition + semver-aware ordering on -// `SemVerVersion`. `VersionScheme.compare` on opaque `VersionIdentity` uses wire-label -// lexicographic ordering until parse ingress lands (dissolve-on: parse_semver_version). - module extdeps.version.semver import extdeps.version { VersionIdentity, VersionScheme, VersionConstraint } @@ -19,19 +7,14 @@ import std.list { List } import std.nat { nat_compare } import std.types { NonEmptyStr } -// Published semver version label (MAJOR.MINOR.PATCH wire form). type SemVerIdentity = VersionIdentity -// Semver version requirement / comparator wire text — not a published identity. type SemVerConstraint = VersionConstraint -// Pre-release / build identifier (semver.org §9–§10). type SemVerIdentifier = SemVerNumericIdentifier { value: NonNegativeInt } | SemVerAlphanumericIdentifier { label: NonEmptyStr } -// Decomposed semver version. Build metadata is informational and ignored in -// precedence (semver.org §11). type SemVerVersion { major: NonNegativeInt minor: NonNegativeInt @@ -61,7 +44,7 @@ fn semver_compare_identifier(a: SemVerIdentifier, b: SemVerIdentifier) -> Orderi fn semver_compare_identifiers(a: List, b: List) -> Ordering { if a.count() == 0 && b.count() == 0 { Equal } - // semver.org §11.4.4: when all preceding identifiers are equal, the longer set wins. + else if a.count() == 0 { Less } else if b.count() == 0 { Greater } else { @@ -130,11 +113,6 @@ fn semver_to_version_identity(v: SemVerVersion) -> VersionIdentity { semver_version_label(v: v) } -// VersionIdentity ingress for extdeps.version.VersionScheme. -// Interim: lexicographic order on wire labels (deterministic total order, not -// semver-aware — pre-release segments can sort wrong on the opaque surface). -// Scaffold: dissolve-on: parse_semver_version lands — replace body with: -// (a, b) => semver_compare(a: parse_semver_version(a), b: parse_semver_version(b)) fn semver_identity_compare(a: VersionIdentity, b: VersionIdentity) -> Ordering { if a == b { Equal } else { if a < b { Less } else { Greater } } }