Field types
One per data_type: how it reads, writes, clears and filters. Each rule is the card's own Traps, copied whole. The matrices behind them are in the cards.
calculated
A calculated field refuses every write with "is read only" and every filter with "cannot be used in a filter", yet it sorts and summarizes fine, and the formula is exposed as calculated_function.
Filter it by rewriting the formula.
["workload", "is", 600]400s;["duration", "is", 600]gets the same rows for{duration}. There is no equivalent forCONCAT({code}, {id}): page and match client-side.Sort is the one query verb that survives: top-N by a computed column is one call, on all four fields.
A
floatrenderer returns a string, sosorted(rows, key=...)on the raw value sorts lexicographically and puts"0.9"after"0.625". Cast before comparing (field_types/float).A
textrenderer formats numeric operands for display:CONCAT({code}, {id})on id 1226 gives"charA1,226", a thousands separator inside a string a client might parse back.Division by null yields null, not an error:
workload_per_day_per_assigneeis null on 21 of 40 rows where{workload_assignee_count}is 0. Fill rate measures the operands, so drop the type from fill ranking (probe 007).default_valueis present inpropertiesand always null. Nothing sets it; do not read it as the value of an unpopulated row.
corpus/findings/field_types/calculated.md
checkbox
A checkbox is two-state, never null - an untouched row already reads false, null is unwritable and unfilterable, and the only relations are is/is_not, so fill rate reads 100% on every checkbox.
Fill rate is meaningless on this type. Every checkbox on every row is non-null, so a fill-rate scan reports 100% for all four Version checkboxes while every row holds the same value (probe 007). Drop
data_type == "checkbox"from fill ranking before scoring; no threshold separates an informative checkbox from a dead one.The
is_not Nonefill-rate filter that works on every other type 400s here, in both_searchand_summarize(probe 020). Special-case the type; do not catch the 400 and score 0._summarizereturns the UI glyph, not the value, so the empty-group trick that yields an empty count on a list field ([('<value>', 99), ('', 1)]) never sees''here and reports the field fully populated.A checkbox can be refused on both paths.
Note.client_noteiseditable: falseand answers400 API create() Client Notes can not be created through the APIto a create sendingtrueand400 API update() Note.client_note is editable on create only.to every update,falseincluded, so there is no value a caller can put in it (probe 069).Strings coerce on read and write (
"true"->True), so a checkbox set from a CSV or a form post works until someone sends"1". That 400s with a different error shape (Invalid data for 'checkbox' data type, undersource) than a bare1(expected [String, FalseClass, TrueClass] ... got Integer). Match on the status, not the title.
corpus/findings/field_types/checkbox.md
color
Task.color holds the token pipeline_step rather than a colour: read step.Step.color in the same dotted call and keep a client default. A real value is decimal r,g,b, never hex.
Never treat
Task.coloras a colour. A swatch renderer parsing it asr,g,bgetspipeline_stepon every row this site has and must followstep.Step.colorinstead.Decimal
r,g,b, no spaces and no#, matchingStatus.bg_color(probe 010). Hex is rejected on write and on filter. Build it with"%d,%d,%d" % rgb, split on,to read.No
Task.colorrow on this site is empty and a written null is refused, so a fill-rate count over it reads 100% and measures nothing (probe 007).A bad filter value is a 400 on
StepandProjectbut a silent 0 rows onTask.Writing a legacy name is lossy:
"Red"stores253,1,0and never reads back as"Red", so filtering on the name it was written with returns 0.
corpus/findings/field_types/color.md
date
A date is the string "YYYY-MM-DD" and nothing else: any timestamp 400s on write and as a filter value. Every negating operator (is_not, not_in, not_in_last) also matches rows that are null.
Every negating operator also returns null rows.
is_not "2026-09-02",not_in [...]andnot_in_last [1,"MONTH"]each matched the row with no date. Useis_not nullfor "has a value"; it is the only filter that means that.A
datenever accepts a timestamp, on write or as a filter value;date_timeaccepts both"2026-09-02"and"2026-09-02T00:00:00Z". That and the read shape are the only differences: the operator list and the relative-value shapes are identical between the two types.betweenwith anullendpoint returns 0 rows and no error. Usegreater_than/less_thanfor an open-ended range; they are strict, not inclusive.HOURis a legal unit but the value has no time part, so anything under 24h collapses to today: a date 5 days back missedin_last [1,"HOUR"]and matchedin_last [200,"HOUR"].""is not a distinct empty state: it is written, filtered and read back asnull.
corpus/findings/field_types/date.md
date_time
Stored and read as UTC YYYY-MM-DDTHH:MM:SSZ: a written offset is silently normalised, a zoneless string is taken as UTC, and a date-only filter value means midnight UTC, not the whole day.
A written offset is not preserved:
05:06:07+05:00reads back as00:06:07Z. Convert to UTC yourself and keep the original zone in your own field if a client must redisplay local wall-clock time.A zoneless string is assumed UTC, not site-local:
"2026-03-04T05:06:07"is not "5am here".isis exact-second equality, sois "2026-03-04"finds only rows at00:00:00Z. Match a day withbetween ["2026-03-04", "2026-03-05"]orin_calendar_day.""400s where atextfield accepts it; onlynullclears. There is no numeric form: epoch integers 400 with the[String, NilClass]type error, epoch strings with the format error.editable: falseon a timestamp means "not editable by aPUT", not "not settable". The 400 says so outright,is editable on create only, and a create body sets both (probe 070). Test the create path rather than reading the flag.
corpus/findings/field_types/date_time.md
duration
A duration is a bare integer of minutes and the unit is on the site: GET /preferences gives hours_per_day and duration_units. A Float truncates toward zero at 200, so round before writing.
The unit is on the site, not on the field. No
/schemaroute names it. Readhours_per_dayandduration_unitsonce fromGET /preferences, then render.A Float truncates instead of failing.
number400s on3.7(field_types/number);durationtakes90.9and stores90. Round before writing an average, a ratio ortotal/2."2:30"is not a duration. The only string the API accepts is one that parses as a number.Negation includes nulls; comparison excludes them.
is_not 480andnot_in [999999]return the null rows too (3 and 4 of 4);greater_than -1returns only the 2 rows holding a value. A row holding0isis_not None, so a field full of zeroes scans as fully populated (probe 007); rank bygreater_than 0.
corpus/findings/field_types/duration.md
entity
An entity link is a {type,id} hash under relationships, cleared only by null. Enforce valid_types yourself: it binds on a few fields, is ignored on most, and nothing in the schema marks which.
Validate the type against
valid_typesclient-side, on every field. A client cannot predict which field will protect it, and an unenforced write stores nonsense at 200:sg_task(['Task']) took a Shot and read it back as a Shot.No project-consistency check. Pointing a sandbox Version at a Shot in another project returned 200 and read back linked, with nothing in the response flagging it. Compare projects before writing.
A wrong
typefor a real id 400s here only because ids come from one site-wide sequence (250 shots 862..1111 vs 250 assets 1226..3588, zero overlap), so the wrong table holds no such row. That is a lookup miss, not type validation.Reading
attributesalone makes every entity link look absent, andfilter[]needs the full{type, id}:[{"id": N}]and bare ints both 400 (probe 017), while a bad?fieldsname is silently dropped at 200 (probe 004).
corpus/findings/field_types/entity.md
entity_type
An entity_type field is a bare schema-name string in attributes, validated on write against 290 built-in type names but not against the site's enabled ones, and filtered only by is/is_not/in/not_in.
Not an
entityfield.entitystores a{type, id}link underrelationshipsand takes the entity vocabulary (type_is,name_contains, nine operators);entity_typestores the type name alone underattributesand takes four. An{type, id}hash 400s on both read and write here.Filters are case-sensitive, unlike a
list, where'type a'matches'Type A'."shot"returns 0 rows with no error, so a lowercased value reads as "nothing matches".The 290-name legal set is the built-in type table, not the site's schema. Validate against
/schemabefore writing, or store a type name that has no endpoint.Existing rows hold values the validator rejects:
PermissionRuleSet.entity_typereadsPermissionRuleSet.HumanUser, and writing that back 400s. Never round-trip a read value into an update.Four of the five are read-only, and a write to one 400s with
is editable on create only.
corpus/findings/field_types/entity_type.md
float
A float reads back as a JSON string rounded to 6 decimals and rejects Integer on both write and filter: send 1.0 or "1.0", never 1; 0.0 and null stay distinct, and 1e-9 silently becomes 0.0.
Integer is rejected on both halves:
PUT {"field": 1}and["field", "is", 1]. A client that computed an aspect ratio as exactly2must send2.0or"2.0".numberis the mirror image; it rejects Float.The value is a string, so
row["attributes"][f] > 1.0raises and== 1.0is False. Cast on read.Precision is 6 decimal places, applied on write, at 200 and without warning.
1e-9stores as0.0and then matchesis 0.0, notis None.not_inreturns rows whose value is null, so it is not the complement ofin. Intersect it withis_not Nonefor "has a value, but not that one".
corpus/findings/field_types/float.md
image
Only the upload dance sets an image: every value but null 400s, and clearing it also clears filmstrip_image. The value is a presigned URL re-signed per read, so store the row id, never the string.
is_not Nonematches a row that is still transcoding, so a job that filters and then downloads fetchesthumbnail_pending.png. Filter, then check the prefix on each row.Transcoding took ~38 seconds for a 16x16 97-byte PNG. Poll the field every 5 seconds.
The REST upload never fills
image_blur_hash: stillnull102 seconds after the thumbnail settled and after a second upload tofilmstrip_image. The one sample-project row holding one ('YXFZJ]4U-=ISt8oh…', 68 chars) was made outside REST. Do not wait on it.
corpus/findings/field_types/image.md
jsonb
jsonb filters, where serializable cannot: is, is_not, contains, not_contains, values always hashes. Note.meta stores what you send but is create-only, so nothing written there is ever editable.
The filter on
EventLogEntry.audit_trailis a silent no-op.is nullandis_not nulleach return the full unfiltered page, so the two together over-count every row. The field is filterable per the schema, absent from every response, and ignored in everyWHERE.Note.metais a one-shot slot. A client can seed it at create and never revise it, and there is no update or clear.editable: falsein the schema does not predict the create path; a create-time write succeeds where every later one 400s.A one-element filter array is unwrapped.
is [[]]reaches the field as[], which matchesnullrows, so a stored empty array cannot be selected.contains [{"x": 1}]is unwrapped to the hash and then fails to match an array-valued row.containsreaches into objects only. A stored array is unmatchable by any containment value: a hash finds nothing and an array is unwrapped first.Distinct from
serializableon every axis but read.serializablehas noValid relationslist and cannot be filtered;Task.splitsaccepts a write at 200 and storesnull.jsonbfilters with four operators and stores exactly what it is given. Both return a decoded value underattributes.
corpus/findings/field_types/jsonb.md
list
A list is one bare string in attributes; a write outside valid_values 400s and is case-sensitive, while filters are case-insensitive and only is/is_not/in/not_in exist.
Never round-trip a filter value into an update.
An invalid operator 400s (probe 017); an invalid value does not, so a dropdown typo reads as "no rows match".
"list" names the schema, not the value: it holds one string, and an array 400s with
expected [String, NilClass].viewed_by_current_userandNote.read_by_current_userare stored per person, not per row. A write undersudo_as_loginreads back for that person alone; the script's own write answers 200 and stores nothing, which is what "writing'read'reads back'unread'" was (probe 007, corrected by probe 068).A
listfield can nameinandnot_inin its ownValid relationsand evaluate neither. OnNote.read_by_current_user,in,not_inand anisvalue outsidevalid_valueseach answer 200 with the caller's unread rows rather than 0 (probe 068). Run a negative control per field.default_valueis applied on create when the field is omitted, so a fill-rate count over alistmeasures the default, not intent (probe 007).
corpus/findings/field_types/list.md
multi_entity
A bare list replaces the whole link set, but {"multi_entity_update_mode": "add"|"remove"|"set", "value": [...]} adds and removes in place; the field never reads null and null 400s.
Both incremental spellings that live in the query string return 200 having silently replaced the list. The loss is a success response, not an error; send the mode in the body.
A bare list replaces, so an append coded as read-then-PUT loses any link a concurrent writer added between the two calls. Use the
multi_entity_update_modewrapper, not read-modify-write.in [X]means "links any of X" andnot_in [X]means "links none of X", so it matches empty rows, as doesis_not. "Links all of X" has no operator: repeatisonce per entity, as separate filter rows.inwith only unresolvable ids is field-dependent, so a negative control built that way must be checked per field. OnVersion.sg_ai_generated_fromit returns the rows linking nothing rather than zero rows; onNote.note_linksit returns zero rows though rows with an empty list exist (recipes/009). Mixed,in [A, 99999999]returns A's rows. Which side varies, and why, is unprobed.A dotted path through this field reads back nothing: 200, key absent from
attributes, inGET ?fieldsand in_searchalike, while the identical path filters correctly (probe 016). To read the far side, query the child entity filtered by the parent.Read order is not insertion order (adding B then A read back A then B), so never treat it as a sequence.
corpus/findings/field_types/multi_entity.md
number
A number is a signed 32-bit integer: floats 400, 2**31 is "integer out of range", and 0 is not null, yet is_not and not_in match null rows while greater_than and less_than do not.
Signed 32-bit, not 64. A 64-bit id or seed reaches
2**64-1and must be stored in atextfield (probe 019saw the same ceiling on a created field). The create path names the cause,PG::NumericValueOutOfRange; the update path says onlyInvalid statement.A float is rejected, not coerced.
int()anything computed (a mean, a ratio,n/2in Python 3) before writing it. A numeric string coerces, so"42"works and42.0does not.0is a value,''is not a clear.nullis the only clear. Followingprobe 007: a row holding0isis_not None, so a number field full of zeroes scans as 100% filled, exactly like a checkbox full ofFalse. Rank a number field bygreater_than 0, or by_summarizegrouping (probe 020), never by fill rate.Negation includes nulls; comparison excludes them.
is_not 1001andnot_in [999999]return the null rows too (3 and 4 of 4), whilegreater_than -1returns only the 2 rows that hold a value. Any "everything except X" filter over a sparse number field silently sweeps in every unset row.
corpus/findings/field_types/number.md
password
A password field reads as a constant seven-asterisk mask on every row, including through a dotted path; it cannot be filtered, sort is accepted and ignored, and it must never be written.
The field passes every generic inspector test (
visible: true,ui_value_displayable: true, present in/schema/<Type>/fields) and returns a value, so excludedata_type == "password"by name from field pickers, from row exports and from anything that echoes a read back into a write.Fill-rate scanning reads 100%, and the
is_not Nonecorrection 400s. Drop the type before ranking, the way probe 007 dropscheckbox.A sort on a
passwordfield is a silent no-op. Validate a user-supplied sort key against the schema rather than trusting a 200 to mean the rows came back ordered.ClientUser.password_proxyreportseditable: true. Treat that as a schema claim only: no probe writes apasswordfield, and neither should a client.
corpus/findings/field_types/password.md
percent
A percent is a bare integer on a 0-100 scale (50% is 50, and 0.5 is rejected as Float), but nothing is clamped, so -1, 1000 and 2**31-1 all store at HTTP 200.
Integer or nothing, on both halves.
PUT {"field": "50"}and["field", "is", "50"]each 400 withexpected [Integer, NilClass] ... but got String.int()a value out of a CSV or a form field before sending it.The 0-100 range is a convention, not a constraint.
-1,101and1000000all store at 200 and read back unchanged, and nopropertieskey declares a bound. Validate before writing, and clamp on read; a percent field is not evidence that its value is a fraction of a whole.0is a value and""is not a clear. Followingprobe 007, a row holding0isis_not None, so a percent field full of zeroes scans as 100% filled. Rank bygreater_than 0, never by fill rate.Negation includes nulls; comparison excludes them.
is_not 50andnot_in [50]return the null rows too, 3 of 5;greater_than -1returns only the 3 rows holding a value. A "not yet at 100%" filter written asis_not 100sweeps in every unset row.
corpus/findings/field_types/percent.md
pivot_column
A pivot_column is a web-UI task rollup with no REST implementation - it reads null on every row, and write, filter, sort and _summarize each fail with a different error.
These pass every generic test an inspector applies (
visible: true,ui_value_displayable: true, present in/schema/<Type>/fields) and then return null for every row.Fill-rate scanning breaks twice: the
is_not Noneprobe 400s like acheckbox, and the_summarizefallback 500s rather than 400s. A scanner that retries on 5xx retries a permanent failure 45 times per site.Only the write error names the field. A request that 400s with
Read failed for entity type [Shot]gives no clue which sort key caused it; match on code 104 plus the sort you sent.step_0exists on types that have no Steps at all, so its presence says nothing about whether the type is task-tracked. ReadStep.entity_typefor that.
Exclude data_type == "pivot_column" from field pickers and from any payload built by iterating the
schema. For the same information, query Task filtered on entity and step, and aggregate
sg_status_list yourself.
corpus/findings/field_types/pivot_column.md
serializable
No operator works on a serializable field: every filter 400s as unfilterable. Task.splits answers a well-formed array of hashes with 200 while storing null, so REST cannot write it.
A client cannot query into a blob. No operator means no
is Noneto rank fill rate by (probe 007) and no way to find the rows holding a marker;_summarize(probe 020) has nothing to group on. Fetch rows on some other filter and inspect the decoded value client-side.Task.splitsanswers 200 and stores nothing. A client that writes state there and re-reads it cannot tell a discarded write from an empty field. Read back every serializable write.Two failure layers, two error shapes. A wrong Ruby class gives code 103 with the accepted-class list and an empty
source; a right class the setter chokes on gives code 104 with a raw Ruby message andsource: null. Neither names the key at fault.The column takes arbitrary JSON; the field refuses it.
EventLogEntry.metaholds nested objects, lists, booleans and nulls, so the storage is a blob. Of the four editable fields three are outside a project:Project.tracking_settingsis site configuration,SavedFilter.filtersandRvLicense.metahave noprojectfield. A project-scoped blob to write does not exist here.
corpus/findings/field_types/serializable.md
status_list
REST does not enforce hidden_values: a project-hidden status writes and reads back fine, so every client must subtract it itself. Only valid_values is enforced.
hidden_valuesis not a subset ofvalid_values. On the probed sandbox project Task hidesblkandrdy, neither of whichvalid_valuescontains, so writing one is 400 while the hidden-but-validhldwrites at 200 and reads back. Subtracting one set from the other is right for offering a choice and wrong for testing a row: a row may hold a code outside the usable set (recipes/005).hidden_valuesis not enforced by the API. REST 201s and 200s on a status the project's UI refuses to offer, so every client must subtracthidden_valuesitself (probe 009). The API will not do it. Conversely, do not treat a hidden code read back off an entity as corrupt: it is a legal stored value.Permitted is not safe. An operator reports that a hidden status set this way can break the web UI for that entity. Unverified: it is not observable through the API (see
docs/quirks.md). Until someone checks it in a browser, treat writing a hidden status as something to avoid, not merely as something the server allows.A wrong code in a filter is a silent 0 rows, indistinguishable from a status nothing holds.
Display labels are accepted nowhere. Round-trip through
display_valuesin both directions, and fall back to the raw code when a key is missing.No substring operator, so there is no server-side type-ahead over statuses. Fetch
valid_valuesonce and filter the list client-side. Sorting and filtering is on the code, which is not alphabetical by label.Codes are per entity type:
Versionhas 16,Shot10,Shot.sg_latest_vendor_status6. Never reuse a code across types, and read the schema per field, not per entity.
corpus/findings/field_types/status_list.md
summary
A summary field is a live rollup: refused on write even where editable=true, unfilterable, unsortable, and null on every custom one here, so re-run the query /schema exposes to select on it.
Fill rate is meaningless on this type.
open_notes_countis never null, so it scans as 100% filled while holding one value: 100 Versions all read0(probe 007). The other four readnullon every row and scan as 0% filled while their queries match rows. Excludedata_type == "summary"from fill ranking; theis_not Noneprobe 400s, as does_summarizegrouping.Sort fails silently.
?sort=codeand?sort=-codereturn different orders,?sort=open_notes_countreturns the unsorted order, and so does?sort=definitely_not_a_field: an unsortable field and a typo are indistinguishable at 200.editable: truedescribes the field-configuration form in the web interface, not the REST value, and the refusal cites the data type rather than the field. Three of the 42 summary fields on this site claim it, so a client building an update form fromeditableoffers three that can never be saved.38 of the 42 are
open_notes_count, one per entity type, all counting Notes whose status isopn,iporrdy. That set is the site's definition of "open", readable fromproperties.queryand site configuration rather than an API constant: read it instead of hardcoding the three codes.
corpus/findings/field_types/summary.md
text
A text field has no empty string: writing "" stores null, so is "" and is None are one filter; matching is case-insensitive, whitespace is stripped, and a non-string 400s.
Writing
""returns 200 and storesnull. A client round-tripping a form field cannot distinguish "user cleared it" from "never set"; encode that distinction in a sentinel string.Every operator is case-insensitive, including
is. There is no case-sensitive text match. Filter broadly and re-check the case client-side.is_notandnot_containsreturn the null rows, sois_not Xis not the complement ofis X.is ''matches exactly the rowscontains ''skips.Leading and trailing whitespace is stripped on write, silently, so
' 'is stored asnull.cached_display_namereportseditable: Trueand accepts a write at 200, then discards it. It mirrorscode, and re-reads as the newcodeafter a rename. Never write it.in [None]teaches nothing: code 104,source: null,detail: null. Useis None.
corpus/findings/field_types/text.md
timecode
A timecode stores milliseconds as a signed 32-bit integer. No schema or preference names its frame rate, but a _summarize group_name renders HH:MM:SS:FF and the rate solves out of that.
The rate is real but hidden. Solve it once per site from two
_summarizewrites and store it; a client that guesses 24 or 25 is wrong by a frame inside the first second.A timecode field rejects timecode strings.
"01:00:00:00"and the drop-frame"01:00:00;00"both 400 on write and again inside a filter, and a numeric string does not coerce the way it does fornumberandduration. Sendintmilliseconds.Nothing is validated as a time.
-3600000,86400001and2147483647all store, and render as-1:59:59:00,24:00:00:00and596:31:23:16;-1renders as-1:59:60:00, a 60th second. Range-check before writing. The API only enforces the 32-bit column.Negation includes nulls; comparison excludes them.
is_not 3600000andnot_in [999999999]return the null rows too (3 and 4 of 4), whilegreater_than -1returns only the 2 rows holding a value. A row holding0isis_not None, so a field full of zeroes scans as fully populated (probe 007); rank bygreater_than 0.A new field belongs in
text, not here. Every stock field a cut or a source clip uses for timecode istextplus anumberrate, which round-tripsHH:MM:SS:FFand survives drop frame.
corpus/findings/field_types/timecode.md
url
The value is a presigned link re-minted on every read and expiring on X-Amz-Expires, so persist the Attachment id and re-read. No filter relation exists at all, and sort is a 200 no-op.
"Has media" is not a query. Page the rows with
fields=sg_uploaded_movieand test the value client-side._summarizerefuses with the same message underAPI summarize()(probe 021), so a fill-rate scan must special-casedata_type == "url".The filterable neighbours are proxies, not answers.
image is_not Noneandsg_uploaded_movie_transcoding_status is_not Noneboth matched exactly the media-holding rows on the sample project, and on two Versions uploaded and then cleared both still matched the row aftersg_uploaded_moviehad gone null. A picker built on either offers Versions with no media.The url is regenerated per read and signed with an expiry. Anything that caches it (a database column, a rendered page, a message to a chat client) serves a dead link once it lapses.
Read
link_typebefore anything else.uploadandwebare indistinguishable by keys, and alocalvalue has nourlkey at all, so indexingvalue["url"]raises on the shape a published file uses.
corpus/findings/field_types/url.md
uuid
A uuid field is server-generated and rejects every write with "is read only", so it cannot hold your key; it filters on is/is_not/in/not_in only, and a malformed value 400s.
is nullis a 400, not a filter. Useis ""for "unset" andis_not ""for "set". The empty string is legal only withisandis_not:in [""]fails as a malformed uuid.A malformed filter value 400s the whole read. Code 104
invalid input syntax for type uuidsurfaces the database. A prefix, aurn:uuid:form, surrounding whitespace and any non-uuid string all fail. Validate client-side; there is no partial match to fall back on, sincecontainsis unsupported.is_notandnot_inreturn the rows where the field isnull, sois_not Xis not the complement ofis X. Addis_not ""to exclude them.Sorting on a uuid field fails, on both spellings:
GET /entity/icons?sort=uuidand_searchwith"sort": "uuid"return 400 code 104Read failed for entity type [Icon], withsourceanddetailnull.sort=idon the same endpoint returns 200. Page byidand sort client-side.It cannot be your correlation key. A uuid field is generated by the server, is not unique, and refuses every write. To tie a Flow PT row to a record in another system, put your identifier in a
textfield, which is writable and supportsis,inandcontains.
corpus/findings/field_types/uuid.md