Skip to content

feat(core): containment is traversable without being drawn - #1452

Merged
lex00 merged 3 commits into
mainfrom
feat/containment-is-traversable
Aug 3, 2026
Merged

feat(core): containment is traversable without being drawn#1452
lex00 merged 3 commits into
mainfrom
feat/containment-is-traversable

Conversation

@lex00

@lex00 lex00 commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Supersedes #1437, which fixed this by hand. The question that prompted the rewrite: shouldn't this be expanded rather than hand-maintained? It should.

What was wrong

reconstructEdges made a containment rule traversable only if the rule set viaAttr. That one field decided two unrelated things — "draw this as a line" (a renderer's concern) and "let a query walk this" (a caller's concern) — so making a relationship queryable meant drawing it, and the list of which relationships had been remembered was the list of which questions could be asked.

AWS::EC2::Instance -> Subnet had been remembered. AWS::EC2::NetworkInterface -> Subnet had not. So kind:EC2::Subnet !<-kind:EC2::NetworkInterface — the query the grammar exists to express — matched 23 of 23 subnets on an estate where 8 of 13 are empty. An inert negation is indistinguishable from one that searched and found nothing.

Three changes, all general

1. containmentEdges. The same pairs, as edges a query can walk, with the traversal name derived from the attribute path the containment was read through. A containment rule is now traversable because it is a containment rule, not because someone remembered. edges is untouched, so reference-catalog.test.ts's expect(edges.some(e => e.to === "vpc")).toBe(false) still holds and renderers gain no lines.

2. Instance -> VPC. Subnet, security group and route table all had an "in VPC" rule; the instance did not. So the one kind every estate question is about reached its VPC only through its subnet — two hops, which a one-hop <- cannot cross. describe-instances returns VpcId directly; nothing is inferred.

3. Containment survives the overlay. sourceOverlayGraphs admits a live edge only when one endpoint is foreign, because "declared edges already cover every declared relationship". True of the references it was written for, false of containment — no source declares "this instance is in this VPC"; the instance declares a subnet and the VPC is implied by the account. So an instance and its VPC, both declared, had their containment dropped between them, while an instance in the account's default VPC kept it because that VPC is foreign.

That asymmetry is what the measurement showed: "which VPCs have no instances" answered correctly for the one VPC nobody declared and wrongly for every VPC somebody did. Containment now merges into the queried IR after the overlay, so it is never subject to a filter written for a different kind of edge.

Measured against a live estate

Ground truth 13 subnets (8 empty) and 6 VPCs (2 empty):

build empty subnets empty VPCs
before 23 (every subnet) 6 (every VPC)
+ containmentEdges 8 6
+ Instance -> VPC 8 5
+ overlay fix 8 2

Zero hand-added viaAttr flags — the AWS catalog's count is unchanged from main.

Full suite 10498 passed, 5 skipped. Typecheck and lint clean.

Closes #1432

🤖 Generated with Claude Code

https://claude.ai/code/session_014KoduiMJRyLqjFYBUbMskE

lex00 added a commit to INTENTIUS/chant-bench that referenced this pull request Aug 3, 2026
The middle of a replicate set rather than a single run, the same rule the board
uses — and here it matters more, not less. Six trials move further than
twenty-four do: on one build these questions returned 3, 4 and 6 of 6 with
nothing changed between the runs.

    before the kind fix   3/6, 4/6, 6/6   median 4/6
    after                 6/6, 6/6, 6/6   median 6/6, no spread at all

That is a real shift rather than another draw from the same distribution, and
the variance collapsing is the more convincing half.

## What was making it noisy

Not the traversal — the counting. `kind:` is a substring, and a substring of a
CloudFormation type crosses kind boundaries: `kind:EC2::VPC` also matched
`AWS::EC2::VPCGatewayAttachment` and `kind:EC2::Subnet` also matched
`AWS::EC2::SubnetRouteTableAssociation`. An estate holding 6 VPCs answered 9.

Agents were naming exactly the right VPCs and reporting "9 VPCs in the estate"
beside them, and the grader failed the answer for contradicting the estate —
correctly, because it did. The finding was right and the census next to it was
of a set nobody asked for. Fixed in INTENTIUS/chant#1451.

The traversal work that made the questions answerable at all is
INTENTIUS/chant#1452, which replaced a per-rule opt-in with containment being
traversable by construction.

## A provenance error, found and corrected

`chant-neg-3/4/5` were published claiming workspace `30c405b9a8f5`. They ran
against `787ab0fd5bd0`; the emitter read the fingerprint file at emit time and
that file had been overwritten by a later export. Corrected here from the build
logs, and made impossible in lex00/aws-bench#11 — the runner now records the
fingerprint into the job.

Worth stating plainly because the correction changes what the table says: the
three runs either side of the kind fix are NOT the same experiment, and the
mis-stamp had made them look like they were.

Refs #27

Claude-Session: https://claude.ai/code/session_014KoduiMJRyLqjFYBUbMskE

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
@lex00
lex00 merged commit 93b262a into main Aug 3, 2026
5 checks passed
@lex00
lex00 deleted the feat/containment-is-traversable branch August 3, 2026 21:24
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.

Ambient resources are recorded with no edges, so the graph over-reports every "nothing points at this" question

1 participant