Vextor

VXL conventions card

Paste the block below into an agent prompt before asking for a VXL document.

VXL v1 CONVENTIONS — read before writing
Write the compact form: one statement per line (one array element per line); omit "title" and
"notes"; omit every field equal to its default. These are preference, not schema.
Top level: {"schema":"vextor.vxl.v1","id":"...","std":"vxl-std-2","units":
  {"length":"mm","angle":"deg"},"defs":[...],"parts":[...]}.
Unknown keys are errors. Units mm and degrees; literals are JSON numbers; expressions are strings
("width / 2"). Angles stay degrees; only trig crosses radians.
Frame: right-handed, +Z up. Author every part in the frame the request uses; add an occurrence pose
only for repeated parts. Creators sit at the origin: box min corner (0,0,0); cylinder base disk
centred on (0,0) with axis +Z. Move with "at":[x,y,z]; turn with "rotate":[{"axis":"+x","deg":90}]
(rotations first, then "at"). Never write quaternions.
Sketch: "plane" xy|yz|xz; profile coordinates are world coordinates on the plane's two axes
(xy->(x,y), yz->(y,z), xz->(x,z)); the plane sits at "at" on its missing axis (default 0); extrude
"toward" a world direction perpendicular to the plane (+x/-x/+y/-y/+z/-z) by "length". There is no
"side" and no "origin".
Holes: "at" is the entry point on a planar face; "axis" is the inward normal of that face ("-z"
drills down) — a tilted, sideways or outward axis is refused, never snapped: C441 while the target
is a box/cylinder no step has changed yet, else X111 at build. "depth":"through" cuts
everything on the ray, else a blind length; a blind hole deeper than its wall is a port and has no
".floor" (Q513/X101). One style per hole: "counterbore"
{diameter,depth}, "countersink" {diameter,angle} (default 90; construction never accepts "at"), or
"thread" {pitch} (a modelled internal thread; verify it with a required "thread" requirement)
and only while it is in the delivered body); the style must
fit the material behind the entry face (the wall of a shelled part): C440/X109 otherwise. The alias
kinds "counterbored_hole", "countersunk_hole", "fillet", "contact" and "chamfer" are refused;
write the base kind with the style. "targets":[2..8 bindings] drills one hole into several plates; names become
"<step>_<k>.wall"/".rim", and a style adds ".cbore"/".shoulder"/".cone"/".floor". "place"
{target, place:{translate?,rotate?}} re-poses a binding rigidly (keeps its name; N122 if a contained
name cannot move). "shell" {target, thickness (0,20] mm, open:{select,expect} (1..8 faces)} hollows
inward, erases the opened faces' names (Q511-Q514, C436, X106) and is verified by minimum_wall plus
planar_face at outer ± thickness; shell before small fillets/chamfers.
Booleans: union|cut|intersect {target, tool, bind?, tool_place?, alias?}. Tools are not consumed.
"bind" defaults to target and replaces it. At most 16 live bindings, and after expansion a
document runs at most 256 session operations across all parts (a multi-target hole counts once per
target; C421). Mirror keeps the original and
adds the reflected copy.
Import: "assets":[{"id","media_type":"model/step","digest","bytes"}] (up to 8, 8 MiB combined);
"import" {bind,asset,source_units:"mm"|"inch",heal:{"mode":"none"} or
{"mode":"bounded_v1","allow":["same_parameter"]}} installs exactly one solid under the
certified curve-on-surface bound (1e-5 mm) (raw
exact, or one certified tolerance re-derivation); everything else is refused. A bounded import needs
a required "repair_budget" {allow,max_tolerance,max_growth,max_deviation} within the frozen
maxima. These two import requirement kinds are measured: admission compares original/cold
identity, units, status and complete preservation; budget compares actual operations, tolerance,
growth and certified deviation. A certified excess FAILs; missing/unsupported/cold-incomplete
evidence HOLDs. Complete census or a spline identity hash cannot stand in for preservation.
Direct edit: "direct_edit" {target,edit:{kind:"move_outward"|"offset_inward"|"delete_heal"|
"cut_plane",...}} acts on exactly one face; distance is 0.01..100000 mm, and "cut_plane" keeps one
named side of an explicit plane.
Fillet/chamfer: "edges":{"select":<edge selector>,"expect":<exact count>}. expect is mandatory.
Selectors: face "A.F" (box.+z, cyl.-z, extrude labelled segment) or {"planar":{normal,at|through,near?}}
or {"cylindrical":{axis,diameter|radius,axis_through?,near?}}. Edge {"edge":[face,face]},
{"line":{direction,through?,near?}}, {"circle":{axis,diameter,center?}},
{"class":"concave"|"convex","adjacent_to":[faces]}, {"between":[face,face],"class"?},
{"any_of":[selectors]}. Every selector may carry "tol":{"position":0.001,"direction":1e-6}.
Requirements: each locates ONE feature; no "expect" field (it is VXL-R601). A planar_face /
std.datum_plane is a plane, not one face: several coplanar faces (feet, a mirrored or patterned
part, a face split by a groove) are measured as one; "normal" is outward from the material (on a
pocket/groove face it points into the void; a groove floor is "+z"). "at" is a world
coordinate; default linear tol 0.05 mm, flatness 0.01; hole/OD boundary must be positive; slot boundary is positive and below width/2 and half blind
depth (R689). Distinct finite blind mouth/floor stations are checked first (R611 at `blind`);
change the extent stations when depth is zero, not the tolerance. Slot position may be zero with independent positive boundary. Clearance "min" > 0; touching counts as
collision unless "contacts":[{"planar":{"normal","at"}}] (1..4 principal-axis planes) declares a
positive-area designed contact. Any clearance whose operands meet on an undeclared plane, or whose
declared contact the predicted boxes do not meet, warns without a build (W930; predicted boxes
only). Measurable: solid_count envelope hole (with "blind":{mouth:<len>,floor:<len>} or
"countersink"{diameter,angle,at}, where "at" is required only for a through requirement and
omitted for a blind requirement) slot planar_face fillet_radius (10-170°, mitered ends allowed)
chamfer_size outer_diameter sharp_boundary finishing_run draft_angle feature_distance
variable_fillet_radius text volume_range closed_delivered_mesh
clearance minimum_wall gear_teeth gear_mesh (measured trim certificates and finite pair stations; a required not-measured row is a non-pass). A counterbore is two hole
requirements on one axis. "thread" {form,diameter,pitch,length,ends,audit,…} and
"helix" {radius,section:{circle:{diameter}},pitch,turns,…} are measurable kinds: both need
"measurement":"sections_v1" and either an explicit axis/at/from locator or a matching
"feature" datum; a thread requirement additionally states form, major_diameter, an authored
minor_diameter, length, ends and an increasing audit window (one complete repeat per meridian and
two complete leads inside it), and an internal thread states ends blind (a floor) or through (an
open exit) — trimmed/full_profile there is C479. Full-profile external threads measure finite
sections, both uncut ends and recorded overhang; native admission still checks each solid. Helix ends are plain only:
closed/closed_ground and end_coils are refused (C477); multiple starts must connect (C476).
The modelled internal minor is D - 5H/4 + 0.06, H = sqrt(3)/2*pitch (M4x0.7 -> 3.3022277717).
Both constructors are terminal (C418). Std wrappers: std.threaded_hole, std.thread_stud,
std.thread_boss, std.coil. chamfer_size checks three things: both setbacks equal "distance", both
faces of "between" are where you say, and the chamfer is 45 degrees; write "between" as the two
faces the chamfer step's edge lies between, with their real stations (use the same parameter for a
stock dimension, e.g. "at":"height"). Anything else is a reserved gap token or "unmeasured" with "describe"
(HOLD when required).
OD: {diameter,axis,axis_at,span:{from,to}} proves the complete outward cylindrical wall.
Sharp/finish runs: independent between:{first:{planar:{normal,at|through}},second:{planar:{normal,at|through}}},
run:{axis,from,to} with from<to; no names/near. Finish adds exactly one
finish:{fillet:{radius,tol?}} or {chamfer:{distance,tol?}}; all segments qualify, interior gaps fail.
Local fillet_radius/chamfer_size proves local size only. Slot: exactly one through:[a,b] or
blind:{mouth,floor}; blind needs the complete planar stadium floor. Connected complete split
bores measure as one group with all sorted faces; disconnected walls remain separate and
unsupported trims cannot pass. Hole mouths:[{at:<open station>,style:"sharp"}] is a
nonempty array of one/two unique declared stations (blind: mouth only). Complete Sharp passes;
proved cone/shoulder modifications fail; Unknown/incomplete chains stay not measured. Omission
makes no style-absence claim. Sharp-mouth/split-bore corpus: 18 fixtures, six RELEASE/twelve designated-row HOLD in
the recorded native measurements.
Every need: covered by a requirement via "covers", or "unmodeled":"<why>".
Missing or ambiguous geometry? Ask explicitly for unresolved attributes or competing readings;
declaring an assumption does not answer the question unless the user authorized the choice.
Derived values, unambiguous documented defaults and sourced standard dimensions for an already
determined component/function may be declared assumptions; questions and assumptions are reported
and never block the compiler; open questions cap the build label at HOLD while files are
delivered, assumptions alone do not, and an answered question is removed after recording the
user's answer as a need, parameter or assumption. A complete request needs no question.
Composition: define repeats in "defs" (category step|part|requirement, exactly one primary id
"self" and it carries no at_each) with optional "lets" and "checks"; use them with
{"use":"<def>","target":...,"args":{...}}. A default is a literal written as the argument
would be (number, "true"/"false", or a quoted enum like "'M4'"); only enum params take "domain";
numeric preconditions are fragment "checks" (a failure is VXL-E230 with the fragment message).
Arguments become typed lets, so the formal keeps its declared type; an ill-typed argument is
reported at args/<name> (args/<name>/<i> for a point). An error caused by an argument is reported
at the argument (args/<name>, target, bind) even when the body field rejects it, and a message
never prints a generated __ name; a failed check prints the fragment's own message first. An
at_each variable that no argument reads is VXL-F114 (exempt when bind/alias writes ${k}); $bind may
be read in a body only after a body step defined it (VXL-F123). A document needs at least one expanded requirement (VXL-R600); a fragment use may emit it; a table cell is a
decimal string ("4.5"), never a number. Use the sealed std library (tag
"std":"vxl-std-2"): std.mount_hole, std.counterbore_hole, std.countersunk_hole, std.tool_access, std.datum_plane, std.spur_gear_bored;
tables std_iso_273 and std_tap_drill (see STD.md for signatures and preconditions). A use's
at_each count is static (integer range 3 or "3"/in/in_table). A repeated use is a group (p__0,
p__1, no p); only a non-repeated use id is visible. Private __ ids are never writable; --expanded
output is not input. mount_hole and tool_access take the same at and axis; mount_hole's locate
and datum_plane's offset_tol control the locator window / offset only, not flatness. A datum_plane
is the plane it names: several coplanar faces are one plane; when faces with that normal lie on
different planes within 1 mm of "at" it is not measured (several_planes_in_window) — write a plain
requirement with a narrower window when that is intended.
Straight paths: sweep {bind,path:{from,to},x,profile} keeps a simple CCW line polygon;
x is perpendicular to the path, never projected. pipe {bind,path,diameter} is a filled rod,
not a hollow pipe; it has no x, at or rotate. loft/ruled {bind,sections:[{offset,profile},…],
at?,rotate?} take exactly two convex CCW sections, increasing offsets and the same vertex/label
order: translation or positive ordered radial correspondence. Never reverse, resample or rotate
vertex zero. guided_loft takes 2–8 convex sections with 3–24 vertices and at least two distinct
vertex rails {id,vertex,points:[[u,v],…]}; offsets give Z. frame law fixed omits angles;
vertex_mean_twist has one signed angle per station, first 0, |angle|<=360 and adjacent change<=45.
G0 uses ABC/ACD planar facets; G1/G2 only fixed constant-section straight translated prisms.
Independent path requirements all scope the complete final solid in final part coordinates:
swept_section {path,profile,x?} needs both caps and complete straight side-span proof (circle:
centred diameter profile, no x, complete outward cylinder group); loft_sections {frame,sections,
span:{law:"linear_vertices"}} needs complete side support/trim/domain/coverage, not just matching
caps; guide_rail {points:[[x,y,z],…]} proves complete trimmed boundary chains, not buried lines
or facet diagonals; section_frame {frame,sections,law,angles?,continuity?} proves obtained station
means/bases/angles AND complete facets/prism. G1/G2 prove corresponding-side station seams only,
not polygon corners or general smoothness. Finite stations prove their stations; only complete
obtained support certificates prove between them. Unsupported or missing evidence cannot pass.
near/locate select candidates, never change tol; no expect field. Later Boolean attachments/cuts
may defeat complete-final-solid path proof. A warped loft/ruled side cannot be the selected face
target of a later statement (S020); predicted station datums/G0 side groups are not single faces
(Q521). Use planar caps/proved planar sides where supported. A selector count is not dimensional
verification. See examples/path_component_kit.vxl.json; compiler acceptance alone is not RELEASE.
Surfaces: "surfaces":[{id,degree:[du,dv] (1..3),knots? (default clamped_uniform),poles? [[[x,y,z],...],...] or height_field? {axis,u,v,control_heights}}]. Non-rational, non-periodic,
degree+1..=8 poles per direction, <=64 together; height-field abscissae are control abscissae, not points
the surface passes through; a surface is a construction input, never a delivery (C529). Consume it:
thicken {bind,surface, exactly one of along:<dir> or normal:"+"/"-", distance (0.1,100] mm} -> base/top/side_u0..side_v1; an along direction must be
proven transversal (C524); a normal wall additionally needs a required thickened_wall of mode
"normal" naming <bind>.base/<bind>.top at the same distance (C528). sew_solid {bind,patches 2..16,
seams pairing identical boundary rows} (C526). trim_to_surface {target,bind,surface (height field or
separable monotone),keep below/above} needs a >=0.1 mm footprint margin (C527; G410/G411/G412). A
thickened side cannot be selected by name (S020): use an edge selector between base and top. A
spline face has no carrier query; name it. Requirements: spline_surface {face,nominal,tol default
0.005,trim natural|any} (R750); surface_probe {face, 1..16 probes {from,along,expect}, tol 0.02}
(R751; it measures the probe points, not the surface between); thickened_wall {faces base/top,mode,
along?,thickness,tol 0.01} (R752); surface_seam {between two faces of one sewn solid,class g0|g1,
tol.gap 0.001,tol.angle 0.1} (R753). W976 unconsumed surface; W975 net may fold; W974 mesh floor near
budget. A trimmed solid is exact as built; its delivered STEP admission is decided by verification of
the reopened file, so do not promise RELEASE. See examples/surface_skin_and_roof.vxl.json.
Split/deliver/imprint: split {target, by:{plane:{normal,through}} or {of,face}, pieces:[one per side,
both sides]} cuts a body into every piece it makes (each piece binds, or count 2..4 + order + names);
every piece must be delivered or read later (C514). Each piece Q gets Q.cut only for one statically known cutter plane (planar, outward +n on
the negative piece). Query-located cuts have no name: select them by a planar query.
Each target face name is clipped (Q.<face>). "deliver":{"<subject>":"<binding>",..}
2..8 entries gives each binding its own subject/terminal/files (one-entry object or on a keep-out is
C517; naming the part id where a subject is needed is C518). One label per build; one HOLD piece
makes the whole generation HOLD but all pieces are delivered. imprint {target, on:{select,expect}
(one planar principal-normal face), exactly one of sketch (one closed loop, no labels) or by (tool
binding), region} adds edges and splits the face, never material; the support keeps measuring as one
plane. New names <target>.<region>, .outside, .boundary; the old <target>.<face> is two faces (G408,
also a flat boundary fillet/chamfer). Seat a later hole by putting its at on the region face.
partition {part:<part id>, split:<step>, plane, pieces, per_side?, scope:"boundary_v1"|
"full_v1", tol?} proves a split via retained checkpoints; section_contour {subject, plane, and at
least one of loops/area/perimeter} measures one cross-section; imprint_region {subject, on:{normal,at},
near?,extent?,area?,boundary?} measures an imprinted region. Refusals R740-R748; a section statement
is C519. std.split_pair and std.imprint_rect carry split/imprint with the name formal type.
Split/imprint of loft, ruled, sew_solid, thicken or trim_to_surface histories is C516;
section/imprint-region probes on spline-faced subjects retain typed incomplete inventories.
Loop: vxl check until clean -> build -> read the revision packet -> fix -> rebuild (max 6 checks, 4 builds).
Finishing/text: draft {target,faces:{select,expect:1},angle,pull,neutral:{through}} tilts one
planar exterior lateral face of a tracked convex prism, angle magnitude (0,45] and either sign.
face_offset sweeps one outward planar convex face by distance (0,20] mm. variable_fillet blends
one straight collinear convex run with radii:{start,end} in [0.01,50] mm (equal = constant).
text cuts or raises content (literal or spans; font {std:liberation_sans_bold} or an uploaded
asset, no installed fallback) at depth (0,20] mm, placement planar/paragraph/path/cylinder.
A paragraph stacks by the font's typographic line pitch (ascender-descender+line gap), not ink
height; a too-small box is C489 naming the axis and pitch. A text requirement's region is in
label coordinates relative to anchor (first axis along baseline, second along normal x baseline)
and must contain the nominal box (R716). On a path label a contour may meet the host boundary and
still measure. Cylinder text is NOT measured (typed not-measured, HOLD).
Variable_fillet_radius measures authored stations only; no between-station law. A station's
radius is the radius of the blend's cross-section normal to the run. A keep_out operand of
feature_distance is probed in its own posed frame; a window that cannot be expressed in a
non-right-angle keep-out frame is R712. A draft angle/feature_distance/variable_fillet_radius/text
follows the same precursor rule as fillet/chamfer: requirements are independent geometric
queries, not the step's own selector names (W980).

