SG Ground Truth

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.

API

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 for CONCAT({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 float renderer returns a string, so sorted(rows, key=...) on the raw value sorts lexicographically and puts "0.9" after "0.625". Cast before comparing (field_types/float).

  • A text renderer 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_assignee is 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_value is present in properties and 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 None fill-rate filter that works on every other type 400s here, in both _search and _summarize (probe 020). Special-case the type; do not catch the 400 and score 0.

  • _summarize returns 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_note is editable: false and answers 400 API create() Client Notes can not be created through the API to a create sending true and 400 API update() Note.client_note is editable on create only. to every update, false included, 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, under source) than a bare 1 (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.color as a colour. A swatch renderer parsing it as r,g,b gets pipeline_step on every row this site has and must follow step.Step.color instead.

  • Decimal r,g,b, no spaces and no #, matching Status.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.color row 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 Step and Project but a silent 0 rows on Task.

  • Writing a legacy name is lossy: "Red" stores 253,1,0 and 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 [...] and not_in_last [1,"MONTH"] each matched the row with no date. Use is_not null for "has a value"; it is the only filter that means that.

  • A date never accepts a timestamp, on write or as a filter value; date_time accepts 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.

  • between with a null endpoint returns 0 rows and no error. Use greater_than / less_than for an open-ended range; they are strict, not inclusive.

  • HOUR is a legal unit but the value has no time part, so anything under 24h collapses to today: a date 5 days back missed in_last [1,"HOUR"] and matched in_last [200,"HOUR"].

  • "" is not a distinct empty state: it is written, filtered and read back as null.

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:00 reads back as 00: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".

  • is is exact-second equality, so is "2026-03-04" finds only rows at 00:00:00Z. Match a day with between ["2026-03-04", "2026-03-05"] or in_calendar_day.

  • "" 400s where a text field accepts it; only null clears. There is no numeric form: epoch integers 400 with the [String, NilClass] type error, epoch strings with the format error.

  • editable: false on a timestamp means "not editable by a PUT", 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 /schema route names it. Read hours_per_day and duration_units once from GET /preferences, then render.

  • A Float truncates instead of failing. number 400s on 3.7 (field_types/number); duration takes 90.9 and stores 90. Round before writing an average, a ratio or total/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 480 and not_in [999999] return the null rows too (3 and 4 of 4); greater_than -1 returns only the 2 rows holding a value. A row holding 0 is is_not None, so a field full of zeroes scans as fully populated (probe 007); rank by greater_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_types client-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 type for 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 attributes alone makes every entity link look absent, and filter[] needs the full {type, id}: [{"id": N}] and bare ints both 400 (probe 017), while a bad ?fields name 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 entity field. entity stores a {type, id} link under relationships and takes the entity vocabulary (type_is, name_contains, nine operators); entity_type stores the type name alone under attributes and 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 /schema before writing, or store a type name that has no endpoint.

  • Existing rows hold values the validator rejects: PermissionRuleSet.entity_type reads PermissionRuleSet.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 exactly 2 must send 2.0 or "2.0". number is the mirror image; it rejects Float.

  • The value is a string, so row["attributes"][f] > 1.0 raises and == 1.0 is False. Cast on read.

  • Precision is 6 decimal places, applied on write, at 200 and without warning. 1e-9 stores as 0.0 and then matches is 0.0, not is None.

  • not_in returns rows whose value is null, so it is not the complement of in. Intersect it with is_not None for "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 None matches a row that is still transcoding, so a job that filters and then downloads fetches thumbnail_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: still null 102 seconds after the thumbnail settled and after a second upload to filmstrip_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_trail is a silent no-op. is null and is_not null each 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 every WHERE.

  • Note.meta is a one-shot slot. A client can seed it at create and never revise it, and there is no update or clear. editable: false in 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 matches null rows, 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.

  • contains reaches into objects only. A stored array is unmatchable by any containment value: a hash finds nothing and an array is unwrapped first.

  • Distinct from serializable on every axis but read. serializable has no Valid relations list and cannot be filtered; Task.splits accepts a write at 200 and stores null. jsonb filters with four operators and stores exactly what it is given. Both return a decoded value under attributes.

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_user and Note.read_by_current_user are stored per person, not per row. A write under sudo_as_login reads 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 list field can name in and not_in in its own Valid relations and evaluate neither. On Note.read_by_current_user, in, not_in and an is value outside valid_values each answer 200 with the caller's unread rows rather than 0 (probe 068). Run a negative control per field.

  • default_value is applied on create when the field is omitted, so a fill-rate count over a list measures 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_mode wrapper, not read-modify-write.

  • in [X] means "links any of X" and not_in [X] means "links none of X", so it matches empty rows, as does is_not. "Links all of X" has no operator: repeat is once per entity, as separate filter rows.

  • in with only unresolvable ids is field-dependent, so a negative control built that way must be checked per field. On Version.sg_ai_generated_from it returns the rows linking nothing rather than zero rows; on Note.note_links it 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, in GET ?fields and in _search alike, 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-1 and must be stored in a text field (probe 019 saw the same ceiling on a created field). The create path names the cause, PG::NumericValueOutOfRange; the update path says only Invalid statement.

  • A float is rejected, not coerced. int() anything computed (a mean, a ratio, n/2 in Python 3) before writing it. A numeric string coerces, so "42" works and 42.0 does not.

  • 0 is a value, '' is not a clear. null is the only clear. Following probe 007: a row holding 0 is is_not None, so a number field full of zeroes scans as 100% filled, exactly like a checkbox full of False. Rank a number field by greater_than 0, or by _summarize grouping (probe 020), never by fill rate.

  • Negation includes nulls; comparison excludes them. is_not 1001 and not_in [999999] return the null rows too (3 and 4 of 4), while greater_than -1 returns 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 exclude data_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 None correction 400s. Drop the type before ranking, the way probe 007 drops checkbox.

  • A sort on a password field 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_proxy reports editable: true. Treat that as a schema claim only: no probe writes a password field, 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 with expected [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, 101 and 1000000 all store at 200 and read back unchanged, and no properties key 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.

  • 0 is a value and "" is not a clear. Following probe 007, a row holding 0 is is_not None, so a percent field full of zeroes scans as 100% filled. Rank by greater_than 0, never by fill rate.

  • Negation includes nulls; comparison excludes them. is_not 50 and not_in [50] return the null rows too, 3 of 5; greater_than -1 returns only the 3 rows holding a value. A "not yet at 100%" filter written as is_not 100 sweeps 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 None probe 400s like a checkbox, and the _summarize fallback 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_0 exists on types that have no Steps at all, so its presence says nothing about whether the type is task-tracked. Read Step.entity_type for 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 None to 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.splits answers 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 and source: null. Neither names the key at fault.

  • The column takes arbitrary JSON; the field refuses it. EventLogEntry.meta holds nested objects, lists, booleans and nulls, so the storage is a blob. Of the four editable fields three are outside a project: Project.tracking_settings is site configuration, SavedFilter.filters and RvLicense.meta have no project field. 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_values is not a subset of valid_values. On the probed sandbox project Task hides blk and rdy, neither of which valid_values contains, so writing one is 400 while the hidden-but-valid hld writes 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_values is not enforced by the API. REST 201s and 200s on a status the project's UI refuses to offer, so every client must subtract hidden_values itself (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_values in 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_values once and filter the list client-side. Sorting and filtering is on the code, which is not alphabetical by label.

  • Codes are per entity type: Version has 16, Shot 10, Shot.sg_latest_vendor_status 6. 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_count is never null, so it scans as 100% filled while holding one value: 100 Versions all read 0 (probe 007). The other four read null on every row and scan as 0% filled while their queries match rows. Exclude data_type == "summary" from fill ranking; the is_not None probe 400s, as does _summarize grouping.

  • Sort fails silently. ?sort=code and ?sort=-code return different orders, ?sort=open_notes_count returns the unsorted order, and so does ?sort=definitely_not_a_field: an unsortable field and a typo are indistinguishable at 200.

  • editable: true describes 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 from editable offers three that can never be saved.

  • 38 of the 42 are open_notes_count, one per entity type, all counting Notes whose status is opn, ip or rdy. That set is the site's definition of "open", readable from properties.query and 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 stores null. 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_not and not_contains return the null rows, so is_not X is not the complement of is X. is '' matches exactly the rows contains '' skips.

  • Leading and trailing whitespace is stripped on write, silently, so ' ' is stored as null.

  • cached_display_name reports editable: True and accepts a write at 200, then discards it. It mirrors code, and re-reads as the new code after a rename. Never write it.

  • in [None] teaches nothing: code 104, source: null, detail: null. Use is 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 _summarize writes 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 for number and duration. Send int milliseconds.

  • Nothing is validated as a time. -3600000, 86400001 and 2147483647 all store, and render as -1:59:59:00, 24:00:00:00 and 596:31:23:16; -1 renders 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 3600000 and not_in [999999999] return the null rows too (3 and 4 of 4), while greater_than -1 returns only the 2 rows holding a value. A row holding 0 is is_not None, so a field full of zeroes scans as fully populated (probe 007); rank by greater_than 0.

  • A new field belongs in text, not here. Every stock field a cut or a source clip uses for timecode is text plus a number rate, which round-trips HH:MM:SS:FF and 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_movie and test the value client-side. _summarize refuses with the same message under API summarize() (probe 021), so a fill-rate scan must special-case data_type == "url".

  • The filterable neighbours are proxies, not answers. image is_not None and sg_uploaded_movie_transcoding_status is_not None both matched exactly the media-holding rows on the sample project, and on two Versions uploaded and then cleared both still matched the row after sg_uploaded_movie had 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_type before anything else. upload and web are indistinguishable by keys, and a local value has no url key at all, so indexing value["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 null is a 400, not a filter. Use is "" for "unset" and is_not "" for "set". The empty string is legal only with is and is_not: in [""] fails as a malformed uuid.

  • A malformed filter value 400s the whole read. Code 104 invalid input syntax for type uuid surfaces the database. A prefix, a urn:uuid: form, surrounding whitespace and any non-uuid string all fail. Validate client-side; there is no partial match to fall back on, since contains is unsupported.

  • is_not and not_in return the rows where the field is null, so is_not X is not the complement of is X. Add is_not "" to exclude them.

  • Sorting on a uuid field fails, on both spellings: GET /entity/icons?sort=uuid and _search with "sort": "uuid" return 400 code 104 Read failed for entity type [Icon], with source and detail null. sort=id on the same endpoint returns 200. Page by id and 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 text field, which is writable and supports is, in and contains.

corpus/findings/field_types/uuid.md

Every entry on this site is the output of a probe in probes/. The corpus is generated by running those probes against a live Flow Production Tracking site, not written from memory.

Not affiliated with or endorsed by Autodesk. Flow Production Tracking is their product; this is an independent record of how its REST API answers.