Repository navigation
T-13 Phase 2 family-wide migration ratchet — implement crisp-boar-896 Phase 1 proposal: (1) ClassifiedDependencyView<C> in v4.std.dependency; (2) migrate all 5 T-13 lenses + claims; (3) split-contract via composition (rollup_unused ∘ use_classification_fact); (4) test-claim template; (5) Practice 11 - #3506
Conversation
… lenses + claims + test-claim template + Practice 11 sub-rule
Phase 1 implementation per crisp-boar-896 design (operator-ratified
2026-05-21 via PM smart-lynx-142). Dissolves the recurring
parallel-payload-vs-typed-reference anti-pattern (5th instance) on the
T-13 lens family.
Substrate (v4.std.dependency):
- ClassifiedDependencyView<C> { dependency: DependencyView; classification: C }
is now the one parametric T-13 lens row. Endpoints live on the inner
DependencyView (single authority); per-lens C is the projection.
- classified_source/dependent/usage_site accessors + classified_dependency_view_eq
(parametric over a classification-eq comparator).
Lens family (one mechanism, N projections):
- v4.lens.parallelism — ClassifiedDependencyView<ParallelismRelation>
- v4.lens.effect — ClassifiedDependencyView<EffectClassification>
- v4.lens.ownership — ClassifiedDependencyView<OwnershipMode>
- v4.lens.idempotency — ClassifiedDependencyView<IdempotencyVerdict>
- v4.lens.unused_parameters — split-contract:
PROJECTION: Witness<UseClassificationFact> (T-13 family shape)
BEHAVIORAL: Witness<UnusedParametersFact> (registry roll-up
aligned with LensIdV0::UnusedParameters / v3 query)
Behavioral = composition: unused_parameters_fact =
rollup_unused ∘ use_classification_fact (single mechanism, no
parallel authority). UnusedParameterFact = { declaration, declaration_facts }.
Endpoint duplication removed from every row: no more source/dependent/at/
owner/subject/use_site/declaration parallel-payload fields on lens rows;
endpoints read through dependency.* accessors. Per-node InferredFacts no
longer copied onto rows; read at use-sites via tree.facts.lookup(...)
(Practice 3 — facts flow forward by reference).
Test-claim template (Phase 1 step 4):
- src/v4/test/claim/lens_common/infer_fixture.dag — claim_atom_node,
claim_inferred_facts, claim_inferred_facts_map, claim_inferred_tree.
All 6 T-13 claim files migrated to this fixture: substrate shape
changes (e.g. InferredFacts field evolution) need a single edit, not
N (cost-of-change = 1).
Claim updates (all 5 lenses + new roll-up claim):
- parallelism / effect / ownership / idempotency: PROJECTION on the new
ClassifiedDependencyView<C> shape via the shared fixture.
- unused_parameters/binds_to_edge.dag: PROJECTION — BindsTo ⇒
IsUseOfDeclaration on UseClassificationFact.
- unused_parameters/non_use_edges.dag: PROJECTION partition — Contains/
DataDependsOn/GeneratedFrom ⇒ {IsStructuralComposition / IsNonUseDependency /
RequiresResolutionWitness}.
- unused_parameters/rollup_unused_declaration.dag (NEW): BEHAVIORAL —
declaration with only non-USE edges rolls up into UnusedParametersFact.unused.
Practice 11 sub-rule:
- docs/modeling-discipline.md — new "Parallel-payload vs typed-reference"
section under Practice 11, with worked instance + mechanical test +
family-wide-ratchet disposition + 5-instance recurring table (memory-
grounded). Operator-direct standing 2026-05-19, ratified for this
ratchet 2026-05-21.
Acceptance criteria run locally:
target/debug/v2-compiler compile --source-root src/v4 \
--output-dir /tmp/gunbc-v4-final
→ 120 modules / 124 files emitted / 0 diagnostics
python3 scripts/strict_deprose_dag.py --check → OK
rg 'WholeFile|Whole[A-Z][A-Za-z]*' over the migrated files → no matches
No external consumers of the old *DependencyFact types (grep confirmed
pre-migration); only lens files + claim files used them.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
briansrls
left a comment
There was a problem hiding this comment.
Review metadata
- Provider / model:
codex/unknown - Commit:
7eac547b· Trigger:schedule - Thinking:
261s wall
BLOCKING (1)
Root Cause
src/v4/lens/unused_parameters.dagUseClassificationFact carries per-edge classifications but not the declaration-candidate/query scope needed by the behavioral roll-up → carry or derive the typed declaration scope before constructing UnusedParametersFact.
| dependencies: fold(dependencies, init: [], f: fn(acc, view) { | ||
| list_push(acc, unused_parameters_dependency_fact(tree: tree, view: view)) | ||
| unused: fold(use_fact.uses, init: [], f: fn(acc, classified) { | ||
| let declaration = classified.dependency.source |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
|
Re: codex BLOCKING on sha Verified valid for The codex finding is the same root issue as the inline review at Chose the design-note branch (b) — derive the typed declaration scope inside This keeps — sent from lively-cat-513 |
…ins-dependent candidate scope Addresses cursor APPROVE exploratory observation on PR #3506 at src/v4/lens/unused_parameters.dag:107-109: the roll-up scope comment still described the prior `source == N` candidate identification. Refresh to match the corrected behavior (Contains-dependent candidates under P6). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Re: cursor APPROVE exploratory observations:
— sent from lively-cat-513 |
…er (B3 single-authority) Addresses codex REQUEST_CHANGES on PR #3506 (sha 7eac547, 2026-05-21 09:37:16Z): the previous `EffectClassification` enum mapped `DependencyKind` to effect kinds (EffectDependsOn ⇒ WriteEffect, etc.), which re-authored effect kinds from dependency kinds — a second authority contradicting B3 ("the type signature is the effect authority"). Fixing the parallel-payload defect by introducing a parallel-kind-authority defect would have been the same Practice 5 / INVARIANTS P2 trap in a different shape. Fix: `EffectClassification` is now an empty signature-deferred marker (`type EffectClassification {}`). The per-edge row carries the typed dependency reference plus this marker; the actual effect kind is read at use-sites from `tree.facts.lookup(dependency.source)`, never derived from `DependencyKind`. The dependency kind has no role in effect classification — single authority preserved. Decoding `InferredFacts` into a closed effect-kind carrier (the full fix for #3468's collapse-of-signature/resource/algebra BLOCKING) remains the follow-up lane; this PR no longer pretends to settle it. Claim updated: effect_depends_on.dag expects `EffectClassification {}` for the EffectDependsOn case (every dependency kind would produce the same row — the lens is intentionally signature-deferred). Acceptance: v2-compiler compile src/v4 → 120 modules / 124 files / 0 diagnostics. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Re: codex REQUEST_CHANGES on sha `7eac547b` — Verified valid; addressed in
Decoding Effect claim updated: Acceptance: `v2-compiler compile --source-root src/v4` → 120 modules / 124 files / 0 diagnostics. — sent from lively-cat-513 |
briansrls
left a comment
There was a problem hiding this comment.
Review metadata
- Provider / model:
codex/unknown - Commit:
4928f7b5· Trigger:schedule - Thinking:
337s wall
BLOCKING (3)
Root Cause
src/v4/lens/unused_parameters.dagThe behavioral roll-up lacks a typed consumer contract for declaration facts → carry only the declaration reference, or make consumers receive the InferredTree/query context and look up facts at use sites.src/v4/lens/unused_parameters.dagUnusedParametersFact has only a positive unused list and no declaration-level unresolved verdict → preserve RequiresResolutionWitness in the roll-up model or withhold/diagnose those candidates before emitting unused.src/v4/lens/unused_parameters.dagThe roll-up hand-rolls local variant-discriminant predicates instead of consuming a canonical UseRelation query/fold surface → add the modeled query surface or a bounded feature gate with dissolve-on-arrival.
| declaration: Node | ||
| dependency: DependencyView | ||
| use_site_facts: Witness<InferredFacts> | ||
| declaration_facts: Witness<InferredFacts> |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
| if already_in_unused(unused: acc, declaration: candidate) { | ||
| acc | ||
| } else { | ||
| if declaration_has_use(uses: use_fact.uses, declaration: candidate) { |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
| // IsUseOfDeclaration`. Roll-up scope is derived from the existing | ||
| // classification (feedback_scope_from_query_not_type_tag — scope is a | ||
| // query fact, not a substrate tag). | ||
| fn use_relation_is_use(relation: UseRelation) -> Bool { |
This comment was marked as resolved.
This comment was marked as resolved.
Sorry, something went wrong.
… (Practice 3)
Addresses BLOCKING inline review at src/v4/lens/unused_parameters.dag:57
(briansrls 2026-05-21T11:19:28Z): UnusedParameterFact carried
declaration_facts beside declaration, duplicating
tree.facts.lookup(declaration) and reintroducing the same Practice 3 / P2
facts-flow-by-copy defect this PR is meant to dissolve.
The Phase-1 design proposed declaration_facts on this row, but the
operator-direct sharpening is that Practice 3 reference-not-copy applies
*strictly* — even on the registry-aligned behavioral row.
declaration_facts == tree.facts.lookup(declaration) is a derivable
lookup, not a separately-authoritative fact.
Fix:
- UnusedParameterFact = { declaration: Node } only.
- unused_parameter_for_declaration drops the tree parameter.
- unused_parameter_fact_eq compares declaration only.
- rollup_unused drops the unused InferredTree parameter — matches the
Phase-1 composition shape exactly:
unused_parameters_fact(tree, deps) = rollup_unused(use_classification_fact(tree, deps))
- InferredFacts import dropped (unused).
- Rollup claim updated: expected entry is just { declaration: rollup_parameter }.
Acceptance: v2-compiler compile src/v4 → 120 modules / 124 files / 0
diagnostics.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…use evidence blocks the unused verdict
Addresses BLOCKING inline review at src/v4/lens/unused_parameters.dag:170
(briansrls 2026-05-21T11:19:28Z): rollup_unused recognized only
IsUseOfDeclaration as "use evidence", so a RequiresResolutionWitness
edge with source==candidate (the fail-closed slot for edge kinds the
lens couldn't classify — GeneratedFrom / VerifiedBy / PromotedBy /
BootstrapDependsOn) was treated as "no use", letting unresolved-use
evidence silently become an UnusedParameterFact. Fail-OPEN defect on
a fail-closed-by-design slot.
Fix: rename and broaden the use predicate.
declaration_has_use → declaration_has_use_or_unresolved.
The blocker set is {IsUseOfDeclaration, RequiresResolutionWitness}; an
edge with source==candidate and either classification blocks the
unused verdict. IsStructuralComposition and IsNonUseDependency remain
positive non-use evidence and do not block. The fail-closed slot now
behaves fail-closed at every consumer of the projection.
Acceptance: v2-compiler compile src/v4 → 120 modules / 124 files / 0
diagnostics.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…, tag the other 🟡
Addresses BLOCKING inline review at src/v4/lens/unused_parameters.dag:115
(briansrls 2026-05-21T11:19:28Z): use_relation_is_use (now renamed
use_relation_blocks_unused) and classification_is_structural_composition
were new Bool predicates over the UseRelation coproduct without
predicate-dissolution disposition tags (Practice 10 / P5).
Two-step fix:
1. **Dissolve** classification_is_structural_composition into the
existing `use_relation_eq` — it was just single-variant equality:
classification_is_structural_composition(r)
⇒ use_relation_eq(r, IsStructuralComposition)
The predicate is removed; `rollup_unused` calls `use_relation_eq`
directly. One fewer hand-rolled predicate over the coproduct.
2. **Tag 🟡** use_relation_blocks_unused (the genuinely-needed
2-class partition predicate). Disposition: dissolves on arrival of
a substrate variant-tag partition primitive ("partition variants
of <Coproduct> by <classifier>" parametric form). Until that lands
the match is hand-rolled with the dissolution-on-arrival obligation
tracked at the predicate.
Acceptance: v2-compiler compile src/v4 → 120 modules / 124 files / 0
diagnostics; strict_deprose_dag --check → OK.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Re: codex BLOCKING (×3) on sha `4928f7b5` — all three addressed in the commit burst between codex's SHA and current HEAD `61f7d689e`. Verifying each: 1. "behavioral roll-up lacks a typed consumer contract for declaration facts → carry only the declaration reference, or make consumers receive the InferredTree/query context and look up facts at use sites." ✅ Fixed in `c5561fdf4`. Took codex's option (a): 2. "UnusedParametersFact has only a positive unused list and no declaration-level unresolved verdict → preserve RequiresResolutionWitness in the roll-up model or withhold/diagnose those candidates before emitting unused." ✅ Fixed in `8a5a0fa12`. Took codex's "withhold" option: any 3. "The roll-up hand-rolls local variant-discriminant predicates instead of consuming a canonical UseRelation query/fold surface → add the modeled query surface or a bounded feature gate with dissolve-on-arrival." ✅ Fixed in `61f7d689e`. Took codex's option (b) — bounded feature gate. Two-step disposition:
Acceptance: `v2-compiler compile --source-root src/v4` → 120 modules / 124 files / 0 diagnostics; `strict_deprose_dag --check` → OK. — sent from lively-cat-513 |
briansrls
left a comment
There was a problem hiding this comment.
Review metadata
- Provider / model:
codex/unknown - Commit:
8c65950f· Trigger:schedule - Thinking:
201s wall
Non-blocking — Strengths
src/v4/std/dependency.dagThe mixed .dag/docs migration cleanly moves the T-13 family onto ClassifiedDependencyView without copied endpoint or fact payloads.
✅ No blocking concerns in the changed lines.
Summary
Phase 1 implementation of crisp-boar-896 design (operator-ratified 2026-05-21 via PM smart-lynx-142). Dissolves the recurring parallel-payload-vs-typed-reference anti-pattern (5th instance per memory
feedback_parallel_payload_vs_typed_reference_recurring.md) on the T-13 lens family.Substrate (v4.std.dependency)
One parametric T-13 lens row; endpoints live on the inner
DependencyView(single authority); per-lensCis the projection. Addsclassified_source/dependent/usage_sitefree-fn accessors + a parametricclassified_dependency_view_eqtaking a classification-eq comparator.Five lenses migrated (one mechanism, N projections)
v4.lens.parallelismParallelismRelationv4.lens.effectEffectClassification(minimal — see below)v4.lens.ownershipOwnershipModev4.lens.idempotencyIdempotencyVerdict(law witness rides the verdict variant)v4.lens.unused_parametersUseRelationEndpoint duplication removed from every row: no more
source/dependent/at/owner/subject/use_site/declarationparallel-payload fields on lens rows; endpoints read throughdependency.*accessors. Per-nodeInferredFactsno longer copied onto rows; consumers read at use-sites viatree.facts.lookup(...)(Practice 3 — Facts Flow Forward by reference).Split-contract for
UnusedParameters(Phase 1 step 3)unused_parameters.dagcarries both contracts in one module, registered as composition:Witness<UseClassificationFact>(T-13 family shape, per-edge classification).Witness<UnusedParametersFact>, the v3-aligned declaration roll-up forLensIdV0::UnusedParameters.UnusedParameterFact { declaration, declaration_facts }.unused_parameters_fact = rollup_unused ∘ use_classification_fact. No parallel mechanism; the registry-named output is derived from the projection.Test-claim template (Phase 1 step 4)
New
src/v4/test/claim/lens_common/infer_fixture.dagprovidesclaim_atom_node/claim_inferred_facts/claim_inferred_facts_map/claim_inferred_treeso every claim shares one fixture. Substrate evolution (e.g.InferredFactsfield changes in04_infer.dag) is now a single edit, not N edits across claim files (cost-of-change = 1). All 6 T-13 claim files migrated to the fixture; collateral cleanup of stale claimInferredFactsliterals (Phase-1 design "implementation hygiene" item) lands inside the same rewrite.Claims (5 lenses + 1 new roll-up)
lens_parallelism/data_dependency.dag— projection (DataDependsOn ⇒ DataDependent).lens_effect/effect_depends_on.dag— projection (EffectDependsOn ⇒ WriteEffect).lens_ownership/resource_dependency.dag— projection (ResourceDependsOn ⇒ RequiresAccessWitness).lens_idempotency/write_effect.dag— projection (EffectDependsOn ⇒ RequiresAlgebraWitness).lens_unused_parameters/binds_to_edge.dag— projection (BindsTo ⇒ IsUseOfDeclaration onUseClassificationFact).lens_unused_parameters/non_use_edges.dag— projection partition (Contains / DataDependsOn / GeneratedFrom ⇒ {IsStructuralComposition / IsNonUseDependency / RequiresResolutionWitness}).lens_unused_parameters/rollup_unused_declaration.dag(NEW) — behavioral: a declaration that sources only non-USE edges rolls up intoUnusedParametersFact.unused.Practice 11 sub-rule (Phase 1 step 5)
docs/modeling-discipline.md— new "Parallel-payload vs typed-reference" section under Practice 11 with worked instance, mechanical test, family-wide-ratchet disposition, and the 5-instance recurring table. Operator-direct standing 2026-05-19, ratified for this ratchet 2026-05-21.What's intentionally NOT in this PR
EffectClassificationcarries a minimal 4-variant slot withRequiresSignatureWitnessas the open variant routing to InferredFacts per B3. Refining it to the closed signature-derived effect kind set is a separate downstream lane; flagged 🟡 in the file header. The Phase-1 ratchet's job is the parametric-shape migration; effect-kind closure is its own substrate move.RequiresAccessWitness; closing the access carrier is a tracked follow-up.These are explicitly out of scope per Phase 1; the codex BLOCKING findings on #3468 were the motivating evidence for the ratchet, but the Phase-1 design scopes only the parametric-shape primitive + family migration + split-contract.
Test plan
Locally run on the migrated tree:
target/debug/v2-compiler compile --source-root src/v4 --output-dir /tmp/gunbc-v4-final→ 120 modules / 124 files emitted / 0 diagnosticspython3 scripts/strict_deprose_dag.py --check→ OKrg 'WholeFile|Whole[A-Z][A-Za-z]*' src/v4/lens/{parallelism,effect,ownership,idempotency,unused_parameters}.dag src/v4/std/dependency.dag→ no matches (scope-from-query discipline)rg -n 'source:|dependent:|use_site:|declaration:|owner:|subject:|at:' src/v4/lens/*.dagfiltered to exclude legitimateview.source/view.dependent/dependency.source/dependency.dependentprojections → only legitimate uses (declaration:inUnusedParameterFact { declaration: Node; declaration_facts: Witness<InferredFacts> }, the registry behavioral roll-up identity)*DependencyFacttypes acrosssrc/v4anddsl→ 0 results (only lens + claim files used them)References
feedback_parallel_payload_vs_typed_reference_recurring.md(5th instance),feedback_scope_from_query_not_type_tag.md(Practice 11 sub-rule sibling)