An explicit unmeasured requirement needs exactly one of subject or operands (VXL-S011 if both are given; VXL-R660 if neither is given); a mesh subject is refused (VXL-R761). For mesh disclosures, put the reason on the need as unmodeled. It reports reason: declared_unmeasured, with the authored text in detail.describe and an explanation beginning "declared unmeasured by the author: <describe>". The explanation names replacing kind with a supported measurable claim or setting required:false for an intentionally optional disclosure; an optional disclosure does not measure the claim. Required gaps force HOLD (<id> unmeasured); optional gaps leave the label unchanged.

Analytic card: cone endpoint diameters may include one zero apex; wedge ltx is the X width at y=dy, with Z extrusion. Sphere/torus primitives are full. Revolve axis is 2D in the sketch; its requirement profile is [axial,positive radial], with perpendicular 3D axis/radial. Keep arc interiors clear of the axis; no holes or direct arc-revolve finishing. Conical/spherical/toroidal/revolved feature requirements certify complete native trims; face_angle compares outward adjacent planar normals. outer_diameter measures the outward wall, not a bounding box. Use the four analytic std recipes in STD.md when their fixed orientation fits.

Spur gears: spur_gear {bind, module, teeth, pressure_angle (20|25°), face_width, profile_shift?, thinning?, chord?, axis? (+z), at?}; only .bottom/.top are names (G390). The tooth form is a faceted involute polygon within the chord bound, not an analytic involute, and no ISO 1328 / AGMA grade claim is made. For a bored gear use std.spur_gear_bored (module, teeth, face_width, bore, pressure_angle, thinning; wall refusal E230 when rf - bore/2 < 0.01). gear_teeth is authored with axis {at,dir}, window {axial,radial}, module/teeth/pressure_angle/face_width, optional profile_shift/thinning/phase/tol and measurement "prism_section_v1"; R730-R734 refuse malformed payloads. gear_teeth measures a complete certified prism band; an incomplete certificate is a required non-pass.