Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions dag/extdeps/w3c/svg.dag
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ data svg_rect_tag: String = "rect"
data svg_circle_tag: String = "circle"
data svg_text_tag: String = "text"
data svg_g_tag: String = "g"
data svg_style_tag: String = "style"

data svg_xmlns: String = "http://www.w3.org/2000/svg"
data svg_role_img: String = "img"
Expand Down Expand Up @@ -97,6 +98,16 @@ fn svg_document(view_box: String, class_name: String, aria_label: String, childr
)
}

// A STYLE ELEMENT, WHICH SVG 2 DEFINES AND THE MEDIUM ALREADY SUPPORTS. Without one an emitted
// document carries semantic class names and no presentation, so its text renders at the user
// agent's default size inside a coordinate space measured in micrometres -- legible only through
// an external stylesheet somebody writes by hand, which makes the artifact not self-contained.
// The content is emitted through the ordinary text escape, so a selector may not use the child
// combinator or an ampersand; descendant selectors express everything this document needs.
fn svg_style(css: String) -> Fragment {
svg_element(tag: svg_style_tag, attributes: [], children: [FragmentText { content: css }])
}

fn svg_group(class_name: String, children: List<Fragment>) -> Fragment {
svg_element(tag: svg_g_tag, attributes: [attr(name: "class", value: class_name)], children: children)
}
Expand Down
39 changes: 37 additions & 2 deletions dag/product/pcb/plan_view.dag
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import std.orthogonal_geometry {
}
import extdeps.w3c.svg {
svg_document,
svg_style,
svg_rect,
svg_text,
serialize_svg_document,
Expand Down Expand Up @@ -58,6 +59,15 @@ data legend_origin_y: Micrometer = micrometer(count: 12000)
data established_label_lift: Micrometer = micrometer(count: 1200)
data established_source_lift: Micrometer = micrometer(count: 2400)
data obligation_cause_drop: Micrometer = micrometer(count: 1800)

// TYPE SIZES IN THE BOARD'S OWN UNITS, because the coordinate space IS micrometres and a font size
// expressed in it is a length like any other. Without these the document carried semantic class
// names and no presentation, so every label rendered at the user agent's default size inside a
// 305 millimetre wide viewBox and was effectively invisible; the artifact was only readable
// through a stylesheet somebody wrote by hand outside it, which is not a self-contained emission.
data label_type_size: Micrometer = micrometer(count: 4400)
data cause_type_size: Micrometer = micrometer(count: 2600)
data legend_type_size: Micrometer = micrometer(count: 3000)
data legend_design_drop: Micrometer = micrometer(count: 2400)

type OutlineExtent {
Expand Down Expand Up @@ -294,12 +304,17 @@ fn element_fragments(e: PcbSceneElement, attachment_index: Int, body_layout: Pcb
}
}

// A FUNCTIONAL MARKER CONSUMES TWO LABEL SLOTS, because unlike an attachment marker it emits a
// cause line beneath its label. Advancing by one put the next label 2400 below while the cause sat
// 1800 below, so consecutive functional markers overlapped their own reasons. The defect arrived
// with the clock functions when they moved off the physical roster and was visible in the first
// emitted document anybody looked at.
fn fold_scene_fragments(scene: PcbEngineeringScene) -> List<Fragment> {
let body_layout = scene.world.physical.body_layout
let acc = fold(scene.elements, init: AttachmentLabelAcc { index: 0, fragments: [] }, f: fn(state, e) {
let next_index = match e {
SceneAttachmentMarker { layer: _, cause: _ } => state.index + 1
SceneFunctionalMarker { function: _, cause: _ } => state.index + 1
SceneFunctionalMarker { function: _, cause: _ } => state.index + 2
SceneBoardOutline { outline: _ } => state.index
SceneEstablishedBody { identity: _, origin: _, body_width: _, body_height: _, source: _ } => state.index
SceneObligationMarker { identity: _, origin: _, cause: _ } => state.index
Expand Down Expand Up @@ -372,7 +387,7 @@ fn project_pcb_world(w: PcbWorld) -> PcbSceneConstruction<PcbPlanViewScene> {
view_box: concat("0 0 ", concat(to_string(width), concat(" ", to_string(height)))),
class_name: "pcb-world-scene",
aria_label: "PCB plan view",
children: fragments,
children: concat([svg_style(css: plan_view_stylesheet())], fragments),
)
),
)
Expand All @@ -381,6 +396,26 @@ fn project_pcb_world(w: PcbWorld) -> PcbSceneConstruction<PcbPlanViewScene> {
}
}

// THE EMITTED STYLESHEET. Selectors are descendant-only and carry no ampersand, because the style
// text goes through the medium's ordinary escape; a child combinator would be escaped and the rule
// silently lost. Sizes come from the typed rows above rather than being spelled here twice.
fn plan_view_stylesheet() -> String {
concat(
concat("svg.pcb-world-scene text\{font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace}",
concat(".pcb-legend\{font-size:", concat(to_string(micrometer_count(m: legend_type_size)), "px;fill:#1a2744}"))),
concat(
concat(".pcb-legend-design\{font-size:", concat(to_string(micrometer_count(m: cause_type_size)), "px;fill:#5a6472}")),
concat(
concat(".pcb-label-subset-body,.pcb-label-established\{font-size:", concat(to_string(micrometer_count(m: label_type_size)), "px;fill:#1a2744}")),
concat(
concat(".pcb-component-unselected-part,.pcb-component-missing-document,.pcb-component-named-attachment-type-part-unresolved,.pcb-label-attachment-obligation,.pcb-label-functional-obligation\{font-size:", concat(to_string(micrometer_count(m: label_type_size)), "px;fill:#8a4a4a}")),
concat(".pcb-obligation-cause\{font-size:", concat(to_string(micrometer_count(m: cause_type_size)), "px;fill:#6b5a4a}"))
)
)
)
)
}

type PcbSceneEmission
= PcbSceneEmitted { source: String }
| PcbSceneEmissionRefused { cause: PcbSceneRefusal }
Expand Down
84 changes: 74 additions & 10 deletions dag/test/claim/altra_pcb_world_svg_witness_test.dag
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,9 @@ import product.pcb.world {
first_unsettled_capability,
}
import product.pcb.plan_view {
label_type_size,
cause_type_size,
attachment_label_step,
PcbSceneEmitted,
PcbSceneEmissionRefused,
PcbSceneReady,
Expand All @@ -72,7 +75,6 @@ import product.pcb.plan_view {
emit_pcb_plan_view,
represented_scene_labels,
attachment_label_base,
attachment_label_step,
}
import product.pcb.scene {
project_engineering_scene,
Expand Down Expand Up @@ -441,15 +443,20 @@ test fn w_unselected_roles_render_as_unselected_part() -> Bool {
}
}

// COUNTED ON THE CLASS ATTRIBUTE, NOT THE BARE NAME. These counts previously matched the class
// name anywhere in the document, which was an accurate element count only because nothing else
// mentioned those names. The emitted stylesheet mentions every one of them, so the old needle
// started counting its own selectors -- a proxy that silently stopped measuring elements. The
// attribute form counts elements, which is what the claim was always about.
test fn w_subset_bodies_are_not_drawn_as_checked() -> Bool {
match scene_or_empty() {
Absent => false
Present { value: s } =>
count_substring(haystack: s, needle: "pcb-component-established") == 0
&& count_substring(haystack: s, needle: "pcb-component-subset-body") == 2
&& count_substring(haystack: s, needle: "pcb-component-unselected-part") == 11
&& count_substring(haystack: s, needle: "pcb-component-named-attachment-type-part-unresolved") == 1
&& count_substring(haystack: s, needle: "pcb-component-missing-document") == 0
count_substring(haystack: s, needle: "class=\"pcb-component-established\"") == 0
&& count_substring(haystack: s, needle: "class=\"pcb-component-subset-body\"") == 2
&& count_substring(haystack: s, needle: "class=\"pcb-component-unselected-part\"") == 11
&& count_substring(haystack: s, needle: "class=\"pcb-component-named-attachment-type-part-unresolved\"") == 1
&& count_substring(haystack: s, needle: "class=\"pcb-component-missing-document\"") == 0
&& string_contains(s: s, pattern: "body layout admitted over established subset only; 12 parts owed")
&& !string_contains(s: s, pattern: "body layout checked over established subset only")
}
Expand Down Expand Up @@ -486,7 +493,7 @@ test fn w_mounting_and_socket_attachment_obligations_appear() -> Bool {
match scene_or_empty() {
Absent => false
Present { value: s } =>
string_contains(s: s, pattern: "attachment: mounting") && string_contains(s: s, pattern: "attachment: socket") && string_contains(s: s, pattern: "attachment: board land pattern") && count_substring(haystack: s, needle: "pcb-label-attachment-obligation") == pcb_attachment_obligation_count(p: pcb_world_physical(w: w))
string_contains(s: s, pattern: "attachment: mounting") && string_contains(s: s, pattern: "attachment: socket") && string_contains(s: s, pattern: "attachment: board land pattern") && count_substring(haystack: s, needle: "class=\"pcb-label-attachment-obligation\"") == pcb_attachment_obligation_count(p: pcb_world_physical(w: w))
}
}
}
Expand Down Expand Up @@ -527,7 +534,7 @@ test fn w_plan_view_unselected_marker_count_follows_population() -> Bool {
match projected_document(ids: ["m0", "m1", "m2", "m3", "m4", "m5"]) {
Absent => false
Present { value: six_doc } =>
count_substring(haystack: four_doc, needle: "pcb-component-unselected-part") == 4 && count_substring(haystack: six_doc, needle: "pcb-component-unselected-part") == 6
count_substring(haystack: four_doc, needle: "class=\"pcb-component-unselected-part\"") == 4 && count_substring(haystack: six_doc, needle: "class=\"pcb-component-unselected-part\"") == 6
}
}
}
Expand All @@ -539,8 +546,8 @@ test fn w_plan_view_missing_document_count_follows_population() -> Bool {
match projected_missing_document(ids: ["p0", "p1", "p2"]) {
Absent => false
Present { value: three_doc } =>
count_substring(haystack: two_doc, needle: "pcb-component-missing-document") == 2
&& count_substring(haystack: three_doc, needle: "pcb-component-missing-document") == 3
count_substring(haystack: two_doc, needle: "class=\"pcb-component-missing-document\"") == 2
&& count_substring(haystack: three_doc, needle: "class=\"pcb-component-missing-document\"") == 3
}
}
}
Expand Down Expand Up @@ -859,3 +866,60 @@ test fn w_no_clock_device_appears_in_the_physical_population() -> Bool {
&& !string_contains(s: s, pattern: "clock_fanout<")
}
}

