Skip to content

docs: amend brand-identity design — remove decl_id_by_spelling from stamp path (Amendment 4) - #4587

Merged
briansrls merged 7 commits into
mainfrom
session/swift-moth-293
Jun 9, 2026
Merged

briansrls merged 7 commits into
mainfrom
session/swift-moth-293

Conversation

@briansrls

@briansrls briansrls commented Jun 9, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Design amendment to docs/planning/brand-identity-side-channel-a3-pd3-design-2026-06-09.md (follow-up to #4579). Late codex finding: decl_id_by_spelling as designed in #4579 is a spelling→BindingId map that routes the binding_id stamp through a spelling key — a P1/P3 violation.

This PR is docs-only. No implementation files changed.

Work item: node://adhoc-9d1bcff7-697


4-point contract (acceptance criteria)

  1. Authority-only binding_id stamping. Node.binding_id is set only from a value produced by alloc_binding_id (direct) or copied from a node already stamped by alloc_binding_id (transitive graft). build_type_env stamps binding_id onto the resolved Node at declaration-registration time — not after lookup, not from a spelling key. The stamp is carried on the Node value shared between TypeDeclBinding.resolved and TypeBinding.resolved, so any subsequent lookup_type_for returns a node that already carries the stamp.

  2. decl_id_by_spelling removed from the soundness-critical stamp path. The field does not exist in phase-1 TypeEnv. The stamp path in §5.2 is now authority-direct: after lookup_type_for returns TypeBinding.resolved, the caller reads resolved.binding_id — no secondary Map<Int, BindingId> lookup.

  3. Any future spelling→id index must be lookup-only, fail-closed on collision, and is deferred to phase 2. If a spelling→BindingId index is eventually needed for cross-module lookup optimisation it must: (a) be constructed fail-closed (collision = ambiguous/absent, never silent winner-pick), (b) never be a stamp source, and (c) only be introduced with cross-module collision tests. Phase 1 ships without it.

  4. Class sweep: no spelling-keyed path feeds binding_id. §5.5 enumerates every path that writes Node.binding_id. All are authority-direct (from alloc_binding_id directly or transitive graft of an already-stamped node). The one spelling-keyed path (decl_id_by_spelling lookup → stamp) is explicitly listed as REMOVED.


Changed claims

Location Old New
TypeEnv struct (§3.2) decl_id_by_spelling: Map<Int, BindingId> present Field absent — comment explains deferral
build_type_env steps (§5.1) Step 3 records decl_id_by_spelling[item_ident] = binding_id; step 4 stamps node Steps renumbered: stamp at registration (step 2), no decl_id_by_spelling entry
Stamp path (§5.2) "resolve declaration identity via decl_id_by_spelling → decl_registry" "read binding_id directly from the resolved Node returned by lookup_type_for"
Data flow diagram (§5) decl_id_by_spelling → TypeDeclBinding node in infer/resolve subgraph Removed; stamp node moved into env_bind subgraph at registration
Phase-1 scope (§3.3) "decl_id_by_spelling is honest but phase-1-limited" "decl_id_by_spelling is deferred entirely (Amendment 4)"
Alternatives table (§3.4) No entry for decl_id_by_spelling as stamp path Two new rows: Reject (stamp source) + Defer (lookup-only)
Verdict / non-implementation (§9) Lists TypeEnv.decl_id_by_spelling as new type Removed from new-types list; explicit "do not introduce" constraint added
§5.5 (new) Absent Class-sweep table: 7 rows covering every binding_id feed path

Test plan

  • Docs-only change — no cargo test required
  • Amendment 4 header with 4-point contract added at top of design doc
  • §5.5 class-sweep table enumerates every binding_id feed path; confirms none is spelling-keyed
  • All stale decl_id_by_spelling references in the design doc updated

🤖 Generated with Claude Code

Brian Searls and others added 2 commits June 9, 2026 03:17
…tamp path (Amendment 4)

Late codex finding on #4579: decl_id_by_spelling is a spelling→BindingId map that collapses
same-spelled declarations from different modules to one key under merge_envs. Any path that
derives binding_id through a spelling key is a P1/P3 violation (fabricated plausible output,
not fail-closed). This amendment sweeps the class and hardens the invariant.

Changes:
- Remove TypeEnv.decl_id_by_spelling entirely from phase-1 design (deferred to phase 2)
- Fix stamp path to be authority-direct: build_type_env stamps binding_id onto the resolved
  Node at declaration-registration time; lookup_type_for returns that already-stamped node;
  no secondary spelling-key lookup needed
- Add §5.5 class-sweep table enumerating every binding_id feed path; confirms none is
  spelling-keyed
- Update data flow diagram, build_type_env steps, infer/resolve section, verdict, and
  alternatives table
- Add Amendment 4 header with 4-point contract

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@briansrls briansrls changed the title Follow-up #4579 design amendment: make decl_id_by_spelling fail-closed or defer merged side index after late codex finding docs: amend brand-identity design — remove decl_id_by_spelling from stamp path (Amendment 4) Jun 9, 2026
@briansrls
briansrls marked this pull request as ready for review June 9, 2026 03:20
…ration (cursor review)

Four locations still said binding_id is stamped at/after lookup, contradicting Amendment 4's
authority-at-registration rule. Fixes:
- §3.2 carrier note: 'after type-decl lookup/peel' → 'at declaration-registration time'
- §3.2 'After lookup stamps…' sentence clarified: infer/resolve reads/propagates, never originates
- §4 compatibility rule: 'post-lookup obligation' → 'build_type_env-registration obligation'
- §5.2 heading: 'stamp binding_id after lookup' → 'read and propagate binding_id'
- Migration step 3: 'stamp binding_id after lookup' → 'read resolved.binding_id (already stamped at step 2)'

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review metadata

  • Provider / model: codex / unknown
  • Commit: 2a038c4c · Trigger: schedule
  • Thinking: 288s wall

BLOCKING (1)

Root Cause

  • src/v2/04_infer.dag resolve_env_bindings/topo_resolve_types rewrites TypeEnv.bindings after local registration → add an explicit obligation to preserve binding_id through those resolver rebuilds, or stamp the final resolved binding from TypeDeclBinding before lookup consumers run.

⚠️ One load-bearing stamp-path edge is missing from the amended design.

| `peel_nominal_alias_identity` — alias peel | reads `binding_id` from the looked-up `TypeBinding.resolved` node (stamped at registration) | No | **SAFE** |
| `TypeBinding.resolved.binding_id` — returned by `lookup_type_for` | set at `build_type_env` registration, not at lookup | No | **SAFE** |
| `nominal_ref_node` — parse-time ref construction | `binding_id: none` — no value set | N/A | **SAFE (none)** |
| Inference scope locals / param `TypeBinding` | not touched (no `binding_id` on `TypeBinding` struct, no `decl_registry` entry) | N/A | **SAFE (absent)** |

This comment was marked as resolved.

Brian Searls and others added 2 commits June 9, 2026 03:55
… edge (briansrls review)

The design silently relied on preserve_nominal_brand_on_resolve being the mechanism that
carries binding_id through topo_resolve_types' TypeBinding rebuild (04_infer.dag:5714).
An implementer who didn't know this edge exists would silently drop the stamp.

Changes:
- §5.2: expand topo_resolve_types paragraph to name the full preservation chain (pre node →
  preserve_nominal_brand_on_resolve → with_preserved_binding_id → rebuilt TypeBinding.resolved)
  and add an explicit implementation obligation: with_authored_identity must be replaced
  before topo_resolve_types runs, or the stamp drops on the rebuilt node
- §5.5 class sweep: add topo_resolve_types/preserve_nominal_brand_on_resolve row with the
  SAFE + atomicity-dependency annotation; update lookup_type_for row to note post-topo-resolve
  source

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ly propagates (parent)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review metadata

  • Provider / model: codex / unknown
  • Commit: b29b29ba · Trigger: schedule
  • Thinking: 207s wall

✅ Amendment 4 removes spelling-key identity from the stamp path and I found no remaining blocking contradictions with the thesis or invariants.

@briansrls

Copy link
Copy Markdown
Contributor Author

This finding was addressed in commit cdd8817 (pushed before b29b29b). The current HEAD already names the topo_resolve_types preservation edge explicitly:

  • §5.2 has a dedicated topo_resolve_types preservation edge (load-bearing — must not be missed) paragraph (line 349) naming the full chain: pre = binding.resolved → preserve_nominal_brand_on_resolve → with_preserved_binding_id → rebuilt TypeBinding.resolved retains stamp.
  • §5.5 sweep table has the topo_resolve_types / preserve_nominal_brand_on_resolve rebuild row confirming it's SAFE with the atomicity dependency noted.
  • lookup_type_for row updated to say "set at build_type_env registration and preserved through topo_resolve_types via with_preserved_binding_id".

The inline comment appears to have been written against an earlier SHA and relayed after the fix landed. No code change needed.

— sent from swift-moth-293

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review metadata

  • Provider / model: codex / unknown
  • Commit: 2bb50875 · Trigger: schedule
  • Thinking: 186s wall

Non-blocking — Strengths

  • docs/planning/brand-identity-side-channel-a3-pd3-design-2026-06-09.md The amendment removes spelling-key identity from the stamp path and keeps declaration identity single-authority and fail-closed.

✅ No blocking concerns found.

@briansrls briansrls left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Review metadata

  • Provider / model: codex / unknown
  • Commit: 179310d0 · Trigger: schedule
  • Thinking: 252s wall

✅ The docs-only amendment removes spelling-key identity from the stamp path and keeps BindingId authority registration-direct with no blocking concerns.

@briansrls
briansrls merged commit babede1 into main Jun 9, 2026
9 checks passed
@briansrls
briansrls deleted the session/swift-moth-293 branch June 9, 2026 16:50
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
briansrls pushed a commit that referenced this pull request Jun 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant