Skip to content

Commit 4848cfd

Browse files
committed
test(ownir): give every composition input a witness that dies without it
RED for #259 cp4's wiring. No production code: the oracle grows, the port has nothing new to satisfy it with, and the next commit is what turns it green. WHAT THE CORPUS ACTUALLY OBSERVED. The 37 frozen cases read like a corpus and are a historical accident. Measured across them: `di` reaches DI001 and nothing else — seven of its eight cases being one coordinate band walked through the same code — and `effects` reaches its single storm witness. So `di=9` looked like coverage and was one mechanism out of five. Six of the eleven fields the DI adapter builds are invisible to every frozen case: `weak_deps` (DI002), `disposable` (DI003/DI004), `root_resolves` + `root_resolve_sites` (DI004), `scope_cached` + `scope_cache_sites` (DI005). A composition that wired none of them replayed all 37 clean. That is the hole b66b10d closed for `effects`, six fields wide — and closing a checkpoint the same way twice would stop being an accident. `disposable` is the sharpest. There is no typed `disposable` on `own_ir::Service`; it arrives through the flattened `extra` map, so an adapter reading the named fields loses it with NO compile error, and DI003/DI004 go quiet. The reference is `s.get("disposable") is True` — the JSON boolean and nothing else, so a stray `"false"` must not coerce. NINE WITNESSES, one per unobservable input, existing cases untouched: DI002 weak_deps DI003 disposable DI004 root_resolves + root_resolve_sites, site line 1 -> call.cs:1 DI004 the same document, site line 0 -> falls back to reg.cs:5 DI005 scope_cached + scope_cache_sites, site line 1 -> store.cs:1 DI005 the same document, site line 0 -> falls back to reg.cs:5 EFF init: call -> silent (isolates bindings[].init) EFF io: false -> silent (isolates the IO gate) EFF deps: [] -> silent (isolates the dependency set) The DI004/005 pairs sit at 1 and 0 — the first value the `>= 1` site sentinel admits and the last it rejects — and their sites differ from the registration in FILE as well as line, so a mis-anchored verdict shows up in the frozen `(path, line, code)` rather than only in a number. Deliberately not another walk through i64::MIN..MAX: the signed carrier is already proven by the coordinate band, and the sentinel is a switch, not a range. Measuring a switch with a ruler is how the first census read 0/0/0. `ctor_file`/`ctor_line`/`ctor_type` are NOT here. Measured on the reference they surface as `related` evidence, so they cannot change a cp4-shaped verdict and must not become a cp4 blocker; they belong to cp5's Finding mapping. TWO GUARDS make the rule mechanical instead of remembered. `REQUIRED_CODES` fails — not warns — when a gating channel exhibits no case for a code, naming the input nothing would then observe; the `effects` hole was a warning for exactly as long as it took to write the code it let through. `DISCRIMINATING_PAIRS` fails when the two halves of a boundary pair agree, because a pair whose halves match has stopped being evidence while the file stays green. The summary line now prints the observed CODE SET, since a row count is what made `di=9` look like coverage. A SECOND TRAP, found while building these and now witnessed: `root_resolve_sites` is a list of OBJECTS on the OwnIR wire (`own_ir::Site`, spec §4.2) and a list of `(type, file, line)` TRIPLES at the fact-level boundary in `di_eff_fact_parity.json`. A composition that reuses the fact-level shape parses every field as absent and loses the site in silence. The `-site-primary` witnesses die on exactly that. VERIFIED BY MUTATING THE DOCUMENTS, not by reading them: 13 mutations over the witness set — each of the six fields dropped, `disposable` swapped to the string `"false"`, the sites downgraded to fact-level triples, `init` moved between stability classes, and every registration line moved onto the site line. Each mutation proved it applied before any verdict was computed. All 13 land as declared, and the isolation half holds too: the io=false and deps=[] negatives do NOT react to an `init` change, which is what makes them isolate a wire rather than answer to any input. Refs #250, #259. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_017umyRWQed6WaoRbVagGYVw
1 parent d8d32fb commit 4848cfd

2 files changed

Lines changed: 696 additions & 47 deletions

File tree

‎tests/fixtures/ownir/verdicts.json‎

Lines changed: 350 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,356 @@
447447
"origin": "witness",
448448
"protocols": []
449449
},
450+
{
451+
"advisories": [],
452+
"core": [],
453+
"di": [],
454+
"document": {
455+
"effects": [
456+
{
457+
"bindings": [
458+
{
459+
"init": "call",
460+
"line": 1,
461+
"name": "opts",
462+
"refs": []
463+
}
464+
],
465+
"component": "A",
466+
"deps": [
467+
"opts"
468+
],
469+
"file": "A.tsx",
470+
"io": true,
471+
"line": 10
472+
}
473+
],
474+
"module": "M",
475+
"ownir_version": 0
476+
},
477+
"effects": [],
478+
"family": "effects channel (bindings[].init: call -> no verdict)",
479+
"name": "composition-effect-opaque-call-silent",
480+
"origin": "witness",
481+
"protocols": []
482+
},
483+
{
484+
"advisories": [],
485+
"core": [],
486+
"di": [],
487+
"document": {
488+
"effects": [
489+
{
490+
"bindings": [
491+
{
492+
"init": "object",
493+
"line": 1,
494+
"name": "opts",
495+
"refs": []
496+
}
497+
],
498+
"component": "A",
499+
"deps": [
500+
"opts"
501+
],
502+
"file": "A.tsx",
503+
"io": false,
504+
"line": 10
505+
}
506+
],
507+
"module": "M",
508+
"ownir_version": 0
509+
},
510+
"effects": [],
511+
"family": "effects channel (io: false -> no verdict)",
512+
"name": "composition-effect-no-io-silent",
513+
"origin": "witness",
514+
"protocols": []
515+
},
516+
{
517+
"advisories": [],
518+
"core": [],
519+
"di": [],
520+
"document": {
521+
"effects": [
522+
{
523+
"bindings": [
524+
{
525+
"init": "object",
526+
"line": 1,
527+
"name": "opts",
528+
"refs": []
529+
}
530+
],
531+
"component": "A",
532+
"deps": [],
533+
"file": "A.tsx",
534+
"io": true,
535+
"line": 10
536+
}
537+
],
538+
"module": "M",
539+
"ownir_version": 0
540+
},
541+
"effects": [],
542+
"family": "effects channel (deps: [] -> no verdict)",
543+
"name": "composition-effect-no-deps-silent",
544+
"origin": "witness",
545+
"protocols": []
546+
},
547+
{
548+
"advisories": [],
549+
"core": [],
550+
"di": [
551+
[
552+
"reg.cs",
553+
5,
554+
"DI002"
555+
]
556+
],
557+
"document": {
558+
"module": "M",
559+
"ownir_version": 0,
560+
"services": [
561+
{
562+
"file": "reg.cs",
563+
"lifetime": "singleton",
564+
"line": 5,
565+
"name": "App",
566+
"weak_deps": [
567+
"Db"
568+
]
569+
},
570+
{
571+
"file": "reg.cs",
572+
"lifetime": "scoped",
573+
"line": 6,
574+
"name": "Db"
575+
}
576+
]
577+
},
578+
"effects": [],
579+
"family": "di channel (services[].weak_deps -> DI002)",
580+
"name": "composition-di002-weak-deps",
581+
"origin": "witness",
582+
"protocols": []
583+
},
584+
{
585+
"advisories": [],
586+
"core": [],
587+
"di": [
588+
[
589+
"reg.cs",
590+
5,
591+
"DI003"
592+
]
593+
],
594+
"document": {
595+
"module": "M",
596+
"ownir_version": 0,
597+
"services": [
598+
{
599+
"deps": [
600+
"Conn"
601+
],
602+
"file": "reg.cs",
603+
"lifetime": "singleton",
604+
"line": 5,
605+
"name": "App"
606+
},
607+
{
608+
"disposable": true,
609+
"file": "reg.cs",
610+
"lifetime": "transient",
611+
"line": 6,
612+
"name": "Conn"
613+
}
614+
]
615+
},
616+
"effects": [],
617+
"family": "di channel (services[].disposable -> DI003)",
618+
"name": "composition-di003-transient-disposable",
619+
"origin": "witness",
620+
"protocols": []
621+
},
622+
{
623+
"advisories": [],
624+
"core": [],
625+
"di": [
626+
[
627+
"call.cs",
628+
1,
629+
"DI004"
630+
]
631+
],
632+
"document": {
633+
"module": "M",
634+
"ownir_version": 0,
635+
"services": [
636+
{
637+
"file": "reg.cs",
638+
"lifetime": "singleton",
639+
"line": 5,
640+
"name": "App",
641+
"root_resolve_sites": [
642+
{
643+
"file": "call.cs",
644+
"line": 1,
645+
"type": "Conn"
646+
}
647+
],
648+
"root_resolves": [
649+
"Conn"
650+
]
651+
},
652+
{
653+
"disposable": true,
654+
"file": "reg.cs",
655+
"lifetime": "transient",
656+
"line": 6,
657+
"name": "Conn"
658+
}
659+
]
660+
},
661+
"effects": [],
662+
"family": "di channel (root_resolve_sites line 1 -> site anchor)",
663+
"name": "composition-di004-site-primary",
664+
"origin": "witness",
665+
"protocols": []
666+
},
667+
{
668+
"advisories": [],
669+
"core": [],
670+
"di": [
671+
[
672+
"reg.cs",
673+
5,
674+
"DI004"
675+
]
676+
],
677+
"document": {
678+
"module": "M",
679+
"ownir_version": 0,
680+
"services": [
681+
{
682+
"file": "reg.cs",
683+
"lifetime": "singleton",
684+
"line": 5,
685+
"name": "App",
686+
"root_resolve_sites": [
687+
{
688+
"file": "call.cs",
689+
"line": 0,
690+
"type": "Conn"
691+
}
692+
],
693+
"root_resolves": [
694+
"Conn"
695+
]
696+
},
697+
{
698+
"disposable": true,
699+
"file": "reg.cs",
700+
"lifetime": "transient",
701+
"line": 6,
702+
"name": "Conn"
703+
}
704+
]
705+
},
706+
"effects": [],
707+
"family": "di channel (root_resolve_sites line 0 -> registration anchor)",
708+
"name": "composition-di004-site-fallback",
709+
"origin": "witness",
710+
"protocols": []
711+
},
712+
{
713+
"advisories": [],
714+
"core": [],
715+
"di": [
716+
[
717+
"store.cs",
718+
1,
719+
"DI005"
720+
]
721+
],
722+
"document": {
723+
"module": "M",
724+
"ownir_version": 0,
725+
"services": [
726+
{
727+
"file": "reg.cs",
728+
"lifetime": "singleton",
729+
"line": 5,
730+
"name": "App",
731+
"scope_cache_sites": [
732+
{
733+
"file": "store.cs",
734+
"line": 1,
735+
"type": "Db"
736+
}
737+
],
738+
"scope_cached": [
739+
"Db"
740+
]
741+
},
742+
{
743+
"file": "reg.cs",
744+
"lifetime": "scoped",
745+
"line": 6,
746+
"name": "Db"
747+
}
748+
]
749+
},
750+
"effects": [],
751+
"family": "di channel (scope_cache_sites line 1 -> site anchor)",
752+
"name": "composition-di005-site-primary",
753+
"origin": "witness",
754+
"protocols": []
755+
},
756+
{
757+
"advisories": [],
758+
"core": [],
759+
"di": [
760+
[
761+
"reg.cs",
762+
5,
763+
"DI005"
764+
]
765+
],
766+
"document": {
767+
"module": "M",
768+
"ownir_version": 0,
769+
"services": [
770+
{
771+
"file": "reg.cs",
772+
"lifetime": "singleton",
773+
"line": 5,
774+
"name": "App",
775+
"scope_cache_sites": [
776+
{
777+
"file": "store.cs",
778+
"line": 0,
779+
"type": "Db"
780+
}
781+
],
782+
"scope_cached": [
783+
"Db"
784+
]
785+
},
786+
{
787+
"file": "reg.cs",
788+
"lifetime": "scoped",
789+
"line": 6,
790+
"name": "Db"
791+
}
792+
]
793+
},
794+
"effects": [],
795+
"family": "di channel (scope_cache_sites line 0 -> registration anchor)",
796+
"name": "composition-di005-site-fallback",
797+
"origin": "witness",
798+
"protocols": []
799+
},
450800
{
451801
"advisories": [],
452802
"core": [],

0 commit comments

Comments
 (0)