feat(verify): verify_capabilities + verify_access_sites passes (proposal 0002 §Gate 4)#109
Merged
Conversation
…proposal 0001 + 0002 Gate 4) Closes proposal 0002 §Gate 4 (`verify_access_sites` cross-section pass) and adds the equivalent for proposal 0001's capabilities carrier (§"What the proposal adds" #2). Both are now thoroughly tested cross-section verifier passes. ## New public API `crates/typed-wasm-verify/src/lib.rs`: - `CAPABILITIES_SECTION_NAME` = "typedwasm.capabilities" (gated `unstable-l15`) - `ACCESS_SITES_SECTION_NAME` = "typedwasm.access-sites" (gated `unstable-l2`) - `CapabilitiesError` enum (gated `unstable-l15`): `FuncIdxOutOfRange`, `CapabilityIdxOutOfRange` - `AccessSiteError` enum (gated `unstable-l2`): `MissingDependentRegions`, `FuncIdxOutOfRange`, `RegionIdOutOfRange`, `FieldIdOutOfRange` - `verify_capabilities_from_module(wasm_bytes)` — entry point - `verify_access_sites_from_module(wasm_bytes)` — entry point ## New impls `crates/typed-wasm-verify/src/verify.rs`: - `function_count(wasm_bytes)` — small helper: scans Import + Function sections to get total `import_count + locally_defined_count`. Shared by both new passes. - `verify_capabilities_from_module` — iterates the capabilities section, checks each `func_idx` against `function_count()` and each per-function `required` index against `capability_count`. - `verify_access_sites_from_module` — iterates the access-sites section + regions section together (single pass). Checks: 1. `MissingDependentCarrier` (proposal 0002 §"Producer obligations" #2): access-sites present without regions is a hard error. Treated identically if regions present but unparseable (version mismatch). 2. `func_idx` in range against `function_count()`. 3. `region_id` in range against regions table. 4. `field_id` in range against target region's field table (skipped if region_id was out of range — can't cross-reference a missing row). `DistinctCaps` (strictly-increasing per-function required list) is NOT re-checked because the codec parser already normalises required indices to sorted+deduped form. Verifying that would require parsing raw wire bytes pre-normalisation; defer as a producer-side property test. `AccessSiteMisalignment` (instruction_byte_offset doesn't land on a typed access opcode) is NOT checked — would require parsing function bodies to verify the offset. Proposal 0002 explicitly defers this to a follow-up. ## Tests (11 new) `capabilities_verifier_tests` (5, gated `unstable-l15`): - module without section verifies trivially - well-formed capabilities verifies clean - out-of-bounds func_idx is flagged - out-of-bounds capability index is flagged - imports count toward function_count (validates Import section is consulted in addition to Function section) `access_sites_verifier_tests` (6, gated `unstable-l2`): - module without access-sites section verifies trivially - access-sites without regions = MissingDependentRegions - well-formed access-sites verifies clean - out-of-bounds func_idx is flagged - out-of-bounds region_id is flagged + skips field check - out-of-bounds field_id is flagged All 4 feature combos green: | features | tests passed | |--------------------------------|--------------| | (default) | 43 | | unstable-l2 | 65 | | unstable-l15 | 55 | | unstable-l2,unstable-l15 | 77 | ## What this leaves for [accepted] For proposal 0001: - §Criterion 2: wire-vs-Idris2-spec review — could land as a Coq-style proof-doc OR an Idris2 `Schema ≡ wire_layout` property test in `src/abi/`. Not real impl, but a deliberate write-up step. For proposal 0002: - §Gate 6: producer codegen issues for access-sites (affinescript + ephapax). Filed under #97-adjacent producer-readiness checklist. Both proposals are now ~95% through their acceptance criteria. Refs #34 #76 #78 Refs #86 #106 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
🔍 Hypatia Security ScanFindings: 96 issues detected
View findings[
{
"reason": "Action perpolymath/standards/.github/workflows/governance-reusable.yml@main\n needs attention",
"type": "unpinned_action",
"file": "governance.yml",
"action": "pin_sha",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in boj-build.yml",
"type": "unknown",
"file": "boj-build.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in c5-regenerate.yml",
"type": "unknown",
"file": "c5-regenerate.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in cargo-audit.yml",
"type": "unknown",
"file": "cargo-audit.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in codeql.yml",
"type": "unknown",
"file": "codeql.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in dogfood-gate.yml",
"type": "unknown",
"file": "dogfood-gate.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in dogfood-gate.yml",
"type": "unknown",
"file": "dogfood-gate.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in dogfood-gate.yml",
"type": "unknown",
"file": "dogfood-gate.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in dogfood-gate.yml",
"type": "unknown",
"file": "dogfood-gate.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
},
{
"reason": "Issue in dogfood-gate.yml",
"type": "unknown",
"file": "dogfood-gate.yml",
"action": "flag",
"rule_module": "workflow_audit",
"severity": "medium"
}
]Powered by Hypatia Neurosymbolic CI/CD Intelligence |
This was referenced May 30, 2026
hyperpolymath
added a commit
that referenced
this pull request
May 30, 2026
…#110) ## Summary Closes proposal 0001 §"Acceptance criteria" Criterion 2 — the last write-up gate before `[review] → [accepted]`. Adds a 247-line "Appendix A — Wire-vs-Idris2-spec mapping" to `docs/proposals/0001-multi-producer-carrier-section.adoc`. ### Appendix structure | Section | Coverage | |---------|----------| | A.1 | `typedwasm.regions` wire fields ↔ `Region.idr` + `Pointer.idr` — per-field table (version, region_count, name, field_count, field_name, kind, wasm_ty, target_region, nullability, cardinality, region_byte_size) | | A.2 | `typedwasm.capabilities` wire fields ↔ `ResourceCapabilities.idr` — capability table + per-function required list; documents that strict-increasing `required[]` encodes DistinctCaps + ContainedIn + canonical-order at once | | A.3 | What is NOT carried on the wire (deliberate): `ContainedIn` proof witnesses (verifier reconstructs), `CallCompatible` (L15-C deferred to #96), `LayoutValid` (verifier recomputes), `SchemaEq` (single-module v1), `RegionDisjoint` (runtime concern), `ExclusiveWitness` (in ownership section) | | A.4 | Soundness shape — single NOTE listing per-emission proof obligations PR #107 (codec) + PR #109 (verifier) already enforce | Criterion 2 line in §"Acceptance criteria" updated to "*(Satisfied — see Appendix A below.)*". ### Why a write-up not a property test Criterion 2's text reads "every wire field maps cleanly to a spec witness" — a *write-up* satisfies it (and is what a reviewer reads). A future task (filed in the appendix's closing paragraph, not blocking `[accepted]`) is to encode the same mapping as Idris2 property tests in `src/abi/` (`WireSchemaEquiv.idr` showing `encode/decode` round-trips preserve the spec witnesses). ### Acceptance-roadmap state after this PR | | 0001 (regions+capabilities) | 0002 (access-sites) | |----------------------|------------------------------|----------------------| | Codec | ✅ #107 | ✅ #107 | | Verifier | ✅ #109 | ✅ #109 | | Spec doc | ✅ #108 | ✅ #108 | | Wire-vs-spec review | ✅ **this PR** | n/a | | Cross-repo issues | ✅ affinescript#444 + ephapax#221 | ✅ affinescript#462 / ephapax pending | | Open Qs |⚠️ #94, #95, #96 still open | n/a | After this lands, proposal 0001's only remaining gate is the open questions converging (`WBool` wire-width pin, region-imports proposal placeholder, capability-grants v1.4.x). The acceptance criteria themselves are all green. ## Test plan - [x] Local proof-doc render check: appendix renders with cleanly-formatted cols=2,3,2 + cols=2,3 tables. - [x] Cross-reference links resolve (Region.idr:253, Region.idr:127, Pointer.idr:74, ResourceCapabilities.idr:67/104/218/241/248/312, etc.). - [x] No code changes — no Cargo build required. - [ ] Reviewer cross-check: confirm A.3 is exhaustive (no missed spec-side relation that v1 silently drops). ## Related - #34 (proposal 0001 umbrella) - #106 (acceptance roadmap tracker) - PR #104 ([draft] → [review]) - PR #107 (codec) / PR #108 (spec doc) / PR #109 (verifier) - #94 / #95 / #96 (acceptance preconditions filed) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
4 tasks
hyperpolymath
added a commit
that referenced
this pull request
May 30, 2026
…C) (#111) ## Summary Closes [#96](#96 third acceptance bullet — "[draft] proposal 0004 for typedwasm.capability-grants is authored and tracks back here." Authors a draft fourth carrier section for **L15-C** (call-graph monotonicity / per-call-site capability attenuation). Companion to [proposal 0001](https://github.com/hyperpolymath/typed-wasm/blob/main/docs/proposals/0001-multi-producer-carrier-section.adoc)'s `typedwasm.capabilities` (which carries L15-A + L15-B). ## What 0004 specifies Per call site `(caller_func_idx, call_instruction_byte_offset)`, a list of `granted_capability_indices` (subset of the caller's required capabilities). Verifier check at every call site: - `callee.required ⊆ grant` (grant covers what callee needs — `CallSiteGrantInsufficient` on violation) - `grant ⊆ caller.required` (grant is a genuine subset of what caller advertised — `CallSiteGrantOverreach` on violation) Together these realise `CallCompatible caller callee` from `ResourceCapabilities.idr:187` *with attenuation* — without the carrier, the verifier can only do conservative transitive analysis, which **cannot express per-call-site attenuation** at all. ## Wire format Mirrors proposal 0002's encoding B for codec-pattern symmetry: ``` u16le version (= 1) u32le_leb128 entry_count for each entry: u32le_leb128 caller_func_idx u32le_leb128 call_instruction_byte_offset u32le_leb128 granted_count u32le_leb128[granted_count] granted_capability_indices (strictly increasing → DistinctCaps) ``` ## Section structure Same shape as 0001 and 0002: | Section | Coverage | |---------|----------| | Context | L15-A vs L15-C deferral in 0001, why per-call-site, capability attenuation rationale | | Proposal | Encoding decision (B adopted, A rejected, C deferred); wire format; spec-type mapping; versioning policy | | Producer obligations | 6 items mirroring 0001 + 0002 (post-rewrite emit, companion section, stable indices, all-or-nothing, call-only opcodes, grant ⊆ caller.required) | | Consumer obligations | `verify_capability_grants_from_module` pass + 5 error variants (`CallSiteUnbound`, `CallSiteGrantInsufficient`, `CallSiteGrantOverreach`, `CallSiteMisalignment`, `MissingDependentCapabilities`) | | Coordination | review by affinescript + ephapax; producer codegen gated on L15-A landing first | | Alternatives considered | A flat / C grouped / D no-carrier / E embed-in-caps / F component-model | | Open questions | (1) indirect calls — option (a) annotate type sigs vs (b) defer to v2; (2) higher-order arg caps; (3) tail calls; (4) cross-module grants; (5) component-model; (6) defaulting policy — permissive default | | Acceptance criteria | 6 gates mirroring 0001/0002 | ## Why `[draft]` and not `[review]` L15-C requires L15-A codegen as a prerequisite: - **AffineScript** — Roadmap C2 (capability tracking) not started (`lib/borrow.ml:1725`). - **Ephapax** — `ExprKind::Perform/Handle` codegen stubs to `Instruction::Unreachable` (`src/ephapax-wasm/src/lib.rs`). Neither producer can emit `typedwasm.capability-grants` until they first ship `typedwasm.capabilities`. The draft sequences the v1.4.x work explicitly; the `[review]` flip can wait on at least one producer landing L15-A. ## README update Adds 0004 entry to `docs/proposals/README.adoc`'s "Current proposals" table. Notes that proposal 0003 ([#95](#95) `typedwasm.region-imports`) is reserved but not yet drafted. ## Test plan - [x] AsciiDoc renders cleanly (cols-tables, code-blocks, cross-refs). - [x] Cross-references resolve (Region.idr, Pointer.idr, ResourceCapabilities.idr line numbers; sibling proposal links; tracker issue links). - [x] No code changes — no Cargo build required. - [ ] Reviewer cross-check: confirm the wire-format details match the spec-side `CallCompatible` predicate's two implications. ## Related - #96 (tracker — this PR closes the [draft] acceptance bullet) - #95 (sibling tracker — region-imports / proposal 0003 slot reserved) - #34 (proposal 0001 umbrella) - #106 (acceptance roadmap tracker for 0001/0002) - PR #76 (proposal 0001 landing — source of L15-C deferral) - PR #109 (verify_capabilities — L15-A + L15-B verifier; 0004's pass extends it) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This was referenced May 30, 2026
hyperpolymath
added a commit
that referenced
this pull request
May 30, 2026
…115) ## Summary Owner-decision close of the proposal-acceptance arc. Both proposals satisfied every acceptance gate this session ([see #106 wrap-up comment](#106 (comment))); this PR applies the status flip. ## Status changes - `docs/proposals/0001-multi-producer-carrier-section.adoc` — `review → accepted` - `docs/proposals/0002-access-site-carrier.adoc` — `review → accepted` - `docs/proposals/README.adoc` — "Current proposals" table updated; NOTE block clarifies files remain in `docs/proposals/` (ADR promotion is a separate file-restructure follow-up). ## LEVEL-STATUS.md updates | Level | Before | After | |-------|--------|-------| | L2 (region binding) | proposal-stage | **YES** (carrier-backed) — `verify_access_sites_from_module` (PR #109); gated `unstable-l2` | | L3–L6 (type-compat, null, bounds, result-type) | proposal-stage | **YES** (carrier-backed, schema half) — regions codec PR #107; per-access enforcement gated on producer codegen | | L15-A/B (capabilities) | proposal-stage | **YES** (carrier-backed) — `verify_capabilities_from_module` (PR #109); gated `unstable-l15` | | L13 cross-module (positive form) | — | proposal-stage — proposal 0003 `[draft]` (new row) | "Open gating items" section rewritten to remove obsolete pre-acceptance gates (all shipped via #107/#109) and enumerate the remaining producer-side prerequisites + [draft] proposal 0003/0004 work. ## What this DOES NOT change - **File locations**: proposals stay in `docs/proposals/`. ADR promotion to `docs/decisions/` (with renumbering — existing ADR 0001 is "adopt-rsr-standard", so proposals 0001/0002 would become ADRs 0002/0003) is a deliberate separate PR to keep the status flip cleanly auditable. - **Code**: no source or test changes. Verifier passes already shipped in #107/#109 behind `unstable-l2` / `unstable-l15` feature flags. - **Producer-side codegen**: still pending per Appendix B prerequisites in proposal 0001. ## Test plan - [x] Status field flipped on both proposals. - [x] README table reflects new statuses with date. - [x] LEVEL-STATUS L2/L3-L6/L15 rows show carrier-backed YES. - [x] Open gating items rewritten (4 items: producer codegen, L13 cross-module, L15-C, ADR promotion). - [ ] CI passes (doc-only changes; no Cargo/Idris2 build risk). ## Related - #34 (proposal 0001 umbrella) - #78 (proposal 0002 RFC) - #106 (acceptance roadmap tracker — full wrap-up comment) - This session's 5-PR sprint that satisfied every gate: #107 (codec), #108 (spec doc), #109 (verifier), #110 (Criterion 2 appendix), #111 (proposal 0004 draft for #96), #112 (proposal 0003 draft for #95), #113 (WBool pin for #94), #114 (producer-readiness for #97). 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
hyperpolymath
added a commit
that referenced
this pull request
May 30, 2026
## Summary Stacks on #115. Promotes the two `[accepted]` (2026-05-30) proposals to architecture decision records under `docs/decisions/`. Closes the last open gating item from PR #115's LEVEL-STATUS rewrite (#4 — "ADR promotion"). ## Changes **New files:** - `docs/decisions/0002-multi-producer-carrier-sections.adoc` — ADR for `typedwasm.regions` + `typedwasm.capabilities` carriers, plus reserved slots for access-sites (→ ADR-0003) and region-imports (→ proposal 0003 `[draft]`). Adopted pins: WBool 4B wire, LEB128 per field (option B), cardinality-1 producer surface in v1, opt-in Cargo features. - `docs/decisions/0003-access-site-carrier.adoc` — ADR for `typedwasm.access-sites` per-instruction `(region_id, field_id)` carrier (proposal 0001 OQ §5 → option A). Realised by `verify_access_sites_from_module` in PR #109. **Updated files:** - `docs/decisions/README.adoc` — rewritten from 2-line stub to proper ADR index (ADR-0001 RSR + new ADR-0002 / 0003 + authoring guidance + cross-refs). - `docs/proposals/README.adoc` — index entries gain promotion arrows; NOTE block updated to reflect the promotion instead of the deferral. - `docs/proposals/0001-multi-producer-carrier-section.adoc`, `docs/proposals/0002-access-site-carrier.adoc` — add `Promoted to` metadata row + inline NOTE under the metadata table. Proposal content is unchanged; they remain canonical wire-format references. - `LEVEL-STATUS.md` — Open-gating item #4 (ADR promotion) → DONE with file-path pointers. ## Why now #115 flipped proposals 0001 + 0002 to `[accepted]` but deliberately deferred ADR promotion as a separate auditable PR (file moves + numbering choices). This PR closes that follow-up: - Existing ADR 0001 is `adopt-rsr-standard` (2026-02-14). New ADRs pick up at 0002 / 0003 in chronological order without renumbering anything else. - Proposal files are **retained** rather than removed — the ADRs are short decision records; the proposals carry the wire-format detail, error variants, and producer-readiness checklists. Cross-references point in both directions. ## Stacking note Branched off PR #115's head commit `d9869bb` so the proposal status fields and `docs/proposals/README.adoc` are already at the `[accepted]` baseline. Will rebase cleanly when #115 merges; no content conflict with #115. ## Test plan - [ ] AsciiDoc renders without broken anchors - [ ] `docs/decisions/README.adoc` index entries link to the right files - [ ] Proposal `Promoted to` rows resolve to the new ADRs - [ ] CI green (no source changes; docs-only) 🤖 Generated with [Claude Code](https://claude.com/claude-code)
Merged
2 tasks
hyperpolymath
added a commit
that referenced
this pull request
May 30, 2026
…ss stale references (#117) ## Summary Companion to #115 (acceptance flip) and #116 (ADR promotion). Sweeps the remaining files that still carried `[draft]` / `[review]` proposal status or referenced now-closed cross-repo gating issues. ## Files changed | File | What changed | |---|---| | \`README.adoc\` | Proposal status flipped to \`[accepted]\` + ADR links; added 0003/0004 to forward-looking section; rewrote the verifier-pass status sentence (was "gated on proposal 0002's acceptance"; now reflects PR #109 having shipped). | | \`CHANGELOG.md\` | New Unreleased section "Multi-producer carrier ABI: proposals 0001 + 0002 accepted, promoted to ADRs (2026-05-30)" covering PRs #110-#116 + the seven closed issues + producer-side gates that remain. | | \`crates/typed-wasm-verify/Cargo.toml\` | Feature-flag comments updated to reflect post-acceptance state. \`unstable-l2\` / \`unstable-l15\` feature gates retained while Phase 3 stabilisation is open. | | \`docs/PRODUCTION-PATH.adoc\` | Proposals 0001/0002 flipped to \`[accepted]\` with PR pointers; added 0003/0004 to active-design-work list. | | \`spec/type-safety-levels-for-wasm.adoc\` | Wire-section status column updated for \`typedwasm.regions\` / \`typedwasm.capabilities\` / \`typedwasm.access-sites\`; tail references enumerate all four proposals with current status. | | \`.machine_readable/6a2/STATE.a2ml\` | Capabilities-by-level entries flipped 30→100; rewrote critical-next-actions; rewrote \`[carrier-abi]\` section with accepted-date / acceptance-pr / adr-pr for both proposals + added \`[draft]\` entries for 0003/0004. | ## What was deliberately left alone \`spec/{ARG,CRG,FRG,TRG}-PROFILE.adoc\` — these are point-in-time audit snapshots, not config. They mention the proposals as the live RFC corpus, but rewriting audit history adds more noise than signal. ## Test plan - [ ] CI green (docs + config only; no source changes) - [ ] Cross-links resolve in rendered AsciiDoc 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes proposal 0002 §Gate 4 (`verify_access_sites` cross-section pass) and the equivalent for proposal 0001's capabilities carrier. Both proposals are now ~95% through acceptance criteria.
New public API
Checks performed
`verify_capabilities`
`verify_access_sites`
Deliberately out of scope (deferred)
Tests (+11)
5 capabilities + 6 access-sites verifier tests using `wasm-encoder` to build minimal valid modules with the relevant custom sections (and matching Function+Code sections — required for wasm validation).
Acceptance progress after this lands
Proposal 0001 (regions + capabilities):
Proposal 0002 (access-sites):
Test plan
🤖 Generated with Claude Code