Repository navigation
Wave-4-A — find_witness enumeration and coercion_fold identity-MVP body fill #3473
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 9 commits
e87f3d9
88fe2d2
e6b9c07
f387b7a
35784a8
a6abe14
20db35f
a9570c3
1273d23
d5e292a
684ee62
625f2e6
fc74b0a
bd676d4
96c8e92
9d8141f
59b6d9f
46f6599
10f0ca2
83208c5
f091757
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -13,14 +13,16 @@ module v4.std.find_witness | |
|
|
||
| import v4.std.collection { List } | ||
| import v4.std.diagnostic { | ||
| Accepted, | ||
| Diagnostic, | ||
| ExternalContractUnknown, | ||
| None, | ||
| NodeLocus, | ||
| Outcome, | ||
| Unavailable, | ||
| outcome_rejected | ||
| } | ||
| import v4.std.node { Node, Symbol } | ||
| import v4.std.node { Node, Symbol, well_formed } | ||
| import v4.std.witness { StructuralPropertyWitness } | ||
| data find_witness_reason_no_candidate: Symbol = find_witness_reason_no_candidate | ||
| data find_witness_reason_ambiguous_candidate: Symbol = find_witness_reason_ambiguous_candidate | ||
|
|
@@ -70,19 +72,166 @@ fn find_witness_not_realized_diagnostic(source_facts: Node) -> Diagnostic { | |
| correction: Unavailable { reason: ExternalContractUnknown } | ||
| } | ||
| } | ||
| // 🟡 coproduct dissolution — scaffold:exact-structural-preservation-identity-mvp · dissolve-on: W-T-10 structural zip-fold predicate algebra; exact_structural_equality accepts only source-identical Node evidence and other preservation rules fail closed. | ||
| fn preservation_predicate_holds( | ||
| source_facts: Node, | ||
| candidate: Node, | ||
| predicate: PreservationPredicate, | ||
| ) -> Bool { | ||
| well_formed(n: source_facts) | ||
| && well_formed(n: predicate.algebra) | ||
| && well_formed(n: candidate) | ||
| && (predicate.preservation_rule == preservation_rule_exact_structural_equality_zip_fold) | ||
| && (predicate.algebra == source_facts) | ||
| && (candidate == source_facts) | ||
| } | ||
| fn passing_candidate_count( | ||
| source_facts: Node, | ||
| candidates: CandidateSet, | ||
| predicate: PreservationPredicate, | ||
| ) -> Int { | ||
| fold(candidates.candidates, init: 0, f: fn(acc, candidate) { | ||
| if preservation_predicate_holds( | ||
| source_facts: source_facts, | ||
| candidate: candidate, | ||
This comment was marked as resolved.
Sorry, something went wrong.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Verified against current PR head
Relevant current-head locations:
No code change needed for this stale finding. — sent from swift-lark-412 |
||
| predicate: predicate | ||
| ) { | ||
| acc + 1 | ||
| } else { | ||
| acc | ||
| } | ||
| }) | ||
| } | ||
| fn only_passing_candidate( | ||
| source_facts: Node, | ||
| candidates: CandidateSet, | ||
| predicate: PreservationPredicate, | ||
| ) -> Node { | ||
| fold(candidates.candidates, init: source_facts, f: fn(acc, candidate) { | ||
This comment was marked as resolved.
Sorry, something went wrong.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Verified against current PR head Current behavior:
So the helper no longer has a fabricated source-node fallback and cannot return a node that was not selected from the closed candidate set. — sent from swift-lark-412 |
||
| if preservation_predicate_holds( | ||
| source_facts: source_facts, | ||
| candidate: candidate, | ||
| predicate: predicate | ||
| ) { | ||
| candidate | ||
| } else { | ||
| acc | ||
| } | ||
| }) | ||
| } | ||
| fn selected_candidate_count( | ||
| source_facts: Node, | ||
| candidates: CandidateSet, | ||
| predicate: PreservationPredicate, | ||
| selection: Node, | ||
| ) -> Int { | ||
| fold(candidates.candidates, init: 0, f: fn(acc, candidate) { | ||
| if (candidate == selection) && preservation_predicate_holds( | ||
| source_facts: source_facts, | ||
| candidate: candidate, | ||
| predicate: predicate | ||
| ) { | ||
| acc + 1 | ||
| } else { | ||
| acc | ||
| } | ||
| }) | ||
| } | ||
| fn accepted_witness_result( | ||
| candidate: Node, | ||
| candidates: CandidateSet, | ||
| predicate: PreservationPredicate, | ||
| ) -> Outcome<FindWitnessResult> { | ||
| Accepted { | ||
| value: FindWitnessResult { | ||
| candidate: candidate, | ||
| witness: StructuralPropertyWitness { | ||
| property: predicate.preservation_rule, | ||
| evidence: candidate | ||
| }, | ||
| closedness: candidates.closedness | ||
| }, | ||
| diagnostics: None | ||
| } | ||
| } | ||
| fn resolve_selected_candidate( | ||
| source_facts: Node, | ||
| candidates: CandidateSet, | ||
| predicate: PreservationPredicate, | ||
| selection: Node, | ||
| ) -> Outcome<FindWitnessResult> { | ||
| match selected_candidate_count( | ||
| source_facts: source_facts, | ||
| candidates: candidates, | ||
| predicate: predicate, | ||
| selection: selection | ||
| ) { | ||
| 1 => accepted_witness_result( | ||
| candidate: selection, | ||
| candidates: candidates, | ||
| predicate: predicate | ||
| ) | ||
| 0 => outcome_rejected(find_witness_no_candidate_diagnostic(source_facts: source_facts)) | ||
| _ => outcome_rejected(find_witness_ambiguous_candidate_diagnostic(source_facts: source_facts)) | ||
| } | ||
| } | ||
| fn find_witness( | ||
| source_facts: Node, | ||
| candidates: CandidateSet, | ||
| predicate: PreservationPredicate, | ||
| multiplicity_policy: MultiplicityPolicy, | ||
| ) -> Outcome<FindWitnessResult> { | ||
| outcome_rejected(find_witness_not_realized_diagnostic(source_facts: source_facts)) | ||
| let passing_count = passing_candidate_count( | ||
| source_facts: source_facts, | ||
| candidates: candidates, | ||
| predicate: predicate | ||
| ) | ||
| match passing_count { | ||
| 0 => outcome_rejected(find_witness_no_candidate_diagnostic(source_facts: source_facts)) | ||
| 1 => accepted_witness_result( | ||
| candidate: only_passing_candidate( | ||
| source_facts: source_facts, | ||
| candidates: candidates, | ||
| predicate: predicate | ||
| ), | ||
| candidates: candidates, | ||
| predicate: predicate | ||
| ) | ||
| _ => match multiplicity_policy { | ||
| UniqueOnly => | ||
| outcome_rejected(find_witness_ambiguous_candidate_diagnostic(source_facts: source_facts)) | ||
| TargetSelection { policy: p } => match p { | ||
| TargetDeclaredPriority { priority: priority } => | ||
| resolve_selected_candidate( | ||
| source_facts: source_facts, | ||
| candidates: candidates, | ||
| predicate: predicate, | ||
| selection: priority | ||
| ) | ||
| UserSelected { selection: selection } => | ||
| resolve_selected_candidate( | ||
| source_facts: source_facts, | ||
| candidates: candidates, | ||
| predicate: predicate, | ||
| selection: selection | ||
| ) | ||
| } | ||
| } | ||
| } | ||
| } | ||
| fn verify_witness( | ||
| source_facts: Node, | ||
| candidate: Node, | ||
| predicate: PreservationPredicate, | ||
| witness: StructuralPropertyWitness, | ||
| ) -> Outcome<StructuralPropertyWitness> { | ||
| outcome_rejected(find_witness_not_realized_diagnostic(source_facts: source_facts)) | ||
| if preservation_predicate_holds( | ||
| source_facts: source_facts, | ||
| candidate: candidate, | ||
| predicate: predicate | ||
| ) && (witness.property == predicate.preservation_rule) && (witness.evidence == candidate) { | ||
| Accepted { value: witness, diagnostics: None } | ||
| } else { | ||
| outcome_rejected(find_witness_no_candidate_diagnostic(source_facts: source_facts)) | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BLOCKING: coercion_candidate_set_from_declared_inhabitants mints CandidateSet.closedness from an arbitrary inhabitants_root without checking it is a well-formed closed-set carrier, so malformed target models can become trusted candidate sets instead of diagnostics under P2/P3.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Verified valid and fixed on current PR head
46f65997.coercion_candidate_set_from_declared_inhabitantsnow returnsOutcome<CoercionCandidateSet>and checkswell_formed(n: inhabitants_root)before minting theCandidateSet.closednesswitness. Malformed roots now returnoutcome_rejected(coercion_candidate_set_not_closed_diagnostic(...))instead of becoming trusted candidate sets.06_translate.dagwas updated to consume thatOutcomedirectly rather than wrapping the constructor result inAccepted.Verification run for this fix:
python3 scripts/test_strict_deprose_dag.py: PASSpython3 scripts/strict_deprose_dag.py --check: PASSgit diff --check: PASSrg -n "import v4\\.lens" src/v4/compiler src/v4/std: no matchescargo test -p v3-compiler --test integration v4_bin_main_dag_smoke_test::v4_bin_main_dag_tokenizes_and_parses_with_trampoline_source_anchor -- --exact --quiet: PASS remotelycargo test -p v3-compiler --test integration v4_compiler_emit_translate_smoke_test -- --quiet: PASS remotely— sent from swift-lark-412