# ManyRows ManyRows is an agent-ready product lifecycle management (PLM) system for teams across industries. Teams connect parts, BOMs, controlled documents, quality, reviewed changes, and release evidence in the web workspace. Optional AI agents can build product models, trace change impacts, check revision release briefs, and prepare updates for review. The workspace review inbox brings together assigned, awaiting, and returned or rejected changes across accessible projects. Authorized administrators can follow recorded agent actions into linked reviews. Revision certification, assembly configuration, as-built state, and shipment eligibility are distinct decisions. Its configurable model supports strongly typed fields, real relationships, and polymorphic base types. Its Data API is a server-to-server JSON HTTP API over one project's schema, records, collections, assets, bills of material, specifications, quality evidence, and release/configuration traceability. ## Product and company Material composition: use the record's Material composition tab or `GET/PUT /entities/{id}/material-composition` with an explicit quantity unit, measured mass per unit where needed, and constituent mass percentages. `GET /entities/{id}/composition-summary` returns primary-BOM contained mass, weighted constituents, captured source profiles and missing-data coverage. Purchasing wastage is excluded; missing mass is not zero. Approved revisions preserve evaluated evidence. See https://manyrows.com/docs#material-composition. Nutrition evidence: Material composition → Nutrition evidence, or GET/PUT /entities/{id}/nutrient-facts, GET /entities/{id}/nutrient-facts/history and GET /entities/{id}/nutrition-summary (external REST/MCP). Store team-reviewed source values per 100 g (energyKcal, proteinG, fatG, carbohydrateG, sugarsG, sodiumMg) with named scope, source and review date. Explicit zero is evidence; missing values remain gaps. Optionally record reviewed servingGrams on the finished formula. Reviewed source facts plus exact primary-BOM input masses produce per100G; a reviewed root serving mass produces perServing. Missing/unreviewed facts, unknown mass, mixed scopes, unsupported formula roles/bases, output allocation, unavailable inputs and structural limits remain incomplete. Zero usage and purchasing waste are excluded. For single-output formulas, an optional separately reviewed processing block on the root fact profile records finished-mass yield above 0 through 100 percent, explicit 0–100 percent retention for each of the six nutrients, process source and review date. Complete reviewed inputs plus all six reviewed retentions produce distinct finishedMassKg, finishedPer100G and, with reviewed servingGrams, finishedPerServing; input-mass results remain separate. Missing values never default to 100 percent. Co-product allocation, label rounding and regulatory requirements remain outside this estimate. Facts are append-only versioned, including removals; GET provides sequence-bound ETag; PUT requires exact quoted If-Match (missing 428, stale/weak/wildcard/multiple 412), and no-op writes do not append. Frozen/submitted records refuse edits; governed live records need working copies. CR clone/diff/apply, approved frozen source evidence, reversion and copySizeSpec duplication preserve this record’s current facts; earlier revisions disclose uncaptured evidence. History is newest 100 plus hasMore. Summary accepts only asOf/asOfUnit and requires read access to every captured BOM input field in a consistent snapshot; protected historical results remain redacted. Shared manyrows schema stores small workspace/project-scoped fact versions; workspace partitions retain high-volume record and BOM data. See https://manyrows.com/docs#nutrition-evidence. Nutrition label reviews: dashboard Material composition → Nutrition label reviews on an active, unlocked live product. Latest approval-bound product revision must capture complete processed nutrition; per-serving display also requires reviewed serving mass. A signed-in data writer supplies a command UUID, revisionId, market, exact rule edition/source, per100g or perServing basis, all six proposed display values and optional note. Compare displayed values with the frozen estimate before recording; market rounding and regulatory compliance remain human reviews, with no supplied country rules or packaging artwork. GET /entities/{id}/nutrition-label-preview returns frozen revision evidence and SHA-256 validator; GET /entities/{id}/nutrition-label-reviews returns paged immutable history and flags a newer product revision. POST /entities/{id}/nutrition-label-reviews requires the exact quoted preview If-Match: missing 428, changed 412, changed command identity 409. Exact retries return the original receipt after head changes, subject to current access. Private/no-store reads require current and all captured BOM input-field permissions, including off-page history. These three paths are dashboard-only, excluded from external REST/MCP. Small review evidence stays in the shared manyrows schema. See https://manyrows.com/docs#nutrition-evidence. Allergen evidence: Material composition → Allergen evidence, or GET/PUT /entities/{id}/allergen-declaration, GET /entities/{id}/allergen-declaration/history and GET /entities/{id}/allergen-summary (external REST/MCP). A profile has named scope (1–120 characters), explicit contains and crossContact arrays (at most 100 unique canonical names across both, 1–80 characters each), reviewed boolean (default false), source reference (up to 2,000 characters), and optional reviewedOn date YYYY-MM-DD. Reviewed profiles require source/date; reviewed empty arrays mean none declared only within that scope. Null removes and retains a removal version; missing lists, duplicate names across lists and unknown body fields are refused. GET returns profile, sequence-bound version, versionNumber and optional creator/time; conditional If-None-Match works. PUT requires the exact quoted ETag in If-Match: missing 428; stale/weak/wildcard/multi-token 412. Normalized no-op writes add no version/audit; restored content gets a new sequence. Frozen/submitted edits refuse, governed live records need working copies; declaration-only CR changes carry/diff/apply/freeze/revert correctly. Specification duplication copies current declarations only with copySizeSpec, keeping origin history. History returns newest 100 plus hasMore; no query parameters on profile/history. Summary accepts only asOf/asOfUnit for effective primary formula lines, not historical declarations. Distinct input-leaf unions retain declared ingredients and cross-contact separately, contributing source IDs, full declarations/versions, matching latest approved source revision IDs when available, and explicit gaps. No mass profiles/conversion needed for positive qualitative inputs, including Fixed additions; ignore purchasing waste and zero usage paths. Assemblies expand input leaves; own declarations never override recipes. Formula outputs are excluded; output separation remains unsupported and keeps results incomplete. Missing/unreviewed declarations, mixed scopes, negative quantities, unsupported roles/bases, unavailable records/lines (including deleted children behind live lines), cycles, depth above 50, more than 10000 usage lines, 1000 distinct input leaves or 1000 distinct names prevent completeness. Known evidence remains partial; input/line limits decline without invented results. UI reveals sources/gaps/names in batches of 50. Existing allergen note/multiselect fields are not trusted as reviewed declarations. Project data read plus all captured parent/child/quantity/role/basis permissions protect live and frozen evidence; writes need read+write. Reads are private/no-store in consistent snapshots; fresh denials clear cached evidence, context changes discard late responses. Approved revisions preserve full evaluated source declarations and coverage; old revisions disclose uncaptured evidence. Reversion restores this record's captured declaration/removal, not every supplier's evidence; recalculation uses current inputs. A stale UI write keeps the draft and blocks blind retry; lost responses reconcile only matching exact-next-version content by reading. Unconfirmed saves hide calculations until a successful reload. Check history/current version before a new edit after closing/navigation. Complete means reviewed input coverage in a common team-owned scope, not finished-product allergen absence or label approval. Team owns scope/name vocabulary/source review; no supplied regulatory list, aliases, concentration threshold, automatic expiry/process-loss assessment or packaging label generation. See https://manyrows.com/docs#allergen-evidence. Environmental impact: `GET/PUT /entities/{id}/material-impact`, `GET /entities/{id}/material-impact/history`, and `GET /entities/{id}/material-impact-summary` provide versioned cradle_to_gate material-production factors in kg CO2e per kg and contained-material BOM estimates. PUT requires the current quoted version in If-Match; explicit null appends removal and unchanged content is a no-op. Method, source and dataset version are required. Totals are absent for missing mass/factors; different method labels suppress aggregates. Coverage is mass-based and unknown total mass leaves it absent. This is not a verified whole-lifecycle product footprint. Revisions and saved substitution comparisons preserve source versions; factor changes invalidate comparison freshness. See https://manyrows.com/docs#material-impact. Certificate applicability: `GET /entities/{id}/certificate-applicability` (`get_entities_by_id_certificate_applicability`) provides paged explicit scope attestations, inclusive dates, captured certificate-revision identity and withdrawal history. Both target and source must have latest approval-bound revisions when linking. `POST` on that path requires data-write access, a caller-generated UUID id, revisionId, certificateEntityId, certificateRevisionId, claim, validFrom, validUntil and scopeConfirmed:true. After an uncertain create response preserve ID/body/credential; an exact replay returns 200 without duplicate history. `POST /entities/{id}/certificate-applicability/{applicabilityId}/withdraw` appends a reason with a single exact If-Match version; uncertain retries preserve reason/actor/version. Renewals, newer targets, expiry, unavailable sources and withdrawals prevent current applicability. Optional schemeVersionId and scopeKey together capture a structured scope assessment; saved gap or unknown results also prevent usable applicability. Manual attestations are not mapped into schemes automatically. Historical revisionId filtering does not reconstruct past state; assessment uses today's UTC date and current heads. Source deletion retains captured identity; purging the target removes its receipts. Custom certificate fields are read through permission-filtered `GET /revisions/{certificateRevisionId}`. Material certificates do not automatically certify parent products or authorize release. Workspace Certificates and revision views show exact captured evidence. All three applicability operations have typed MCP contracts. See https://manyrows.com/docs#certificate-applicability. Certificate scope rules: `GET /certificate-schemes` (`get_certificate_schemes`) pages latest project-defined schemes, or all versions of an exact key. `GET /certificate-schemes/{versionId}` (`get_certificate_schemes_by_version_id`) reads an immutable version. `POST /certificate-schemes` (`post_certificate_schemes`) requires data read/write and schema management. Definitions provide a caller UUID id, stable key/name/edition, certificateTypeIds, three distinct source field IDs and 1-20 scopes. Scopes restrict targetTypeIds and optionally compare approved fields (equals, at_least, at_most) or require minimum constituent percentages. Updates require exact previousVersionId; identical ID/body/actor retries replay without duplicating versions. `GET /entities/{id}/certificate-scope-assessment` (`get_entities_by_id_certificate_scope_assessment`) is a typed read-only preview requiring exact revisionId, certificateEntityId, certificateRevisionId, schemeVersionId and scopeKey. Both records must have those latest approved revisions; a frozen target may be previewed. Uses saved approved values, captured field bindings and selected rules. Known failed checks yield gap; missing or incomplete inputs yield unknown unless a known gap exists. Constituent checks use a complete approved material profile or saved physical BOM summary; an incomplete configured assembly never falls back to a manual profile. Results never copy observed values. Include schemeVersionId and scopeKey together in a certificate-applicability POST to capture the assessment. Only pass counts as usable structured evidence. Hidden captured rule or composition inputs return 403 for affected definitions, previews, receipt pages, coverage counts and writes. Definitions and assessments remain unchanged by later versions. These are project rules, not issuer verification or built-in regulatory standards. Exact versions can be required by a separate certificate release policy. Private, no-store; unsupported queries refused. The Certificates tab includes a version editor, previews, captured rules and exact-version coverage filters. See https://manyrows.com/docs#certificate-schemes. Certificate release requirements: `GET /certificate-release-policies` (`get_certificate_release_policies`) pages the latest policy for each release-controlled type; exact entityTypeId pages newest-first history. `GET /certificate-release-policies/{versionId}` (`get_certificate_release_policies_by_version_id`) reads an immutable version. `POST /certificate-release-policies` (`post_certificate_release_policies`) requires data read/write, schema management and visibility of captured inputs. Supply a caller UUID id, entityTypeId and an explicit requirements array (up to 10 distinct entries; [] disables future gates). Each entry pins schemeVersionId, scopeKey and recordScope=root|bom. Root entries omit targetTypeIds; BOM entries select 1–50 distinct scope-compatible type IDs. Updates require exact previousVersionId; the original actor's identical ID/body retry returns the original version, and conflicts require reviewing the current head. Scheme updates never silently repin policies. Root checks need no BOM. BOM checks include all effectivity periods in the primary BOM and require each distinct selected record's own usable structured receipt at its latest approved revision, including matching roots and intermediate assemblies; parent/child receipts never substitute. Zero-quantity and formula-output branches are excluded. Manual attestations, other definition versions, expiry, withdrawal, changed certificate heads and gap/unknown scope results cannot satisfy requirements. Missing/invalid BOMs or zero matching records block certification. Policy, graph, heads, all matching receipts and inclusive validity use one consistent snapshot and the server's UTC transaction date. Typed release readiness returns certificateCoverage plus certificate_coverage_gap/unknown blockers. Every selected record and one usable receipt pin appear in a passing checkpoint; history pages and example limits cannot truncate it. More than 1,000 records per requirement or 4 MiB yields unknown. Readiness versions cover policy and coverage changes and stay stable within the same UTC day; review again if confirmation readiness changes. A conflicting record edit during certification requires a fresh review and saves no release evidence. Certification saves the policy, revisions, receipt/source pins, dates, claims and rule checks in immutable evidence. Later changes never rewrite or revoke that issued checkpoint; new product revisions use current requirements, and old certificates remain unchanged. Historical release packages include the saved checkpoint in release-certificate.json without adding full source revisions or certificate files. Hidden captured scheme, composition or BOM inputs return 403 before readiness, version or historical evidence is exposed, including briefs/configuration readiness; batch snapshots report a forbidden section. Private, no-store; unsupported queries refused. The Release control policy page manages exact pins, selected types, history, retained drafts and uncertain retries; Changes & releases distinguishes current coverage from certificate evidence at release. Issuance remains a human admin action. These project rules do not verify issuers, regulatory compliance or shipment eligibility. See https://manyrows.com/docs#certificate-release-policies. BOM certificate coverage: `GET /entities/{id}/certificate-coverage` (`get_entities_by_id_certificate_coverage`) assesses the current root and each distinct primary-BOM assembly/material once, without inheriting links between records. Optional asOf/asOfUnit select current BOM lines; validity always uses today's UTC date, current heads and withdrawal state. Optional claim is exact and case-sensitive after trimming (up to 500 characters); blank accepts any declared scope, not equivalent schemes. Optional schemeVersionId and scopeKey filter by an exact immutable definition and selected scope; manual attestations and other versions do not fulfill that filter. Only saved passing assessments count as usable structured links. Global totalRecords/linkedRecords and graph issues cover every record page (default 50, maximum 200). Every matching receipt is assessed; each record shows at most five examples, preferring usable links, with hasMoreEntries and counts. Open certificate-applicability for full history and permission-filtered revision readers for fields. Zero-quantity and formula-output branches are excluded; missing quantity defaults to one. Negative quantities, unknown roles, unavailable usage, cycles and the 50-level boundary prevent complete. Complete requires a primary BOM and usable matching links on every record; counts measure evidence presence, not certified mass, compliance or release authorization. All BOM reference, quantity and role inputs, plus every matching receipt's captured rule and composition inputs, must be readable, including outside the current record page or five examples; otherwise 403. The typed MCP operation is read-only. Responses are private, no-store; historical revisionId and unsupported queries are refused. See https://manyrows.com/docs#certificate-coverage. Certificate renewals: read-only typed `GET /certificate-renewals` (`get_certificate_renewals`) groups recorded receipts on live targets by exact schemeVersionId/scopeKey or exact case-sensitive trimmed manual claim. The longest currently usable receipt wins; active exact replacements clear old expiry alerts, while future evidence stays pending until its inclusive start date. Assessments use the server's UTC transaction date, current approved target/source heads, availability, saved checks and withdrawals in one repeatable-read snapshot. Valid through today is usable; expiring includes today plus the horizon. Without current coverage, date-eligible expired evidence takes precedence over future evidence. Different definitions/claims and parent/child/newer revisions never substitute. Held records remain visible; archived, draft, trashed, replaced and staged targets are excluded. status defaults to attention (all except current); also accepts all, expiring, expired, unusable, upcoming and current. horizonDays defaults to 30, range 1–365. Optional entityId/schemeVersionId are exact project UUIDs; q is a case-insensitive name/reference/claim/scope search up to 200 characters. Group paging defaults to 50, clamps at 200, offset is nonnegative. Response includes assessedOn, horizonDays, throughDate, complete, summary?, groups, total?, limit, offset, hasMore, issues and inputFieldIds. Summary counts cover the whole search/identity selection before status and paging; total covers the selected status. Rows retain exact definition version, selected receipt/source revision pins, validity, usable/recorded counts and pending future start. More than 10,000 selected receipts returns complete:false with receipt_limit, no summary/total and no rows; narrow by record or exact scheme, not search/status/page. Every selected receipt's captured inputs protect derived counts and ETags, including beyond pages, search/status or the limit; denied inputs return 403 before ETag/304. Private, no-store; authorized unchanged representations support If-None-Match/304. Unsupported queries and assessment-date overrides return 400. Project home exposes the same default 30-day certificateRenewals summary, omits restricted inputs, and names unknown evaluation in failedSections with partial:true. The Certificate renewals page links to each record's Certificates tab to review and explicitly link replacement evidence; the queue requires only data read. It covers recorded scopes: release readiness checks requirements with no receipt, and certificate-coverage checks the BOM. Renewal reads/writes never rewrite or revoke immutable release checkpoints. No issuer, regulatory or shipment verification is inferred. See https://manyrows.com/docs#certificate-renewals. Sample and test reviews: Quality → Sample & test reviews captures immutable sessions on a physical sample/test record against an explicitly selected exact approved specification revision, including older approved revisions. Typed read-only `GET /entities/{id}/review-session-specification` (`get_entities_by_id_review_session_specification`) requires revisionId and optional size; chart preview without size lists sizes, while selected size resolves graded/overridden targets. Older charts without captured size-field bindings return 422 and require a newly approved revision; general revisions use frozen characteristics and refuse size. Typed `POST /entities/{id}/review-sessions` (`post_entities_by_id_review_sessions`) requires data read/write, a stable command UUID id, revisionId, project check kind, explicit YYYY-MM-DD checkedOn and authored verdict approved|conditional|rejected. Optional size, notes (4000 characters), measurements (up to 200 unique characteristic/value pairs with explicit finite values) and photoIds (up to 10 distinct live project image IDs) are server-resolved against captured revision limits and image metadata. Optional photoAnnotations groups each attached photo once as {photoId,callouts:[{x,y,text}]}, with an explicit callouts array, at most 50 pins per photo, explicit finite x/y percentages in [0,100] and trimmed 1–200-character labels. Empty groups normalize away; legacy unannotated bodies still replay. Draft annotations are captured only when the review saves, participate in exact retry identity and never update live image-library annotations. Blank measurements stay absent; missing/null actuals do not become zero. Missing targets are unknown, missing tolerance sides zero; sized deviations round to three decimals and missing both size tolerances is unknown, while unsized nominal-only characteristics require exact equality. Measurement results do not choose the authored verdict. Rejected-only requestNextSample, followUp (2000 characters), member owner and dueOn create a canonical rework action; next-sample requests require instructions and dueOn cannot precede checkedOn. Round, evidence, action and audit commit atomically. New command returns 201; identical normalized ID/body/principal replay returns the original 200 result without another round/audit, including after source changes; conflict is 409. New commands bind stable signed-in account ID, API key ID, or delegated grant plus account ID. Email/key/client-name changes preserve replay and the captured original actor label; a different principal with the same displayed name/email cannot replay. Legacy commands keep their exact captured-actor rule, with no automatic identity backfill; changing those labels can still block legacy replay. Actor/principal request properties are forbidden. Current project/scopes/read-write/captured-input authorization is required on every retry; stable identity does not retain revoked access. Preserve ID/body/credential, including submitted annotations, after uncertainty. The review UI can import local CSV/TSV files or pasted text with exactly characteristic,value headers, up to 200 rows and 256 KiB UTF-8. Comma/semicolon/tab separators and quoted names are supported. Names match the approved revision exactly, including case, after trimming; duplicate or unknown names, units, thousands separators, malformed rows, overflow and nonzero numeric underflow block the whole batch. Preview values shows current/imported actuals, frozen targets and derived results for the selected revision/tested size before explicit Apply to draft. Blank values clear listed actuals; omitted rows stay unchanged. Apply updates local draft autosave without submitting a review or changing its authored decision, notes, photos or follow-up. Cancel changes nothing; raw file/pasted text and unapplied previews stay ephemeral. This is a UI workflow over the existing measurements input, with no import REST/MCP operation. Workspace autosaves one browser-local review draft per account, project and sample in IndexedDB; wait for Draft saved on this device before closing the tab, then reopen the same sample to resume. Drafts on this device lists the current account/project’s unfinished reviews on the unselected review page; Saved drafts returns there from a selected sample. Bounded local pages expose identity/status summaries without notes, measurements, pins or command bodies; sample/specification/photo access is freshly checked before names appear. Resume draft opens the exact sample and rechecks restoration access. Recover pending save opens recovery without automatically posting. Denied inputs keep a generic recoverable entry; unreadable records remain visible without guessing pending/working state. Committed same-tab changes refresh discovery; Refresh drafts reloads changes from other tabs. Discovery adds no REST/MCP operation. Drafts retain the exact selected revision and size, raw actuals, date, kind, decision, notes, follow-up, attached photo IDs and applied pins. They do not cache specification limits, source names, image URLs, unfinished uploads, unadded photos or unapplied annotation edits, and do not sync between devices or browser profiles. Fresh sample/specification/photo authorization is required before displaying restored inputs and before preparing a new command. A removed kind requires explicit replacement and a newer revision never silently replaces the chosen one. Before POST, the exact UUID/body is durably committed locally; uncertain commands survive reload and tab closure, lock edits and discard, and require explicit Retry saved command with fresh server authorization. Access loss, conflicts and unavailable records retain the command; only a definite HTTP 400/422 validation rejection unlocks the authored draft. A confirmed response clears only the matching command. Storage failures, unreadable rows and competing-tab changes block blind replacement or submission. Editable drafts have confirmed discard; pending commands are not automatically expired or evicted. Clearing browser storage removes this local recovery state. Full offline capture remains a separate workflow. Samples must be live, non-staged, non-draft, non-archived and non-replaced; held samples permit quality observations. Typed `GET /entities/{id}/review-sessions` (`get_entities_by_id_review_sessions`) pages newest-first with limit default 50/clamped 200 and nonnegative offset, returning sessions/total/limit/offset/hasMore. Every captured input anywhere in that sample's full history protects counts before pagination; denied inputs return 403. Typed `GET /entities/{id}/review-sessions/{sessionId}` (`get_entities_by_id_review_sessions_by_session_id`) reads an exact historical session with its captured inputs guarded. Typed read-only GET /review-session-comparison (get_review_session_comparison) requires exact leftSampleId/leftSessionId/rightSampleId/rightSessionId UUIDs. Both samples and both sessions’ captured inputs are guarded in one snapshot before any evidence is returned; unrelated private history does not block an exact authorized pair. Returns left/right captured sessions, global differences and the union of frozen characteristic rows. Rows retain absent/unmeasured values, captured limits and results. Finite delta is right minus left only where both measured values and specification record/basis/size/kind/unit/method/target/tolerances match. Missing limits stay distinct from explicit zero; no automatic conversion is performed. Revision differences warn but allow a delta when captured criteria otherwise match. Comparable saved pass/fail transitions are unchanged, became_pass or became_fail; other resultChange values are unknown and never infer the authored verdict. Workspace Compare reviews explicitly selects same- or cross-sample pairs, pages older sessions and keeps the pair in the URL. Evidence preserves sample and specification identity, selected size, limits, methods, measured results, photo names/rendition URLs/numbered callouts, decision, original follow-up, actor and timestamp. Linked checks expose reviewSessionId; use check disposition endpoints or the quality queue to change current ownership/due/completion without rewriting the session. Ordinary check deletion, per-kind check import replacement and generic measurement edits return 409 for captured review rounds; sample purge cascades its sessions. Structured callouts render over the saved preview; the original rendition is not a flattened annotated image. Asset bytes follow ordinary image-library retention. All fifteen review and request operations are private, no-store and reject unknown queries/properties. Session measurements do not feed generic measurement trends or replace current chart actuals. No automatic new sample, supplier message, inspection-plan satisfaction or release certification. Sample requests connect rejected review instructions to an existing received sample or reworked original record and one linked follow-up review per receipt. The queue defaults to awaiting_receipt and awaiting_review, with reviewed available explicitly; receipt/review progress never closes the current quality action. Typed GET /review-sample-requests pages requests and current action metadata; GET /entities/{id}/review-sessions/{sessionId}/sample-request reads current progress; GET /entities/{id}/review-sessions/{sessionId}/sample-receipts pages immutable receipt history; GET /review-sample-receipts/{receiptId} reads exact receipt context. All historical request inputs protect evidence/counts before filtering or paging. POST /entities/{id}/review-sessions/{sessionId}/sample-receipts records an existing live receivedSampleId, receivedOn and command id; corrections require the latest previousId and explanatory notes; omit received record/date to withdraw. Every correction appends history. Exact normalized command/principal recovery returns 200 after later changes; different source/body/principal returns 409, and a stale prior head returns 422 without creating an event. Held records permit receipt observations. Start follow-up review retains the original exact approved revision, size and kind with fresh observations; different existing drafts and pending review commands are preserved. Optional receiptId in POST review-sessions captures immutable followUpOf lineage and predecessor input permissions. Review date must be on or after receipt; one new review may be saved per current available receipt. Receipt save uncertainty retains the exact command in account/project/request-scoped IndexedDB, with explicit retry after reopening and no automatic POST. Browser clearing/eviction loses local state. The review draft storage upgrade preserves old data and prevents older open tabs from dropping new lineage. Source purge cascades receipts while surviving follow-up evidence/recovery remains; received record purge keeps receipt pins but prevents new review. Offline capture and freehand drawing remain gaps. Sample request cancellation/reopening: typed GET/POST /entities/{id}/review-sessions/{sessionId}/sample-request-events pages {events,total,limit,offset,hasMore} newest version first or appends an explained state event. POST needs command id, status cancelled|open, trimmed notes of 1–2000 characters and, after the first cancellation, exact latest state previousId. Untouched requests are open; repeated state or stale head returns 422 without writing. Requires current project data read/write, stable authenticated principal and every historical request input. GET uses default limit 50/clamped 200 and nonnegative offset; its exact subject and historical inputs guard evidence/counts before paging. The request response includes optional state and stage cancelled; queue defaults to awaiting receipt/review and stage=cancelled explicitly finds cancelled requests. Cancellation blocks new receipts, corrections/withdrawals and linked reviews, preserves original instructions, receipt/review history and current quality action, and serializes with their writes. Reopening resumes existing receipt/review progress. Event/audit commit together; normalized ID/body/source/principal replay returns original 200 after later transitions, new command returns 201, conflicting reuse 409. Private command metadata stays private; captured-input/current credential authorization applies to recovery. Source purge cascades state history. UI Cancel sample request and Reopen sample request require reasons; Retry saved request change recovers an uncertain exact command from durable browser storage without automatic POST. Receipt, state and delivery-link saves share one unresolved local slot per account/project/original request. Legacy pending receipt/state rows survive its version-3 delivery upgrade; older tabs must reload. Unfinished linked review drafts remain but new saves require an open request; committed exact receipt/review saves still recover after cancellation. Sample delivery commitments: typed GET/POST /entities/{id}/review-sessions/{sessionId}/sample-deliveries pages immutable association history or creates/links/replaces/unlinks a delivery. Requires current data read, cost access and all historical request inputs; writes also require data write, stable principal and an open requested rejected review. Supply id and either deliveryId or create:{supplierId,title,quantity,unit,promisedOn,owner}; creation uses the command UUID as delivery UUID and original reviewed record as item, with live priceable supplier and member owner (blank defaults to caller). Quantity is positive, at most 12 integer/6 decimal digits; promise is on/after original review. Existing delivery must be uncancelled, for that exact item, and exclusively bound to this request while its link history exists even after unlinking. Replacement/unlink requires exact latest previousId and explanatory notes up to 2000 characters; unlink omits deliveryId/create. Link notes are not copied into procurement notes. Link/create/webhook intent/audit commit atomically; exact normalized UUID/body/source/principal recovery returns original 200 after later changes/cancellation, new 201, conflict 409, stale/repeated head 422. Held records permit coordination. GET uses limit default50/clamped200 and offset>=0 with complete historical-input guards before counts/paging. Request and queue include canTrackDelivery and optional delivery:{link,commitment?}, with a frozen selected commitment in link history and current delivery progress separately. No-cost data readers retain ordinary sample progress without delivery details or receipt proof. Optional deliveryReceiptId on sample receipt POST requires cost access and an active receipt/correction on the current linked delivery, not superseded/voided, with exactly matching receivedSampleId/evidence and receivedOn. Saved deliveryReceipt captures linkId/deliveryId/eventId/quantity/unit and complete historical request input permissions; it links existing evidence without adding another supplier receipt. Later delivery changes do not rewrite sample receipt/review evidence. GET /supplier-deliveries accepts exact itemId before filtering/counts/paging. UI creates/links deliveries, displays supplier/owner/promised date/quantities/overdue status, opens the delivery workbench, pages independent link history, and uses active delivery receipt evidence for the existing exact-specification/size follow-up. Cancellation blocks new link changes; committed commands remain recoverable. Retry saved delivery command is explicit after closed-tab recovery; browser eviction/clearing still loses local state. Source purge removes link and sample-receipt history while procurement commitments/events remain independent. Supplier dispatch and tracking entries are available in Purchasing → Deliveries; automatic carrier feeds remain separate. See https://manyrows.com/docs#sample-reviews. Delivery to sample request handoff: typed read-only GET /supplier-deliveries/{deliveryId}/sample-request (`get_supplier_deliveries_by_deliveryid_sample_request`) requires current project data read, cost access and every historical input of the associated request. Returns {request?,isCurrent} with original captured review, current sample receipt/review, current quality action and separately refreshed delivery commitment in one repeatable-read snapshot. A real unbound delivery or unavailable source returns isCurrent:false without request; unknown or foreign-project delivery returns 404. Historical binding survives replacement/unlinking with isCurrent:false; cancellation retains binding and cancelled request stage. Denied historical inputs return 403 without names, identities or state, including private older follow-up inputs preserved by link/receipt snapshots after received-record purge. No query parameters; private, no-store. Purchasing → Deliveries shows Original sample request, original instructions, specification/tested size and current progress. Open original sample request returns to the exact request; Open follow-up review opens the current saved review. Historical deliveries show a warning; Refresh sample request freshly checks access. Denied request details do not disable ordinary procurement receipts. Account/project/delivery/capability changes hide stale request results. This lookup never records another receipt, starts a review or closes a quality action. Opening the request uses the existing draft and command recovery rules and requires an explicit receipt or review save. Source purge removes its association while procurement deliveries/events remain independent. See https://manyrows.com/docs#sample-reviews. Supplier dispatch and tracking: typed GET/POST /supplier-deliveries/{deliveryId}/dispatches (`get_supplier_deliveries_by_deliveryid_dispatches`, `post_supplier_deliveries_by_deliveryid_dispatches`). GET requires current project data read and cost access, resolves the exact delivery before counts/paging, and returns {delivery,dispatches,total,limit,offset,hasMore,canWrite} in one repeatable-read snapshot. Only limit(default50/clamped200)/offset>=0/activeOnly=true|false/receiving=awaiting|overdue|received are supported; receiving always implies active-only and filters before counts/paging using explicit physical receipt links, independent of inspection acceptance. Overdue needs an estimate before today UTC and remaining quantity; today/missing estimates are excluded; newest version first, active flags use complete history. POST additionally requires data write, writable credentials and a stable authenticated principal; delegated callers need read/write scopes. Send new command id, current delivery version and kind dispatch|correction|void. Dispatch/correction needs positive quantity (12 integer/6 decimal digits), dispatchedOn<=today UTC and optional expectedOn>=dispatchedOn, carrier<=120 characters, tracking<=200, notes<=4000. Correction/void needs active targetId and explanation; void omits quantities/dates/carrier/tracking. Active dispatch total cannot exceed the promise; amend first. Amendments cannot reduce below active dispatch quantity; cancellation requires no active dispatches or receipts. Dispatch/correction history cap1000; voids remain available. New201; exact normalized UUID/body/delivery/stable-principal replay200 after later transitions or renames; changed reuse409; new stale/inactive/capacity refusal422 without writing. Original actor remains immutable; private replay metadata stays private. Private,no-store; unsupported queries/properties refused. Transit is max(active dispatched minus gross physical receipts,0), undispatched=max(promise-dispatched,0), estimated using all receipts; explicit outstandingDispatch uses assignedReceived with unassignedReceived reported separately. Active dispatches include rootId and receiving{received,remaining,status,overdue,lastReceivedOn?}. Legacy receipts stay unassigned. expectedOn is the latest active shipment arrival date with remaining linked receiving capacity, separate from the promise, and latest holds the newest active carrier/reference. Current delivery/sample request progress refreshes independently of frozen association history. Purchasing → Deliveries supports manual entry, explained correction/void, paging and in_transit filtering. GET /supplier-deliveries additionally accepts status=awaiting_shipment_receipts|overdue_shipments|unassigned_receipts; exception views include accepted-complete deliveries and exclude cancelled commitments, with all search/item/supplier/promise filters applied before totals/paging in one read snapshot. Gross receipts can complete a delivery while its shipments still await links. Resolve unassigned arrivals by correcting the original receipt to select a shipment, never by duplicating arrival. Awaiting/overdue delivery results open the matching shipment view; view changes reset paging and hide old rows. Summary CSV walks matching pages and includes assigned/unassigned physical received, shipment receipt balance and overdue shipment count. Exact command is durably saved in account/project/delivery-scoped IndexedDB before POST; Retry saved dispatch command is explicit after closed-tab recovery, no automatic POST. Uncertain/403/409 outcomes retain it; 400/422 restores inputs for a fresh reviewed command. Storage failure blocks new writes; browser clearing/eviction loses local state. This records no ordinary/sample receipt, review, stock or quality completion. No automatic carrier feeds, notifications or cross-device recovery. Source sample purge leaves procurement dispatch/receipt history independent. See https://manyrows.com/docs#supplier-deliveries. - Product overview: https://manyrows.com/ - AI agent workflows: https://manyrows.com/ai-agents - Product tour: https://manyrows.com/tour - Robotics PLM: https://manyrows.com/robotics and https://manyrows.com/ko/robotics (robot BOMs, installed serial components, firmware compatibility, independent unit/component hours, replacement comparison, commissioning inspections and pilot quality holds; 17 record types, 252 optional fictional examples, two commissioning inspection plans) - Formula One inspired racing template: https://manyrows.com/templates/formula-one (fictional two-car workflow, 91-second recording, 23 record types, 591 optional examples; internal review and evidence, with human sporting decisions) - Product modelling: https://manyrows.com/features/data-model - Features: https://manyrows.com/features - Controlled documents and files: https://manyrows.com/features/assets - Revision and configuration release: https://manyrows.com/features/release-control - Team reviews and agent activity: https://manyrows.com/features/collaboration - Pricing and trial: https://manyrows.com/pricing - About: https://manyrows.com/about - Contact: https://manyrows.com/contact Industry pages cover fashion and apparel, footwear, outdoor and sports, home décor and furniture, food and beverage, grocery retail, cosmetics and personal care, consumer electronics, retail, OEM and ODM manufacturing, consumer packaged goods, and robotics. These are example workflows, not a limit on supported industries. The industry overview at https://manyrows.com/industries and https://manyrows.com/ko/industries lists these workflows with illustrative record types. Individual industry workflow pages are in English. ## Canonical API resources - Human reference: https://manyrows.com/docs - Evidence and organization wallet publishing: https://manyrows.com/docs#evidence-packages - OpenAPI 3.0.3 contract (public, no authentication): https://dash.manyrows.com/openapi.yaml - API base URL: https://dash.manyrows.com/x/{workspaceId}/api/v1/projects/{projectId}/data - Hosted MCP server: https://dash.manyrows.com/x/{workspaceId}/api/v1/projects/{projectId}/mcp ## Authentication Send an API key using `X-API-Key: ` or `Authorization: Bearer `. Obtain workspace/project UUIDs and the key from the ManyRows dashboard. Never put a key in a URL, prompt, browser client, source file, or log. OAuth-capable MCP clients may instead connect to the project MCP URL and follow authorization discovery, browser sign-in, and consent (authorization code with PKCE S256). Scopes are `project:data:read`, `project:data:write`, and `project:schema:manage` (schema management also requires write scope). Access is bounded by the selected project, consent, current member permissions, and workspace delegation policy. OAuth tokens work only at the selected MCP endpoint, not the REST Data API. Revoke grants from Connected agents in your profile. Delegated agents do not gain human approval authority. ## MCP tool contract Verifiable evidence packages: open Evidence in the project sidebar. Human project administrators can capture private quality, historical release-certificate and configuration-release packages before wallet or network setup. A workspace owner saves the organization's Algorand public address in Workspace settings → Organization publisher, or Publisher setup on Evidence. We recommend Pera Wallet. The organization approves each publication and pays its network fee. ManyRows never requests or stores wallet private keys or recovery phrases. The deployment selects the network; the UI has no network selector. Evidence reads are available through REST and MCP: GET /quality-audit-packages?scope=project lists all kinds with complete project field visibility; omit scope for quality only. GET /release-evidence-packages requires revisionId, and GET /configuration-evidence-packages requires configurationReleaseId. List tool names are get_quality_audit_packages, get_release_evidence_packages and get_configuration_evidence_packages. Package metadata, /download, /integrity-receipt, confirmed /receipt and /events use the corresponding package resource. GET /evidence-events lists project lifecycle activity including removed packages. API keys and delegated agents cannot configure publishers, create packages, sign, reconcile, close or remove them; evidence writes are human_only and omitted from executable MCP tools. Evidence bytes stay private; only a salted commitment, publisher address and transaction metadata appear on Algorand. Verify ZIPs and receipts locally at https://dash.manyrows.com/verify-evidence without an account, wallet or file upload. Local integrity does not prove issuer identity or chain inclusion; optional online verification needs independently trusted publisher information and ledger endpoints for the receipt's network. Proof does not establish physical truth or current certification. Assigned package publishers and issued transaction identities survive workspace address changes; retries never issue automatic replacements. See https://manyrows.com/docs#evidence-packages. For AI-assisted schema design, connect the project through hosted MCP instead of copying a static prompt/specification. In the dashboard use Schema → Connect AI, then authenticate through OAuth or a dedicated API key with Schema management. The agent should inspect capabilities and current types, call `POST /schema/validate`, present the plan, and wait for confirmation before `POST /schema/import`. Never paste an API key into a prompt. Recall response cases use `/recall-cases`, `/recall-cases/candidates`, `/recall-cases/{recallCaseId}`, and `/recall-cases/{recallCaseId}/events` (five operations, all generated as MCP tools; https://manyrows.com/docs#recall-response). Creation freezes the source plus primary-plane ancestors and creates containment/recovery actions per lot. Traces include archived/draft records regardless of effectivity, exclude deleted/staged records, and explicitly warn about missing planes, detected cycles and limits (20 levels, 200 lots, 2,000 scanned connections; 10-second trace timeout). They never prove full distribution or physical recovery. Scope refresh adds work and never removes prior lots; the lifetime union is capped at 200 lots, rejecting an oversized refresh atomically. Owners may manually add lots with evidence, reassign pending actions or reopen completed actions. Only assigned action owners prepare/complete work; reviewers cannot. All work must be complete before the case owner submits evidence and a coverage assessment in the note. Independent member review closes or requests changes; owner cancellation is terminal, not recovery verification. API keys may own work as `apikey:UUID`; delegated OAuth MCP can act for the assigned member with live write access and consent, preserving attribution. Queue summaries are capped at 100; hasMore indicates partial scope. Full detail preserves original trace, retained lots and ordered history after ordinary source deletion, not document bytes. No stock, shipment, NCR, release or notification side effects. Each event needs UUID, current version, kind, note and only applicable optional fields; retry uncertain results unchanged and refresh after 409 conflicts. Controlled concessions use `/concessions`, `/concessions/candidates`, `/concessions/{concessionId}`, and `/concessions/{concessionId}/events` (five GET/POST operations, all generated as MCP tools; https://manyrows.com/docs#controlled-concessions). Immutable item revision, lot, whole-unit allowance, expiry and conditions are independently reviewed. Only the owner records evidence-backed usage; only the independent assigned member reviewer approves or withdraws. API keys may own requests as `apikey:`; delegated OAuth MCP may act for the assigned member with live write permission and consent. Usage cannot exceed remaining quantity or be newly recorded after expiry, even when backdated. Usage references are unique per concession forever, including voided entries. Voiding corrects a recording error, not a physical return; it preserves history and cannot reactivate expiry or withdrawal. Limits are per concession, not a global lot allocation. This does not alter NCR dispositions, inventory, inspections, releases or external customer approval. Retry unchanged uncertain commands with the original UUID, body and version; refresh after conflicts. First-article approval packages are available through `/first-articles`, `/first-articles/candidates`, `/first-articles/{packageId}`, `/first-articles/{packageId}/checks`, and `/first-articles/{packageId}/events` (six GET/POST operations; see https://manyrows.com/docs#first-article-approval). They freeze revision-matching inspections and measurements for explicit supplier/sample-lot evidence coverage. Attach requires a supporting record and lot-applicability attestation; the physical lot claim is not automatically proven. Only the assigned owner prepares/submits; independent member review may be delegated through OAuth MCP with write consent. API keys may own work as `apikey:`, never impersonate the reviewer. Requests for more evidence preserve prior submissions and clear current coverage. Approval does not release production, qualify the supplier, complete supplier-change requirements or certify PPAP compliance. Every command needs its own UUID and current version; unchanged uncertain retries keep the same ID/body/version. All six routes generate MCP tools and appear in capability discovery according to credential access. Agent-callable external Data API operations generate tools; `tools/list` returns the catalog filtered by this connection's access mode. Operations marked `x-manyrows-agent-restriction: human_only` or `retired` remain in OpenAPI but are omitted from executable MCP tools. The canonical OpenAPI contract also retains dashboard-only reference paths marked `x-manyrows-external: false`; they are excluded from external REST integrations and the MCP tool catalog. `GET /capabilities` is `get_capabilities`; `GET /entities/{id}` is `get_entities_by_id`; `PATCH /entities/{id}` is `patch_entities_by_id`. Use the actual returned input schema. Arguments group URL parameters as `path`, query parameters as `query`, declared headers as `headers`, and the payload as `body`. Credentials go on the connection, not in tool arguments. Read-only keys receive only read-safe tools, including `POST /requirements/query` for material-plan queries. For project-level triage, use read-safe typed `GET /project-home/attention` (`get_project_home_attention`) instead of polling each operational register. Permission-restricted sections are omitted, not reported as zero. The optional certificateRenewals section includes default 30-day recorded-scope attention and each status count. If `partial` is true, treat every name in `failedSections` as unknown and retry before concluding that its queue is clear. Material planning distinguishes projections from commitments. `POST /requirements/query` calculates a 1–50-order plan without reserving supply; `POST /material-plan-runs` requires write access and atomically saves the projection plus its stock and purchase-supply reservations. API-key calls scope saved runs to the exact credential rather than its display name, while its creating member retains ownership. Release reservations idempotently through `POST /material-plan-runs/{runId}/release`; released plans remain history and cannot be handed to dashboard RFQ creation. Material stock is unit-specific and optimistic-versioned; reconciliation atomically version-checks 1–200 unique positions and records reasoned before/after evidence. Results return `{status, headers, body}` as structured content and JSON text; header values are arrays of strings. HTTP errors set MCP `isError`. Batch operations can return HTTP 200 with rejected or rolled-back items: inspect `applied`, `failed`, and each item outcome even when `isError` is false. Retain ETags for `If-Match`/`If-None-Match`; pass an `Idempotency-Key` in `headers` for mutating POST retries. Upload bodies use `fileBase64`, `fileName`, and optional `mediaType`; decoded images are limited to 20 MiB, other files to 10 MiB, and the complete base64 MCP request to 30 MiB. CSV bodies are JSON strings. Supply `contentType` when the tool schema offers multiple media types. Coverage refers to the external Data API. Dashboard administration, supplier sourcing/cost/pricing, rework and scrap execution, permanent deletion, release decisions, and human approvals have separate authority boundaries. Supplier change notices are available through `/supplier-changes` and generated MCP tools: they expose evidence metadata, not prices. An API-key agent may own work as its returned `apikey:UUID` principal; independent review requires the assigned member, directly or through delegated OAuth. Delegates retain their underlying member identity for independence and their client attribution in history. Other shared quality transitions may still reject an agent with `human_approval_required`; hand those decisions to the assigned human. A listed tool never bypasses workflow or permission checks. ## Agent operating rules 1. Connect directly to the hosted MCP server, or fetch the canonical OpenAPI contract before generating REST calls. 2. Start with `GET /agent-guide` (`get_agent_guide`) for project identity, effective access, task entry points and human handoffs. Call `GET /capabilities` for hard limits, semantics and detailed workflow links. Cache its ETag and use `If-None-Match` to cheaply revalidate it. 3. Discover type and field keys with `GET /types`; do not guess schema identifiers. 4. Prefer `PUT /entities/by-reference/{type}/{referenceId}` for retry-safe synchronization. 5. Read a record's `ETag` and send `If-Match` on updates that must not overwrite concurrent changes. 6. Use `POST /entities/validate` for a non-persisting validation pass. 7. Follow `nextCursor` (also returned as `X-Next-Cursor`) until absent when enumerating query results. Counted queries also return `X-Total-Count`. 8. For durable incremental work, poll `GET /changes`, deduplicate by change `id`, and persist `nextCursor` only after processing its page. The feed covers `record`, `schema`, `catalog`, and `configuration` resources and contains identity signals rather than changed values; read each `refreshHref` for current authorized state. Configuration definitions outside the portable schema are available from `GET /configuration/export`. Keys with `schemaManage` may atomically upsert supported definitions through `POST /configuration/validate` followed by `POST /configuration/import`; `delete: true` is the explicit deletion path and its plan reports dependency impact. Channels remain read-only. A `410 change_cursor_expired` requires both snapshot refreshes plus a full record resync. 9. Branch on HTTP status and the response's stable `error` code, not its advisory `message`. 10. Treat schemas as strict: do not send undeclared body properties, trailing JSON values, malformed flags, or query parameters absent from an operation's contract. 11. Honor `Retry-After` and the standard `RateLimit-*` headers on 429. Give every mutating POST a fresh `Idempotency-Key`; reuse it only for the identical method, path, query, media type, precondition headers, and body. Completed responses replay for 24 hours. On `409 error.idempotencyInProgress`, retry the unchanged request after `Retry-After`; if it persists, contact support with the key and `X-Request-Id` for outcome reconciliation. A processing reservation does not expire automatically, and a new key could duplicate the command. Send `Prefer: return=minimal` when a successful write body is unnecessary. 12. Cache schema exports, type discovery, single-record reads, and empty change-feed polls with their `ETag`; send `If-None-Match` and handle `304` on later full reads. 13. Use `POST /entities/by-references` for ordered batch lookup by business key and `POST /entities/bulk-validate` to validate up to 200 records without persistence. Use `POST /entities/bulk-upsert` to synchronize up to 200 mixed-type full records by stable `(type, referenceId)` keys; prefer per-item `ifMatch`, preview first, and choose atomic (default) or best-effort semantics explicitly. Use `POST /entities/bulk-update` for heterogeneous partial PATCHes. New upserts honor draft-on-create; activate up to 200 draft roots with ETag-guarded `POST /entities/bulk-activate`, which deduplicates subordinate closures and routes governed closures into human-approved change requests. Governed live updates return `cr_required`; stage those through `POST /change-requests/bulk-update`. Submit up to 200 resulting drafts with `POST /change-requests/bulk-submit`, selecting ordered ids or a whole package, and preview before committing. Clean abandoned automation drafts with the draft-only `POST /change-requests/bulk-abandon`; it accepts ordered ids or a package, preserves live records, and returns item-level missing, lifecycle, and authorship failures. Poll exact lifecycle, approval progress, package readiness, and terminal decisions with the read-safe `POST /change-requests/by-ids`. Approval and package release remain human-only. 14. Schema export is available to every key. For a key with explicit `schemaManage`, use `POST /schema/validate` then `POST /schema/import` for atomic additive definitions. To evolve existing definitions, use `POST /schema/migrations/validate`, review changes/impact/errors/blocked items, then send its ETag in `If-Match` on `POST /schema/migrations/apply`. Safe metadata/invariant changes apply atomically; key/type/target/delete changes are blocked. Deprecated definitions remain addressable for compatibility. 15. To edit one BOM transactionally, read `GET /entities/{id}/structure`, retain its ETag, then call `POST /entities/{id}/composition/lines/bulk` with 1-200 ordered add/update/move/delete operations. Use `preview:true` first, target new children by id or `(type, referenceId)`, send the structure ETag in `If-Match`, and require `applied:true` plus `failed:0`; any item failure rolls the whole batch back. 16. To ingest a complete quality result atomically, read `GET /entities/{id}/characteristics`, retain its specification ETag, then call `POST /entities/{id}/checks/ingest` with the explicit verdict, ordered measurements, and optional rejected-round disposition. Preview first, send the specification ETag in `If-Match`, and require `applied:true`; any invalid step rolls the round back. Tolerance results summarize evidence but never derive the verdict. 17. To reconcile an ordered collection without coordinating individual adds, removals, and moves, read `GET /entities/{id}/collections/{fieldKey}/members`, retain its full-collection ETag, then call `PUT` on the same path with the complete desired `members` list (up to 200). For up to 200 collections across heterogeneous records and fields, use `POST /entities/bulk-sync-collections` with a required per-item collection `ifMatch`; target by id or stable `(type, referenceId)`, preview first, and choose atomic (default) or best-effort explicitly. Existing values retain stable member IDs; require `applied:true` when committing and inspect each added/removed/moved/unchanged summary. 18. To ingest sample actuals atomically, read `GET /entities/{id}/size-spec`, retain its definition ETag, then call `POST /entities/{id}/size-spec/actuals/ingest` with 1-200 unique POM names and finite values (`null` clears one). Preview first, send the ETag in `If-Match`, and inspect each target/deviation/status/action plus `missingPomNames`; the whole run commits or rolls back together. Actuals do not change the definition ETag, but concurrent chart edits do. 19. To reconcile a Time & Action calendar atomically, read `GET /entities/{id}/ta-schedule`, retain its ETag, then call `PUT /entities/{id}/ta-milestones/sync` with the complete desired ordered `milestones` list (up to 200; `[]` clears it). Match existing rows by id or exact unique name, keep names unique and at most 200 characters, and include every named predecessor. Preview first, inspect the would-add/update/remove/move outcomes and resolved schedule, then apply against the unchanged baseline ETag. Writes require a configured schedule; archived, frozen, and working-copy records are refused, and assigned owners must be current workspace members. 20. To replace an order's size split atomically, read `GET /entities/{id}/size-curve`, retain its ETag and ordered `sizes`, then call `PUT` on the same path with the complete `quantities` map (up to 200; `{}` clears it). Preview first, inspect per-size previous/current/delta/actions and total changes, then apply against the unchanged baseline ETag. A configured total field syncs atomically only for ungoverned orders; `totalSynced:false` means leave that governed field to a change request. 21. Before planning work across several records, use the read-safe `POST /entities/operational-snapshots` with 1-100 unique id-or-reference targets and an explicit unique `sections` list; duplicate aliases fail in place as `duplicate_target`. It resolves record, categories, collections, structure, rollups, requirements, sizeSpec, sizeCurve, taSchedule, quality, releaseReadiness, and configurationReadiness data in one repeatable-read transaction. On later polls, put prior ETags in each target's `ifNoneMatch` object keyed by section; a match returns `notModified:true` without the section data. The `categories` section returns applicable trees, current assignments, and the ETag accepted by `POST /entities/bulk-sync-categories`. For `collections`, omit `collectionFields` to discover all readable collections or select up to 50 field keys/IDs; retain each complete ordered member list and per-field ETag as direct input to `POST /entities/bulk-sync-collections`. Preserve ordered target outcomes and inspect collection succeeded/failed counts: any requested field failure makes that target `partial`. 22. For heterogeneous classification, cache `GET /catalogs` and the portable `GET /catalogs/by-key/{key}/categories` with their ETags; both catalog metadata and trees also have local-ID routes, and `GET /catalogs/by-key/{key}/categories/by-code/{code}` refreshes one node plus its rollup count without local IDs. Then read each record's `GET /entities/{id}/categories` ETag (reuse any with `If-None-Match`; category-tree ETags also change with assignment rollup counts). Call `POST /entities/bulk-sync-categories` with up to 200 records and 200 total assignments. Target records by id or `(type, referenceId)`, catalogs by key/ID, and categories by ID, unique code, or exact name path; `category:null` clears. Preview first, choose atomic or best-effort, inspect assigned/cleared/unchanged actions, and use an idempotency key when applying. 23. For duplicate cleanup, call the read-safe `POST /entities/duplicate-candidates` for explainable scored pairs, then `POST /entities/merge` with `preview:true`. Resolve every reported field/category conflict, retain both record ETags and `planEtag`, and apply the identical plan with `preview:false`, both record `*IfMatch` values, `planIfMatch`, and an idempotency key. Never work around a merge blocker: governed/frozen records and referrers, unsafe BOM ownership/cycles, cardinality collisions, and graph collisions require their dedicated workflow first. A successful merge archives a recoverable source tombstone pointing at the survivor. 24. Before migrations, releases, or autonomous cleanup, call the read-safe `POST /integrity/scan`. Page by record subject until `complete:true`; empty finding pages can still carry `nextCursor`. Stable codes diagnose missing required values, non-live references, BOM cycles/malformed lines, one-to-many violations, effectivity/classification drift, missing governed revisions, and staging inconsistencies. Honor severity and ETag-bearing repair guidance; the scan itself never changes data. 25. API keys may propose governed changes but cannot approve or reject them. Permanent deletion, destructive schema edits, cost/pricing, release decisions, and webhook administration remain dashboard operations. ## Product release decision briefs Use `GET /entities/{id}/release-brief` (`get_entities_by_id_release_brief`) after resolving the product record. The read-only brief uses a repeatable-read snapshot and existing release rules. It reports `blocked`, `ready_for_human_certification`, `certified`, or `not_applicable`, with the exact revision, required controlled documents, inspection evidence, source links and next actions. Approval and product certification remain human-only. Some other workflow events support delegated member actions under their own authority rules. Inspect `coverage`: restricted, partial, unavailable or unevaluated evidence must never be treated as a complete dossier. Arrays are capped at 100 and visible totals/returned counts disclose truncation. Current inspections are not reconstructed as historical certificate evidence; a certificate with no document evidence is explicitly marked unavailable. The certificateCoverage summary identifies its policy, counts, completeness and basis (current_snapshot or certification_snapshot); follow its exact policy source and release readiness for record-level pins. This decision concerns a product revision, not assembly configuration, as-built status or shipment eligibility. The ETag versions the brief; `readinessVersion` is the separate release-readiness token. Refresh before acting. The guide and brief expose typed MCP output schemas inside the existing status/headers/body envelope. Controlled-document text: `GET /entities/{id}/document-text` reads one exact document revision (use the document entity ID, not its File ID). Optional `q` is a case-insensitive fragment up to 200 characters; omit it to traverse nonblank lines. `limit` defaults to 20, range 1–20. Check `status` before citing `passages`; `ready` results carry locations and citations tied to document/file SHA-256, with PDF page/line or plain-text line numbers. Each line is a bounded 500-character snippet, not full raw content. `total` counts all matching lines; `truncated` means more remain. Pass `nextCursor` as URL-encoded `cursor` with the same document and query until absent. A changed file returns `409 stale_cursor`; discard the cursor and restart. Invalid/mismatched cursors return 400; every request rechecks field permissions (403 on denial). HTTP 200 can contain an explicit unavailable/unsupported/extraction status and no passages. Scanned PDFs have no OCR fallback. See https://manyrows.com/docs#controlled-documents and the canonical OpenAPI schema for all statuses. For CAD BOM interchange, `POST /entities/import-bom` accepts normalized root-first JSON/CSV with explicit part numbers and at most 2,000 rows (CSV: 8 MiB, subject to stricter upstream limits). Use JSON `dryRun:true` or CSV `?type=part&dryRun=true` to validate in a rolled-back transaction; write permission is required. Quantities are plain decimal strings without units, grouping, or exponents. CSV rows must match header width. Nonempty JSON `fields` maps, duplicate parent-component pairs, and ambiguous existing lines are rejected. Existing parts and additional line attributes are preserved; absent lines are not deleted. A concurrent line edit can return `409 import_conflict`: preview again and retry. Native CAD files and custom property mapping are not supported by this endpoint. CAD document storage: `POST /assets/files` accepts allowlisted native CAD and exchange extensions as opaque attachments (10 MiB per file), preserving bytes and SHA-256. Bind the descriptor through normal File fields; upload alone creates no record. See the Assets section in `/docs` for the exact extension list. Use ZIP for dependent assemblies or numbered filenames such as `.prt.1`. Uploading does not extract geometry, properties, or BOMs, and does not establish a live CAD connection. CAD snapshots: `POST /cad/snapshots/preview` accepts the version-1 counted engineering-BOM graph documented in `/docs` (2 MiB, 2,000 components, 10,000 usages, 1,999 distinct parent-component pairs). CAD preview, import and binding commands require UTF-8 JSON with unique object keys and exact field casing; malformed Unicode and duplicate keys return 400 invalid_json. Identities are preserved without text replacement or normalization; Unicode control characters are rejected. It requires write permission and rolls back records, proposed bindings, audit, and events. Use explicit source/version/configuration identity, complete:true, configured component IDs, explicit part numbers, and positive integer quantities with unit `each`. Shared definitions appear once; repeated usages aggregate exactly. Review proposed parts/lines and `resolutions`, then send `{snapshot, snapshotSha256, expectedImportId, expectedBindingsSha256}` to `POST /cad/snapshots/import` to commit the BOM, bindings, and receipt atomically. Copy expectedImportId from preview.sourceState.importId (none before the first receipt); missing returns 428 cad_preview_required, competing advancement returns 409 cad_source_changed. Matching is source_binding_then_part_number; renamed source components keep their bound target. sourceBindingsPersisted is false in preview and true after a new applied import. The snapshot fingerprint protects the normalized source payload. New applications must also copy preview.bindingsSha256 into expectedBindingsSha256; missing returns 428 cad_preview_required, and changed bindings or resolved part-number target identities for snapshot components return 409 cad_bindings_changed under the same lock used by binding mutations. The guard also detects create/match changes, replacement records and renamed bound targets. It also detects creation, deletion, replacement or edits of incoming BOM lines, including quantities and extra fields, regardless of which stream edited them. Existing line updates use the checked version; edits or deletions detected after line lookup return 409 import_conflict and roll back the entire preview/import. Preview again before retrying. Preview lines include optional previousQuantity: the exact stored quantity before writes, omitted for new lines or unset values. Zero is preserved as a string; stored quantities may be fractional. The dialog shows current and proposed quantities side by side. It distinguishes new lines, changed quantities and unchanged quantities using exact decimal comparison. Hide unchanged quantities filters the review table only; the complete snapshot is still submitted, and refreshing the preview resets the filter. Equal quantities do not imply a no-op import: existing lines remain update operations and source metadata may be recorded. retainedLineCount reports existing nondeleted lines outside change requests, directly under matched snapshot components, that are absent from incoming update targets. It includes matched leaves, excludes descendants of omitted components, and is measured before writes. Those lines remain unchanged; the dialog warns when the count is positive. retainedLines contains up to 200 line details ordered by entity ID, with entityId, parentReferenceId, childReferenceId and optional exact-string quantity. Compare length with retainedLineCount for truncation; larger lists are explicitly marked and can be inspected in Compositions. Details are informational, outside bindingsSha256, and omitted on replay. This informational count is outside bindingsSha256 and omitted on replay. In the CAD import dialog, Refresh preview reuses the selected file and resets assembly confirmation. The selected file is cleared when the dialog closes or its target changes. Lines outside the incoming graph, part attribute values and schema configuration are not covered. CAD and ordinary BOM previews/imports share the project composition lock with BOM-editor and bulk composition operations for graph reads, cycle checks and writes. Direct entity writes do not all acquire that lock; line-version checks remain necessary. Fingerprints are opaque; refresh older previews before applying. Current identical retries remain no-ops despite mapping changes and do not require the binding fingerprint; replayed responses omit bindingsSha256. Previously superseded versions fail with cad_source_replay; changing content for an accepted version fails with cad_source_version_conflict. The current identical version returns replayed:true, applied:false with empty operations and no writes, preserving later manual edits. Entity-scoped retries verify the originally imported target; older receipts without a target ID use the original cad_snapshot_imported audit event, matching receipt ID, version and snapshot hash. A different or unverifiable target returns 409 cad_replay_root_mismatch. Current mappings cannot prove an older import target. GET /cad/snapshots/state reports the accepted receipt per source/root stream. Receipts do not guard manual edits, other streams, or schema changes, and cannot recognize a previously unseen older vendor version. Verify upstream chronology. Missing/non-live bound targets are conflicts, never part-number fallback. Use `POST /cad/bindings` for explicit mappings, scoped `GET /cad/bindings` for discovery, and `DELETE /cad/bindings/{id}` for deliberate removal; binding changes are audited and conflicting mappings are refused. Source metadata may be repaired on approval-governed types without changing the BOM, while frozen targets and targets covered by pending change requests remain blocked. The CAD tab confirms removals; deleting a mapping preserves the BOM and accepted receipt. Check `GET /entities/{id}/cad/change-request` before offering an import; it returns `{changeRequest: null}` or `{id, title, status, cadProposal}` for a draft/open request covering this record, including ordinary change requests. The CAD tab links to the request and hides Add CAD source until it is decided or discarded. Returning to the tab rechecks pending state before enabling import. Refresh on the pending banner or source list reloads the state without closing the record. Discover mappings for a record with `GET /entities/{id}/cad-bindings` or CAD tab. No source scope is required; the project-scoped read returns `{bindings, hasMore, nextOffset}` ordered by binding ID, with limit 1–200 (default 50) and offset 0–1,000,000. Missing/deleted records return 404. Paging is live; refresh starts from the first page. Each mapping offers Show assembly import receipt, using `/cad/snapshots/state` with the source component as rootId. It shows the accepted version, time, receipt ID and snapshot hash, with on-demand refresh. No root receipt does not mean a component was never imported inside another assembly. Receipts belong to source streams and do not follow later mapping changes or manual target edits. These mappings do not imply a live connection or current CAD revision. The entity CAD tab sits after Compositions for composition-enabled types outside working copies. Use the adjacent CAD and Compositions tabs for source review and the BOM. Successful imports refresh source details and BOM data. Read-only, frozen, archived and draft records cannot import. Approval-required types offer Add CAD source → Create change request → Review change request: submit through the usual approval workflow. File attachments stay in Documents. Add CAD source opens guided setup for Onshape, Inventor or Fusion, with prerequisites, exporter downloads and the target type key. Existing snapshot files can be selected directly. Try a sample assembly previews a three-component example using the selected record in both direct and approval workflows; it requires BOM configuration and preview permission, saves nothing, and cannot be applied from the dialog. Other CAD programs have no ready-to-run exporter here yet. Approval-required records use POST /entities/{id}/cad/preview (snapshot body) and POST /entities/{id}/cad/propose (snapshot plus snapshotSha256, expectedImportId and expectedBindingsSha256). Propose returns staged:true, applied:false, changeRequestId and workingCopyId. Live BOM, mappings and the accepted receipt change only at approval, atomically. The root must match this record; existing parent assemblies must be in its working-copy tree. Existing pending requests conflict. Preview and proposal creation also check every existing matched leaf for freezes, pending requests and source-mapping conflicts before creating a draft. These checks publish no mappings or audit events and are repeated at approval. After a lost proposal response, inspect Changes & releases for the created draft. Changed bindings or source heads reject approval with 409 cad_proposal_changed. Discard/reject publishes no source receipt. Reviewers can edit drafts; source receipts describe provenance, not final BOM equality. Ordinary `/entities/import-bom` does not use or persist source bindings. No hosted vendor connection is implemented. Optional component attributes initialize new parts only. The CAD snapshot import dialog offers an standalone Onshape exporter and setup-guide download (Python 3.10+, no source checkout required; authoritative source: `integrations/onshape/export.py`). It can fetch named-version BOMs through API v17 using request-signature credentials and convert them into snapshot files. The app reads a local capture (up to 16 MiB, never uploaded) to select part-number, name and quantity columns by name; it generates a command with exact column IDs and an explicit quantity basis (per-parent or root-total). The exporter preserves shared definitions and exact counts, and rejects unsupported or ambiguous inputs. Capture and snapshot files are published only after writing completes, without replacing existing files; the output folder must support hard links. Standard content, non-geometric items and mutable workspace references are unsupported. It has synthetic contract tests but no authenticated Onshape runtime validation; do not claim production compatibility or automatic synchronization. An standalone Inventor exporter and setup guide are downloadable from the CAD snapshot import dialog. It requires Windows, running Inventor and the .NET 10 SDK. It reads saved, up-to-date Structured/All Levels BOMs with primary model states and count-based quantities, rejecting merged/promoted rows, enabled occurrence instance properties, overrides, parameter units, iParts/iAssemblies and custom/substitute states. Occurrence-specific row distinctions cannot be preserved by snapshot v1. It verifies the active document path and rechecks source stamps after extraction, without saving CAD documents or changing BOM settings. Source identity includes normalized file path and internal ID; file moves change identity. Synthetic collector and Go normalization tests cover the code, but real Inventor COM runtime validation is outstanding. No Vault connection or background synchronization is implemented. CAD setup readiness: GET /entities/{id}/cad/readiness returns {ready, reason, requiresApproval}. Reasons: empty string, root_unavailable, no_composition, component_type_mismatch. Advisory lifecycle/composition check; it grants no write permission and does not replace preview/apply or pending-request validation. Ungoverned record CAD imports use POST /entities/{id}/cad/import/preview (snapshot) then POST /entities/{id}/cad/import (guarded envelope). Roots must resolve to the selected record (409 cad_root_mismatch); accepted retries verify their original target (409 cad_replay_root_mismatch). Governed records retain entity CAD preview/propose. Global snapshot routes remain for creating assemblies. CAD properties: optional component.attributes maps target field keys to non-null scalar values. Initializes new parts only; matched parts keep existing attributes. Text, long-text, integer, decimal and boolean destinations only; unknown/unsupported/denied fields fail. At most 100 keys per component and 16384 JSON bytes per value within the 2 MiB body limit. Decimal values are strings in destination units; no unit conversion. Values are fingerprinted and follow atomic import or staged approval. Preview shows incoming values and preservation policy. Onshape convert accepts --property-columns JSON mapping field keys to BOM column IDs. Inventor does not yet extract properties; custom adapters can enrich snapshots. Fusion: script and guide downloadable from CAD import dialog, maintained in integrations/fusion. Runs inside Fusion on saved, fully processed, unconfigured local-component designs. Counts immediate-parent placements once per definition, includes hidden components; rejects external/configured/derived occurrences, library fasteners, suppressed timeline features, rolled-back timelines and unsaved edits. Optional assigned component material, leaf mass in kg, description and custom API attribute mappings initialize new parts. Component material is not an inference over body overrides. Persistent component IDs are scoped to the saved document. Component-tree adapter only; arbitrary manufacturing BOM rules are unsupported. Synthetic tests exist; real Fusion runtime validation is outstanding. Mapped integer properties are limited to -9007199254740991 through 9007199254740991 so browser review and apply preserve exact values. Larger or fractional values require a decimal field and a JSON string. Property string escaping and whitespace are canonicalized before fingerprinting. CAD integrations feature overview: https://manyrows.com/features/cad — local Onshape, Inventor, Fusion and SOLIDWORKS exporters, reviewed snapshot imports, assembly scoping, source mappings and import receipts, and approval-required BOM changes. No live sync, hosted CAD connection or native CAD viewer. Runtime validation in the CAD applications remains pending. CAD mapping setup: GET /cad/property-fields?type=KEY returns {fields:[{key,name,type}]} excluding denied fields and unsupported types. UI selects target fields, local Onshape capture columns or named Fusion properties, with explicit unit checks. Download a mapping file for Fusion or Onshape convert --property-map-file (64 KiB and 100 fields; duplicate keys rejected). Import validates again. SOLIDWORKS exporter: Windows, SOLIDWORKS 2019+, .NET 10; saved resolved counted component trees, explicit part-number properties, source fingerprints, no overwrites. Rejects unsupported states/exclusions/quantity units/unloaded children/inactive configurations. Drawing table overrides and cut-list expansion unsupported. Path/configuration identity changes on file moves; real vendor runtime validation pending. CAD error guidance identifies indexed source components and usage endpoints from the submitted snapshot. Attribute-binding errors include the component part number and field. The UI explains how to correct properties, quantities and duplicate identities, or refresh a stale preview. Repeat CAD imports: Update from CAD opens an existing source mapping and verifies source system/document/configuration/root before preview. Exporter settings can be remembered in browser-local storage, scoped to account, project, type and source/root. No credentials or captured model data are stored; local file paths and shell preferences do not sync. Save setup for project explicitly shares reusable options and property mappings for an existing binding. Shared options override local reusable options; unit confirmations must be repeated. Restored mappings recheck fields and require numeric unit confirmations again. Disable remembering or use Forget saved settings to remove the local setup. Backend target/approval/stale checks remain authoritative. CAD import history: GET /cad/snapshots/history requires type/system/documentId/configuration/rootId, with limit 1–50 (default 20), offset 0–1000000. Returns imports/hasMore/nextOffset, newest first. GET /cad/snapshots/history/{id} compares source part identities/part numbers and exact per-parent quantity strings against the previous accepted graph; first import compares with empty. Older receipts without graphs return available=false. Graphs omit mapped property values. These are CAD source differences, not applied BOM differences or manual/draft edits; omitted source lines remain in the BOM. Previews and identical retries add no history; governed imports record history only at approval. Shared exporter setup: GET /cad/bindings/{id}/settings returns revision/settings/redacted (initially 0/null/false). PUT replaces with {expectedRevision, settings:{program,command,properties}}, max 64 KiB strict JSON. Program must match source. Command accepts Onshape part/name/quantity column IDs and basis, Inventor namespace, SOLIDWORKS namespace/property, or empty Fusion command. Property rows have field/source, and group/name only for Fusion custom. Paths, shell preferences, column labels, credentials and unit confirmations are not shared. Restricted mappings are redacted on read and block replacement. Writes enforce project permission and metadata lifecycle restrictions. Stale revisions return 409 cad_settings_changed; reload and review. Removing the binding removes shared setup. Retained-line review is paginated in the CAD dialog. All three preview routes accept retainedAfter (previous retainedNextCursor UUID) and retainedLimit 1–200 (default 200). Resubmit the same snapshot while retainedHasMore is true. Retained rows remain informational, outside the apply fingerprint; paging reads live BOM state. Direct CAD delivery: the CAD dialog provides a downloadable Python 3.10+ sender with check/send/export-send commands. Onshape/Inventor/SOLIDWORKS can export and send in one local command; Fusion saves inside CAD then sends the saved file locally. No browser file selection is needed. Keys stay in a hidden prompt or environment (MANYROWS_API_KEY), never URLs or shared setup. HTTPS except loopback; redirects refused; TLS verified; transient failures retry at most three times. A failed/uncertain delivery is retried with send and the same file. GET /entities/{id}/cad/connection returns ready/reason/writable/requiresApproval/type/referenceId/entityId/maxSnapshotBytes/maxPending. Advisory target checks, not CAD installation validation. POST /entities/{id}/cad/submissions takes strict snapshot JSON <=2 MiB (normalized JSON leaves 1024 bytes for apply metadata), validates through a rolled-back importer, and queues it without changing BOM/bindings/accepted receipts or creating a change request. Limit 20 pending per entity, 409 cad_queue_full. Deduplicates normalized content per target atomically; returns {submission,created}, 201 new or restored after proposal rejection/abandonment, 200 existing. Pending/imported/proposed/dismissed retries return the same receipt. Rejected/abandoned proposals can be sent again with the same saved snapshot after fresh validation, restoring the pending payload under the same receipt ID. Dismissed receipts stay closed. Receiving/dismissal writes metadata-only attributed audit events. GET /entities/{id}/cad/submissions lists metadata newest-first (limit 1–50/default20, offset 0–1000000), returning submissions/hasMore/nextOffset. Status is pending/imported/proposed/dismissed/rejected/abandoned; active and rejected proposals may link to a change request. GET /entities/{id}/cad/submissions/{submissionId} returns pending snapshot only after field-access/schema checks. DELETE dismisses pending payload, retaining a receipt; terminal entries are no-ops, 204. Received snapshots in the CAD tab are reviewed through a fresh preview and normal guarded import/proposal. Matching imports/proposals consume the payload atomically; approval marks imported. Rejection marks rejected; deleting the change request marks abandoned and clears its link. Neither action automatically restores the payload. Terminal payloads are removed; receipts remain until type/entity/project deletion. Sending never applies the BOM. Vendor runtimes and upstream chronology remain independently unverified. CAD desktop helper: download both Python helpers and desktop settings from Send to Manyrows. Python with Tk is required. Setup remembers destination/exporter arguments and preserves each export for delivery retries. Optional keyring storage uses macOS Keychain or Windows Credential Manager; keys are never saved in settings. Launch without arguments to reuse the last setup. Onshape captures a named-version BOM from its desktop dialog using session-only vendor keys, then requires column and quantity-basis selection; Fusion exports inside its application. Desktop delivery still requires review and normal approval. CAD desktop package: Send to Manyrows offers one ZIP with the helpers, selected exporter, destination settings, guides and Windows/macOS launchers. Extract before launching. Python 3.10+ with Tk remains required. Named settings replace JSON editing; local checks diagnose source files, .NET SDK and CAD processes. Connection errors explain key/permission problems. Results link to the entity CAD tab. Per-package profiles preserve the retry file, and only matching destination/type/source/program settings are resumed. These checks do not certify vendor compatibility. CAD desktop validation workflow: Windows/macOS UI and launcher tests plus an isolated Windows credential-store test are configured in CI. A workflow definition alone does not establish runtime compatibility. Real vendor CAD and authenticated Onshape tests still require their runtimes/accounts. CAD desktop recovery: exporter exit codes and bounded, credential-redacted output appear in Show error details. Failed exports do not send partial files and restore the previous snapshot selection. Retry saved snapshot checks the file fingerprint and retries the same bytes without exporting. Changing destination/type/file clears the retry action; after restart, Send snapshot can recover the preserved file through server deduplication. Purchase-order register: Costing → Purchasing → Purchase orders keeps search/status/transmission/supplier/member-owner/expected-date controls available during initial loading, empty results and read failures. Filter changes return to page one; Refresh retains all filters/current page and moves to the last available page if the total shrinks. Clear filters resets every filter and page. Search is bounded to 200 characters; invalid bookmarked order/transmission statuses fall back to all. Repeated queries and refreshes hide old rows/counts until current results; obsolete list/detail reads are cancelled and late responses ignored. Account/project changes recheck access before showing names, terms or download actions. HTTP read errors use generic access guidance. Detail paging/retry/refresh hides previous details and current/issued-document downloads until the fresh response. Read-only detail explains current access and offers Refresh to recheck permissions. Detail pauses background list reads; closing it rereads the register. Order cards wrap long names and stack totals/status on phones. Existing write/transmission retry and tab recovery contracts remain unchanged; no new endpoint or snapshot export is added. See https://manyrows.com/docs#purchase-orders. Supplier delivery register: date fields filter promised dates inclusively. Search/status/Clear filters remain available during loading and failed reads. Refresh retains current page, applied dates, search and status, moving to the last available page if results shrink. Clear filters restores all statuses/page one while keeping dates; applying/resetting dates restarts paging and retains search/status. Previous rows/counts stay hidden until current results; repeated queries have independent read attempts, obsolete reads are cancelled and late responses ignored. Invalid bookmarked status falls back to all and search is bounded to 200 characters. Register/detail/order-line/draft-refresh/export HTTP failures use generic access guidance. The table supports horizontal touch/keyboard scrolling with hidden-column hints. Export matching deliveries uses its starting filters; leaving the register, changing account/project or applying/resetting dates cancels further reads and suppresses late downloads. Receipts update linked purchase-order fulfillment; closing a fulfilled order is separate. Starting a return reopens a closed native order. See https://manyrows.com/docs#supplier-deliveries. Shipment receiving: POST /supplier-deliveries/{deliveryId}/events accepts optional dispatchId on receipt/correction; one whole receipt per active shipment, multiple partial receipts up to remaining capacity, receivedOn>=dispatchedOn. Corrections inherit the original frozen binding unless moved with dispatchId or explicitly removed with unlinkDispatch:true (mutually exclusive). All new authenticated receipt/correction/void events, including unassigned receiving, require current project data read/write, cost access, writable credentials and stable principal; delegated callers need both scopes. New unassigned events bind the stable caller identity; legacy empty-principal receipts remain unchanged without backfill. New201, exact UUID/body/principal replay200 after later changes/renames, changedreuse409, capacity/inactive/date refusal422 without committing. Shipment corrections retain rootId, cannot shrink below linked physical receipts or move dispatch after receipt; effective linked receipts prevent shipment void. Erroneous receipt void releases capacity; rejection/returns do not undo physical arrival. Unassigned/legacy receipts stay unassigned; overdue means awaiting a linked receipt, so check unassigned arrivals. Receipt history/CSV and explicit sample-review receipt proof freeze dispatch/carrier/tracking at receiving while current progress refreshes. Authenticated-app receipt/correction/void retries persist the exact UUID/body before sending in an account/project/delivery-scoped durable browser store, require matching UUID plus boolean replay confirmation, and survive closing tabs in the same browser. Receiving recovery never auto-sends; it migrates existing tab receipt commands only after a durable commit, checks current read access before revealing saved inputs, and explicitly retries with current server authorization. Uncertain original outcomes stay recoverable through generic 400/401/403/404/409/412/422 without dismissal. Only receiving-endpoint 409 receipt_stale/receipt_limit/return_changed or 422 dispatch_changed proves no matching receipt existed before refusal. Recorded proof permits dismissal after a fresh delivery read at the click; legacy rejection flags without proof remain recoverable, and retry removes dismissal before HTTP. Atomic storage prevents another tab replacing an unresolved delivery command. Clearing/eviction of browser data removes recovery. Supplier return and purchase-order commands also have durable recovery; ordinary delivery creation/amendments/cancellations also have durable browser recovery; awarded RFQ handoff and other purchasing commands retain tab recovery. No automatic sample receipt, review, inventory or quality completion. See https://manyrows.com/docs#supplier-deliveries. Supplier returns and replacements: GET /supplier-returns filters deliveryId, q (200 characters) and status before total/pagination; omit status for all cases, use unresolved for the app default. limit defaults to 50, clamped to 200; offset is nonnegative. GET /supplier-returns/{returnId} reads complete append-only history. Typed MCP get_supplier_returns/get_supplier_returns_by_returnid expose the same public contract. POST /supplier-returns (MCP post_supplier_returns) reserves an effective receipt quantity using id, deliveryId, receiptId, quantity, reason, owner and optional ncrId. POST /supplier-returns/{returnId}/events (MCP post_supplier_returns_by_returnid_events) records authorize/ship/replace/void/cancel/close using id, current version and note plus action-specific terms. Current project data-read and cost access apply to reads; writes also require data-write, writable credentials and a stable account/key/delegated-grant-plus-account identity; delegated callers need both scopes. New201 and exact UUID/body/principal replay200 return matching id plus boolean replayed, before owner membership/current head/lifecycle checks. Owner departure, caller renames and later events do not duplicate evidence or change original attribution. New creation stores the original request before owner normalization; legacy creations keep their body hash and frozen owner normalization, legacy events remain body-only, no principal backfill. 409 return_command_conflict means changed UUID/body/principal reuse: preserve any uncertain original. 409 return_changed or return_history_limit proves no commit; refresh and review before a new UUID/current version. Strict bodies/queries, private/no-store; private replay metadata is never returned. Original physical receipts remain intact; returns reduce accepted fulfillment and effective replacements restore it with their actual timing. A new return reopens a closed native purchase order with attributed history. No automatic inventory/accounting/quality completion. See https://manyrows.com/docs#supplier-returns. Supplier returns register: search/status controls remain available during loading and failed reads. Filter/page changes and Refresh hide previous rows/counts until the current response, abort superseded reads and ignore late results. All discovers closed cases even with no unresolved returns. Clear filters restores unresolved cases on page one; Refresh retains filters/page and moves to the last available page if results shrink. Invalid bookmarked status falls back to unresolved; search is bounded to 200 characters. The table scrolls horizontally with touch or keyboard while keeping readable columns. Export matching returns uses its starting filters; leaving the register or switching account/project cancels further pagination and suppresses late downloads. See https://manyrows.com/docs#supplier-returns. Supplier return recovery: authenticated-app creation and every return lifecycle command persist exact UUID/body/version before HTTP in account/project/return-scoped IndexedDB. Closing tabs retains recovery in the same browser; reopening never auto-sends. Existing tab commands migrate only after durable commit. Current read access is checked before exposing saved terms; denied reads or server retry errors show generic recovery copy. Explicit Retry saved return change checks current write authorization. Unknown/missing confirmation, generic 400/404/422, 408/429, server failures and access or ambiguous command/principal conflicts retain recovery without dismissal. Only 409 return_changed/return_history_limit proves no matching receipt existed before refusal. Recorded proof permits dismissal after a fresh return read at the click; legacy rejection flags without proof remain recoverable; retry first removes dismissal, and atomic compare/write/cleanup plus browser locks when available block competing tab overwrites or queued retries. A definite entry refusal keeps the authored draft for reviewed refresh and a fresh UUID, while storage failure before HTTP leaves it editable. Clearing/eviction of browser data removes local recovery; cross-device/offline submission is not provided. See https://manyrows.com/docs#supplier-returns. Purchase order command recovery: authenticated-app creation, PUT edits/amendments and POST lifecycle events (issue/send_amendment/acknowledge/close/cancel) persist the complete UUID/body before sending in an account/project/order-scoped durable browser store. Closed tabs retain recovery in the same browser; reopening never auto-sends. Existing tab commands migrate only after durable commit. Current project/order read access must be confirmed before exposing saved commercial inputs; explicit Retry saved order change uses current server authorization. Original UUID, version, lines/decimal quantities/prices, dates, terms and evidence are reused exactly. Only matching response id plus boolean replayed retires recovery and opens current order. New receipts bind the original typed request to stable signed-in account ID, API key ID, or delegated grant plus account ID. Exact UUID/body/principal receipts replay before current owner assignment/defaulting and version/lifecycle checks, including after assigned-owner departure, later changes and caller email/key/client-name changes; original owner choice and attribution remain frozen. Changing the submitted owner or other terms conflicts even if it normalizes to the stored owner. A different identity with the same display name/email cannot replay. Legacy receipts retain stored request-hash rules without automatic principal backfill; legacy owner normalization uses recorded immutable before/after/issued-document evidence when available, preserving hashes and history. Current project data read/write, cost access, writable credentials and stable caller identity remain required on every retry; delegated callers need both data scopes. Credential project restrictions apply to reads and writes, and read-only/currently non-writable reads report canWrite:false. New commands still validate a current member owner. Actor/principal/hash request properties are forbidden and replay metadata is private. Purchase-order creation, edit and lifecycle MCP tools expose typed command-ID/replayed confirmations for successful writes and exact replays. An uncertain original remains recoverable through 400/401/403/404/409/412/422, without dismissal, because validation/access or generic purchase_order_changed conflicts do not disprove an earlier commit. HTTP409 purchase_order_stale means no receipt was found and current version/lifecycle/allocation refused the command; restored recovery can then be reviewed and dismissed after a fresh authorized order read at the click. Retrying resets dismissal before sending. Fresh definite refusals release editable drafts; stale edit/event refusals require refresh with authored inputs preserved. Atomic storage prevents replacing an unresolved request for the same order; supported browser locks refuse concurrent retries without queuing a send. Storage failure blocks new requests. Browser clearing/eviction removes recovery; other orders remain independent. Email transmission retries remain separate. See https://manyrows.com/docs#purchase-orders. Delivery commercial recovery: authenticated-app POST /supplier-deliveries creation, dashboard-only POST /cost-rfqs/{rfqId}/delivery-commitment handoff and POST /supplier-deliveries/{deliveryId}/events amend/cancel persist complete UUID/body in account/project/delivery-scoped IndexedDB before HTTP and survive closing all tabs in the same browser. RFQ handoff also retains its original source RFQ. Existing tab requests migrate only after durable commit. Never auto-send. Fresh current delivery read, or source RFQ read for handoff, hides saved terms when unavailable; explicit Retry saved delivery change still enforces current server write authorization. Matching UUID and boolean replay confirmation retire only the exact request and open the delivery. Atomic compare/save/retire and available browser locks refuse competing unresolved changes or simultaneous retries. Uncertain 400/401/403/404/409/412/422/network results retain the original without dismissal. Only409 delivery_stale proves a missing receipt followed by current state/native allocation refusal; dismissal rechecks current read access, and retry first removes proof. New creation/amend/cancel receipts bind stable account/API-key ID or delegated grant plus account ID, preserve attribution through visible renames and reject different identities. Creation binds the original typed request before owner defaulting; exact replay precedes current owner membership/lifecycle/allocation. New creation requires a current member owner. Legacy creations keep existing hashes and frozen owner normalization; legacy events remain body-hash based, without identity backfill. Ordinary reads require current data-read/cost access and credential project restrictions/scopes; writes need data-read/write, cost, writable credentials and stable identity, with both delegated scopes. canWrite reflects current permission. Typed post_supplier_deliveries and post_supplier_deliveries_by_deliveryid_events output command UUID and boolean replayed for fresh201/replay200; private metadata stays private. Browser clearing/eviction removes local recovery; no cross-device recovery. See https://manyrows.com/docs#supplier-deliveries. Awarded RFQ delivery handoff recovery: dashboard-only POST /cost-rfqs/{rfqId}/delivery-commitment is durable across closed tabs in the same browser/account/project; no external REST/MCP tool. Original source RFQ and submitted UUID/body are immutable. Current data-read/write and cost access, writable credentials, stable identity, credential project restrictions and both delegated scopes apply before every replay. New receipts bind the source RFQ and original typed request to account ID, API key ID or delegated grant plus account ID. Exact replay precedes current owner defaulting/membership, RFQ award derivation and native order allocation, preserving original supplier/item/title/quantity/owner/attribution after owner departure, caller renames or later RFQ changes. New handoffs still need a current award and member owner. Legacy receipts compare their unchanged hashes using frozen creation fields and owner normalization without identity backfill. Reopening never auto-sends. Fresh source RFQ read hides saved inputs when denied; retry errors are generic. Require matching UUID plus boolean replayed before retirement/navigation. Generic 400/404/409/422 or incomplete confirmation retains the exact original; only recorded409 delivery_stale proof permits dismissal after a fresh source read. Legacy rejected flags without proof remain recoverable; migration preserves proof but cannot overwrite a newer durable attempt. Atomic storage refuses a fresh delivery UUID for the same RFQ while another handoff remains unresolved, including across tabs. A proven live-form refusal requires fresh RFQ/allocation review before a new UUID, retaining authored delivery terms. Account/project changes stop recovery and late navigation. Storage cleanup failure after confirmed HTTP retains the request with uncertainty copy, never a false no-send claim. See https://manyrows.com/docs#supplier-deliveries. Formula batch costing: record Cost tab → Cost scenarios → Compare assumptions → New scenario. Explicit root Primary/Co-Product/By-Product outputs enable batch authoring; CPG starter optional role/yield/basis fields leave existing ingredient recipes unchanged. Enter positive batch quantity in parent basis units, review all current output lines, and allocate exactly 100% cost shares (zero allowed). Variable inputs scale, root Fixed inputs apply once, waste increases consumption, and labor/overhead/flat extras remain per basis unit; percentage extras use batch FOB. Actual converted batch consumption selects volume-price tiers. When currency conversion applies, foreign-currency tiers retain flat source pricing; reporting-currency tiers apply normally. Outputs are terminal and never consumed. Expected output = nominal line quantity × batch quantity × yield. Baseline/scenario share quantity and allocation, while baseline retains recorded yield and scenario may override it. Yields are greater than zero and at most one; unset means one. Rounded cents reconcile using largest remainders and line-UUID ties; unit estimates round to 12 places. Missing prices remain incomplete. Limits: quantities up to 1e9/12 fractional places, 50 root outputs, 10,000 formula lines, 50 levels, nonnegative landed cost up to 1e12. Refuse automatic expansion of nested outputs/fixed stages, truncation, incompatible explicit pricing units, single selling price/order quantity and replacements. No automatic allocation/by-product credits. Preview version binds save; immutable history retains raw-input/revision freshness and captured field permissions. Revise/refresh rereads current output identities and requires new shares for new outputs. CSV includes basis/outputs/yields/allocations/all ingredients/totals. Dashboard-only, cost-read/field permissions; no new REST/MCP operation, inventory/production/order write or regulatory/label computation. See https://manyrows.com/docs#formula-batch-costing. Production-stage costing: dashboard Cost scenarios component change → Saved batch output → Formula type → Upstream formula → Saved batch evaluation → Consumed output line. New downstream batches first preview their explicit quantity and output shares to load consumed input choices; select stage outputs and preview the changed prices afterward. Author only formulaId/scenarioId/lineId under materials[].batchOutput, mutually exclusive with entered unitCost/sourceId. The output must produce the exact active leaf or purchased input; expanded assemblies cannot be directly repriced. Source is the saved scenario column, current/fully costed with explicit currency, same project, live formula and explicit supported compatible output/pricing units. An incomplete source baseline is allowed if its scenario prices all inputs. Same reporting currency only; no inferred cross-stage FX. Enable conversion for differing explicit downstream consumption units. Server uses exact allocatedCost/expectedQuantity through compatible conversion, downstream quantities, assembly multiplication and waste before monetary rounding; unit estimates are 12-place strings. Zero allocation is a real zero price. Baseline retains live pricing. Each stage retains explicit reviewed batch quantity, shares and yields; consumption is proportional, without whole-batch rounding, scheduling or stock reservations. Bounds: eight upstream stages, 25 distinct saved evaluations, no formula revisits, nonnegative consumption up to 1e9, waste 0–1000%, nonnegative landed cost up to 1e12. One consistent database snapshot and evaluation clock check every source recursively. Source edits, changed ancestors or deletion require upstream refresh/save and explicit downstream selection of a new evaluation; preview version binds saving. Reload stage rechecks reads; denied, stale and incomplete sources hide figures and block authoring. Immutable downstream history preserves source labels, identities, versions, basis, expected quantities, allocation, shares, yields and unit estimates after edits/deletion; current/captured source field permissions protect previews/headlines/history/deletion, including transitive ancestors even when source records or saved rows are removed. Frozen stageSources[].formulaTypeIds retain producing types for current configuration permission checks after formula deletion. CSV preserves source decimal evidence and identities. No live item-price, inventory, order or production write, external REST/MCP operation, automatic optimization, regulatory computation or label generation. See https://manyrows.com/docs#production-stage-costing. Market constituent checks: dashboard Material composition → Market constituent checks. Schema management plus data-write permission defines team-owned rule sets with command id, stable key, name, market, edition, authority, reference, targetTypeIds and limits[{name,maxPercent}]. Use 1–50 same-project types and 1–50 unique canonical constituent names. Maxima are explicit decimal strings 0–100 with up to 12 fractional places; zero requires absence and comparison is inclusive. New versions require previousVersionId equal to the latest head; commands are immutable, scoped to a stable authenticated principal and exact normalized body. No supplied country rule data or automatic approval of rule content. Choose current live composition (current effectivity lens) or the latest approval-bound revision (frozen composition only). Complete mass composition is required; incomplete/unsupported inputs stay unknown. Exact percentExact rational strings in newly captured composition summaries drive comparisons; rounded display equality does not imply a pass. Older snapshots without exact evidence stay unknown for present constituents. A complete composition can prove absence at zero. Record only a reviewed latest approved revision of an active unfrozen live record using command id, revisionId and ruleVersionId plus its exact quoted SHA-256 If-Match; no authored status, observed percentage or composition. Missing validator 428, changed preview 412, changed revision/rule head or reused command identity 409. Saved checks preserve gap and unknown outcomes as well as pass, rule edition/source/authority, approved composition and exact ratios; subsequent rules/material edits do not rewrite history, and a newer target revision is flagged. Exact retries return the original receipt after head changes but require current access; altered validator/body/principal conflicts. Keep the dialog open for an uncertain retry: pending commands are scoped to the open dialog/record context, not durable across closing or navigation. Check recorded history before a new assessment request and reload the catalog before a new rule request. Current configuration and all captured input-field permissions protect previews and the entire history/counts, including off-page entries; fresh denial hides figures/export, and late responses cannot populate a changed context. Catalog/history default 50/max 200 with offset, dashboard UI pages 50. Rule catalog defaults latest heads; exact key selects immutable editions. CSV preserves IDs, source, edition, exact percentage ratio, display estimate, status and reason. Private/no-store dashboard paths are /market-rule-sets, /market-rule-sets/{versionId}, /entities/{id}/market-assessment and /entities/{id}/market-assessments; excluded from external REST and MCP. A passing configured-limit check does not authorize release or calculate nutrition/allergens/labels. See https://manyrows.com/docs#market-constituent-checks. Quantity-basis portability: schema/export and schema/import preserve optional basisField on primary structures and secondary planes as the junction select field key for Fixed/Variable quantities. The CPG starter maps its optional quantityBasis field; omitted values in existing examples remain Variable and ordinary costs remain available. Import stays additive/create-only for existing structure owners, so reapplying a starter does not repair an old project; configure its quantity-basis field explicitly in the dashboard. The export authoring spec documents basisField.