// THE DOCUMENT CARRIES ITS OWN PRESENTATION. Without this the emitted SVG was semantically
// complete and visually unreadable: class names with no sizes, rendered at a user agent default
// inside a coordinate space measured in micrometres. A viewer had to supply a stylesheet from
// outside, which means the artifact was not self-contained and two people looking at the same
// emission could see different things. The sizes are asserted against the typed rows rather than
// spelled again here, so editing a size cannot leave this witness agreeing with a stale number.
test fn w_the_emitted_document_carries_its_own_type_sizing() -> Bool {
match scene_or_empty() {
Absent => false
Present { value: s } =>
string_contains(s: s, pattern: "<style>")
&& string_contains(s: s, pattern: concat("font-size:", concat(to_string(micrometer_count(m: label_type_size)), "px")))
&& string_contains(s: s, pattern: concat("font-size:", concat(to_string(micrometer_count(m: cause_type_size)), "px")))
&& string_contains(s: s, pattern: ".pcb-obligation-cause")
}
}

// AND NO SELECTOR SURVIVED THE TEXT ESCAPE MANGLED. The style content is emitted through the
// medium's ordinary escape, so a child combinator or an ampersand would arrive as an entity and
// the rule would be silently dropped -- present in the document, matching nothing. This asserts
// the escape did not fire, which is the failure that looks like success.
test fn w_no_style_selector_was_escaped() -> Bool {
match scene_or_empty() {
Absent => false
Present { value: s } =>
!string_contains(s: s, pattern: "&gt;")
&& !string_contains(s: s, pattern: "&amp;")
&& !string_contains(s: s, pattern: "&lt;/style")
}
}

// THE SECOND UNREALIZED FUNCTION SITS BELOW THE FIRST ONE'S REASON LINE, asserted on the emitted
// coordinate rather than on the constants. An earlier version of this witness compared the label
// step against the cause drop, which is a fact about two data rows and stays true no matter what
// the fold does with them -- it passed with the defect reinstated, which makes it evidence that
// cannot fail. This derives the expected y for the second functional label from the same rows the
// emitter uses and looks for it attached to that label in the document, so reverting the fold to
// advance by one moves the label to a different coordinate and turns this red.
fn expected_second_function_label() -> String {
match world_or_empty() {
Absent => ""
Present { value: w } =>
let attachments = pcb_attachment_obligation_count(p: pcb_world_physical(w: w))
let y = micrometer_count(m: attachment_label_base) + ((attachments + 2) * micrometer_count(m: attachment_label_step))
concat("y=\"", concat(to_string(y), "\" class=\"pcb-label-functional-obligation\">function unrealized: clock fanout"))
}
}

test fn w_the_second_function_label_clears_the_first_ones_cause_line() -> Bool {
match scene_or_empty() {
Absent => false
Present { value: s } =>
expected_second_function_label() != ""
&& string_contains(s: s, pattern: expected_second_function_label())
}
}
Loading