{"id":"ops/managed-linked-art-pilot-runbook","relativePath":"ops/managed-linked-art-pilot-runbook.md","title":"Managed Linked Art Pilot Runbook","markdown":"# Managed Linked Art Pilot Runbook\n\nThis runbook covers the first concierge paid pilots for the \"Managed Linked Art Launch Pilot\" offer. It is an operator checklist for onboarding one collection export into a hosted Meta Museum workspace without waiting for self-serve signup or automated billing.\n\n## Scope\n\nUse this runbook when a prospect has agreed to a bounded pilot conversation and a human operator is preparing a workspace, entitlement record, support path, and monthly evidence packet.\n\nThe pilot covers:\n\n- one customer organization\n- one source data export or one bounded source API\n- one hosted workspace namespace\n- one public or review-only collection slice\n- one monthly evidence packet\n- manual invoice-backed entitlement tracking\n\nThe pilot does not cover:\n\n- self-serve signup\n- automated billing\n- custom feature development\n- bulk migration guarantees\n- publication without human approval\n\n## Buyer And Commercial Readiness Packet\n\nUse these artifacts as one controlled sequence:\n\n1. `/museum-pilot-discovery-call-guide.html` qualifies a specific problem and reviewer.\n2. `/managed-linked-art-pilot-brief.html` explains the bounded offer.\n3. `/museum-pilot-data-request-template.html` requests a public source sample.\n4. `/museum-linked-art-pilot-demonstration.html` shows the four-step review path.\n5. `/museum-pilot-pricing-options.html` states the current unvalidated pricing hypothesis.\n6. `/museum-pilot-sample-agreement.html` supplies counsel-review scope language.\n7. `/museum-pilot-results-report-template.html` records observed delivery results and acceptance.\n8. [`paid-pilot-commercial-evidence-process.md`](paid-pilot-commercial-evidence-process.md) records invoice-through-margin proof.\n9. [`../sales/museum-outreach-pipeline.md`](../sales/museum-outreach-pipeline.md) records sent outreach, follow-up drafts, and unsent research prospects.\n\nDo not interpret a completed template as signed scope, a listed price as validated\ndemand, or a prepared follow-up as sent evidence.\n\n## Commercial Readiness Gate\n\nThe public `/pilot` page must stay explicit about the pre-revenue state until\nreal commercial evidence exists:\n\n- paid pilots: `0`\n- billing path: manual invoice-backed entitlement only\n- in-app billing: not built\n- next revenue evidence: first signed pilot with invoice reference, active\n  entitlement, source data received, and seven-day activation evidence\n\nDo not treat a researched account, warm conversation, demo, or internal dataset\nas revenue evidence. A pilot becomes commercial evidence only after all of the\nfollowing are true:\n\n1. Signed scope or written approval names the customer organization, price,\n   publication boundary, workspace owner, and customer review owner.\n2. A real manual invoice reference exists and is recorded in the pilot\n   entitlement. Demo, fixture, internal, placeholder, sample, smoke, or test\n   invoice references do not count as commercial evidence.\n3. The entitlement is active, exact-scoped by `tenantId` or `orgId`, and\n   exportable through managed storage.\n4. Source data has been received for the named tenant.\n5. The activation ledger has dated customer evidence, not demo or smoke data.\n\nOnly after at least one invoice-referenced pilot reaches first value should the\nroadmap consider checkout, subscription webhooks, pricing pages, or self-serve\nplan changes.\n\n## Buyer Onboarding Pack\n\nBefore turning a signed pilot into launch evidence, generate the buyer-specific\ncapture pack:\n\n```powershell\npnpm pilot:buyer-pack -- --account <real-account-id> --tenant <tenant-id> --organization \"<buyer organization>\" --invoice-ref <real-invoice-ref> --owner \"<operator owner>\"\n```\n\nFor web forms or first-touch enquiries where pricing would be premature, generate\na form-safe draft that keeps pricing and invoice language out of the outbound\nmessage body while preserving private evidence fields in the response template:\n\n```powershell\npnpm pilot:buyer-pack -- --account <real-account-id> --tenant <tenant-id> --organization \"<buyer organization>\" --invoice-ref <real-invoice-ref> --owner \"<operator owner>\" --submission-mode=form --omit-pricing\n```\n\nThe command writes:\n\n- `artifacts/pilot-evidence/pilot-buyer-onboarding-pack-latest.json`\n- `artifacts/pilot-evidence/pilot-buyer-onboarding-pack-latest.md`\n- `artifacts/pilot-evidence/runs/pilot-buyer-onboarding-pack-<timestamp>.json`\n\nThe pack is `needs-buyer-evidence` until the operator supplies a real account,\ntenant, buyer organization, owner, and invoice reference. It rejects\ndemo/fixture/local/placeholder/sample/smoke/test-looking account, tenant, and\ninvoice values unless explicitly run as a placeholder rehearsal, and placeholder\nrehearsals do not count as external pilot evidence. A `ready-to-send` pack is\nstill only an operator handoff; the 10/10 gate clears only after the real\nentitlement, outreach, activation, support, KPI, retention, gross-margin, and\npacket artifacts pass. Until then, the buyer pack is not strict paid-pilot\nproof.\n\n## SaaS Packaging Gate\n\nUse `pnpm pilot:packaging` before promising that the concierge path is\nsupportable as SaaS packaging. The command reads the managed\n`pilot-entitlements.json` ledger and writes:\n\n- `artifacts/pilot-packaging/pilot-packaging-latest.json`\n- `artifacts/pilot-packaging/pilot-packaging-<timestamp>.json`\n\nDefault concierge check:\n\n```powershell\npnpm pilot:packaging\npnpm pilot:packaging:check\n```\n\nRepeatable SaaS check:\n\n```powershell\npnpm pilot:packaging -- --target=repeatable-saas --check\n```\n\nPackaging rules:\n\n- Manual invoice billing is supportable only for bounded concierge load: 1-3\n  active pilots with invoice-backed entitlements, workspace owner, review owner,\n  publication boundary, and monthly evidence cadence.\n- Subscription billing is required when active concierge pilots exceed the\n  support limit or when the target is repeatable SaaS.\n- Repeatable SaaS remains blocked until subscription checkout, webhook\n  entitlement sync, customer billing portal, and plan-change audit evidence are\n  implemented and configured.\n- Do not mark an institution plan as available from commercial plan metadata\n  alone; the `institution` tier is package intent until billing and onboarding\n  workflows are executable.\n\n## Workspace Setup\n\n1. Assign an owner and reviewer.\n   - Operator: Sun & Rain Works pilot owner.\n   - Customer: one named collection-side review owner.\n2. Create the pilot namespace:\n   - `pilot-{org_slug}-{YYYYMM}`\n   - Example: `pilot-benton-202606`\n3. Create the source dataset namespace:\n   - `pilot/{org_slug}/{source_slug}/v1`\n   - Example: `pilot/benton/collection-export/v1`\n4. Record publication boundary:\n   - public slice allowed\n   - review-only slice allowed\n   - internal-only records excluded from public projection\n5. Confirm source data minimums:\n   - stable identifiers\n   - titles or display labels\n   - dates or timespan notes\n   - makers or creator notes when available\n   - rights text or rights review status\n   - image references when available\n6. Run import, validation, and review smoke checks against the pilot dataset.\n7. Capture first-value proof:\n   - searchable records\n   - at least one reviewed public or review-only collection slice\n   - one record detail page\n   - one Linked Art JSON response\n   - one unresolved-risk list\n\n## Tenant Namespace Convention\n\nUntil every route and persisted store propagates tenant context, every pilot artifact must include an explicit namespace string so it can be separated later without guessing from file paths or record labels.\n\nRequired namespace fields:\n\n- `tenantId`: `pilot-{org_slug}-{YYYYMM}`\n- `sourceNamespace`: `pilot/{org_slug}/{source_slug}/v1`\n- `plan`: `pilot`\n- `billingMode`: `manual_invoice`\n- `publicationMode`: `review_only`, `public_slice`, or `mixed`\n\nDo not infer tenant identity from a URL, display label, or provider name. The namespace must be explicit in operator notes, entitlement records, evidence packets, and any pilot-specific storage export.\n\nService-level scoped storage now exists for records, manual jobs, and persisted AgentTask review artifacts through `orgId`/`tenantId` options. Tenant-tagged records, jobs, and AgentTask route callers now pass the exact tenant ID into their scoped backing stores. Operators should still record the namespace explicitly and avoid mixing real pilot data in remaining shared routes until activity, annotation, audit, export, and backup evidence paths are covered.\n\n## Manual Plan Entitlement\n\nCreate a manual entitlement record before onboarding data. `src/services/pilot-entitlements.ts` is the executable contract for the interim plan gates, namespace shape, manual invoice fields, durable ledger storage, exact tenant lookup, and validation rules until a first-class entitlement table exists. The entitlement validator rejects synthetic invoice references that tokenize as demo, fixture, internal, placeholder, sample, smoke, or test evidence.\n\nThe durable interim ledger is `storage/pilot-entitlements.json`. It is registered as a managed storage document, so `pnpm storage:export:postgres` exports it with the other storage-of-record JSON documents during Postgres cutover.\n\n```json\n{\n  \"tenantId\": \"pilot-benton-202606\",\n  \"organizationName\": \"Benton Museum of Art at Pomona College\",\n  \"organizationSlug\": \"benton\",\n  \"sourceNamespace\": \"pilot/benton/collection-export/v1\",\n  \"plan\": \"pilot\",\n  \"workspaceOwner\": \"operator-name\",\n  \"reviewOwner\": \"customer-name\",\n  \"publicationBoundary\": \"Public browse slice after rights review; sensitive records held.\",\n  \"evidencePacketCadence\": \"monthly\",\n  \"effectiveFrom\": \"2026-06-14\",\n  \"billing\": {\n    \"invoiceMode\": \"manual\",\n    \"invoiceReference\": \"INV-2026-001\"\n  },\n  \"status\": \"active-pilot\",\n  \"planLimits\": {\n    \"importsPerMonth\": 3,\n    \"aiCallsPerMonth\": 250,\n    \"storageGb\": 25,\n    \"users\": 5,\n    \"exportsPerMonth\": 4,\n    \"apiRateLimitPerMinute\": 120\n  }\n}\n```\n\nOperator rules:\n\n- Do not enable production publication until publication boundary and review owner are recorded.\n- Do not exceed the `pilot` plan gates without written scope approval.\n- Do not promise self-serve billing, automated entitlements, or custom integrations during this pilot.\n- Do not search by loose organization slug when checking access; read by exact `tenantId`.\n- Do not run tenant-tagged imports from a public role. Provider import paths are generated from the capability registry and require `researcher` or higher for both direct legacy and `/api/providers/{provider}/import` facade routes.\n- Run `pnpm test -- tests/services/pilot-entitlements.test.ts` after changing plan IDs, gates, namespace rules, or manual invoice evidence.\n- Run `node --import tsx --test tests/services/org-storage-isolation.test.ts` after changing records, jobs, AgentTask artifact persistence, or scoped storage path rules.\n\n## Outreach Evidence\n\nRecord real outreach status with `pnpm pilot:outreach` instead of changing the static offer page by hand. The command writes to managed `pilot-outreach-events.json`, validates the account id against the named `/pilot` outreach queue, and rejects incomplete or out-of-sequence stage evidence before changing the ledger.\n\n```powershell\npnpm pilot:outreach --account=benton-museum-of-art-at-pomona-college --stage=sent --occurred-at=2026-06-19T16:00:00Z --owner=\"operator-name\" --evidence=channel=email --evidence=messageRef=outreach/benton/2026-06-19 --evidence=followUpAt=2026-06-26\n```\n\nUse `pnpm pilot:outreach --summary` before updating buyer-facing notes. Do not claim first outreach has been sent until the `sent` event has `accountId`, `owner`, `channel`, `messageRef`, `sentAt`, and `followUpAt` evidence for one named account. The `followUpAt` date must be on or after `sentAt`, and `replied` evidence requires a prior `sent` event for the same named account with `repliedAt` on or after `sentAt`.\n\n## Pilot Usage Gate\n\nUse `evaluatePilotUsage` for dry-run plan checks, `assertPilotUsageAllowed` for service callers, and `enforcePilotRouteUsageGate` for route handlers before work consumes monthly or per-minute plan capacity. The first enforced dimensions are:\n\n- imports per month\n- AI calls per month\n- storage GB\n- exports per month\n- API requests per minute\n\nRoute-level gates are now wired for:\n\n- `app/api/providers/[provider]/import` through the shared provider facade, counting one import and one API request\n- `app/api/providers/[provider]/profile` and `app/api/providers/[provider]/search` through the shared provider facade, counting one API request\n- `app/api/ai/query`, `app/api/ai/chat`, `app/api/ai/embeddings`, `app/api/ai/visual-similarity`, and `app/api/ai/mapping-assist`, counting one AI call and one API request\n- `app/api/content/generate`, counting one AI call and one API request\n- `app/api/records`, counting tenant-tagged API reads/writes and one export when `?export=1`, `?download=1`, `?format=export`, `?format=jsonl`, `?format=csv`, or `x-metamuseum-export-request: true` is present\n\nPilot automation must send the exact tenant ID. Route gates now derive current usage from `storage/pilot-usage-counters.json` through `src/services/pilot-usage-counters.ts`; that document is registered as managed storage, so `pnpm storage:export:postgres` carries usage counters alongside entitlement records during Postgres cutover.\n\n| Header | Meaning |\n|---|---|\n| `x-metamuseum-tenant-id` | Exact tenant ID, for example `pilot-benton-202606`. |\n| `x-metamuseum-usage-imports-this-month` | Legacy override only: imports already consumed in the current billing month. |\n| `x-metamuseum-usage-ai-calls-this-month` | Legacy override only: AI calls already consumed in the current billing month. |\n| `x-metamuseum-usage-storage-gb-used` | Legacy override only: current tenant storage usage in GB. |\n| `x-metamuseum-usage-exports-this-month` | Legacy override only: exports already consumed in the current billing month. |\n| `x-metamuseum-usage-api-requests-this-minute` | Legacy override only: API calls already consumed in the current rate-limit minute. |\n\nRequests without `x-metamuseum-tenant-id` remain public/evaluation behavior. Tenant-tagged requests require an exact active entitlement, read the current month/minute counter snapshot by exact tenant ID, reject malformed legacy usage snapshot headers when those overrides are present, and return a CORS-preserving `402` response before import, AI, export, or API work runs when the requested usage would exceed the `pilot` plan.\n\nSuccessful tenant-tagged `2xx` responses on those gated shared route paths increment the same counter ledger after route work completes. Denied, malformed, validation-error, and upstream-error responses do not consume quota.\n\nDirect provider-specific routes such as `/api/met/import`, `/api/getty/sparql`, or `/api/rijks/ldes` remain public/evaluation legacy surfaces only when no pilot tenant header is present. `proxy.ts` blocks tenant-tagged direct provider routes with `409` and points supported `profile`, `search`, and `import` operations at `/api/providers/{provider}/{operation}` so pilot usage cannot bypass facade gates and counters before multi-org hosting.\n\nFocused tenant-isolation tests now prove one over-plan pilot tenant cannot deny or mutate another tenant's counter snapshot at the entitlement/counter gate layer, service-level storage tests prove records, manual jobs, and persisted AgentTask artifacts can be isolated under the same storage root by exact org/tenant scope, and route tests prove tenant-tagged records, jobs, and AgentTask history do not bleed into sibling tenants or the unscoped default store. This does not replace the SaaS-2 requirement to propagate tenant identity through the remaining shared route callers or to add isolation coverage for activity metrics, annotations, audit logs, exports, and backup/restore evidence before shared multi-org hosting.\n\n## Seven-Day Activation Checklist\n\nThe pilot reaches first value only when all items below are true within seven calendar days of receiving usable source data:\n\n- workspace namespace assigned\n- manual entitlement recorded\n- source export ingested or staged\n- imported records are searchable\n- one representative record detail page is reviewable\n- Linked Art JSON response is available for at least one record\n- rights/reuse status is visible to the reviewer\n- critical validation issues are listed\n- customer review owner has viewed the workspace or evidence packet\n- next customer decision is recorded\n\n## Usage And Activation Events\n\nTrack these events manually until product analytics is tenant-aware:\n\nThe public `/pilot` activation evidence ledger mirrors these event names, and `src/services/pilot-activation-events.ts` records the same events in managed `pilot-activation-events.json` by exact tenant id. Keep every public milestone at `not_started` until a real tenant has dated evidence; do not mark a milestone complete from a demo, seed fixture, or internal smoke run. Later milestones require prior activation evidence for the same tenant, and every event's evidence `tenantId` must match the top-level tenant id.\n\nUse the operator command to append real tenant evidence instead of hand-editing JSON:\n\n```powershell\npnpm pilot:activation --tenant=pilot-benton-202606 --event=pilot.workspace.created --occurred-at=2026-06-19T12:00:00Z --evidence=workspaceOwner=\"operator-name\" --evidence=createdAt=2026-06-19T12:00:00Z\n```\n\nUse `pnpm pilot:activation --tenant=pilot-benton-202606 --summary` before sending a customer update to confirm the completed milestone count and the next required evidence. The command writes through the same managed storage service, auto-attaches `tenantId` to evidence, and rejects incomplete, tenant-mismatched, or out-of-sequence required fields before changing the ledger.\n\n| Event | Required fields | Why it matters |\n|---|---|---|\n| `pilot.workspace.created` | `tenantId`, `workspaceOwner`, `createdAt` | Starts the seven-day activation clock. |\n| `pilot.source.received` | `tenantId`, `sourceNamespace`, `recordEstimate`, `receivedAt` | Proves data readiness and source scope. |\n| `pilot.records.imported` | `tenantId`, `sourceNamespace`, `recordCount`, `importedAt` | Confirms first ingestion. |\n| `pilot.review.slice_ready` | `tenantId`, `recordCount`, `sliceUrl`, `readyAt` | Confirms first value for reviewers. |\n| `pilot.customer.viewed` | `tenantId`, `reviewOwner`, `viewedAt` | Confirms non-engineer access. |\n| `pilot.evidence.sent` | `tenantId`, `packetPath`, `sentAt` | Confirms recurring evidence delivery. |\n\n## Support Intake\n\nUse one support channel per pilot. Record every issue with:\n\n- `tenantId`\n- requester\n- severity: `blocking`, `high`, `normal`, or `question`\n- record or source reference when relevant\n- decision owner\n- next response date\n- resolution summary\n\nRecord support load with `pnpm pilot:support` instead of keeping issue state in ad hoc notes. The command writes to managed `pilot-support-issues.json`, validates severity/status fields, keeps issues scoped by exact tenant id, rejects response deadlines before `openedAt`, rejects existing issue updates that rewrite the original `requester`, `summary`, `openedAt`, or `severity`, rejects updates to already resolved issues that rewrite `resolvedAt` or `resolutionSummary`, rejects open issues that include resolution evidence, and rejects resolved issues without both `resolvedAt` and `resolutionSummary` or with `resolvedAt` before `openedAt`.\n\n```powershell\npnpm pilot:support --tenant=pilot-benton-202606 --issue=SUP-1 --opened-at=2026-06-20T10:00:00Z --requester=\"customer-name\" --severity=normal --title=\"Question about rights warning wording\" --decision-owner=\"operator-name\" --next-response-at=2026-06-24T18:00:00Z\n```\n\nUse `pnpm pilot:support --tenant=pilot-benton-202606 --summary` before sending customer updates or monthly evidence packets. Support severities are `blocking`, `high`, `normal`, and `question`; support statuses are `open` and `resolved`.\n\nSupport boundaries:\n\n- Blocking import or access issues get a next-business-day response.\n- Mapping, provenance, and rights questions are triaged weekly unless blocking publication.\n- Feature requests are logged as product feedback, not accepted as pilot scope by default.\n\n## KPI Evidence\n\nRecord monthly outcome evidence with `pnpm pilot:kpi` instead of deriving business readiness from usage counters alone. The command writes to managed `pilot-kpi-events.json`, keeps entries scoped by exact tenant id, validates known metric IDs, requires a numeric value, source, evidence reference, and owner, and rejects evidence references that look like demo, fixture, smoke, or sample data.\n\n```powershell\npnpm pilot:kpi --tenant=pilot-benton-202606 --metric=pilot.first_value_days --value=4 --measured-at=2026-06-24T12:00:00Z --source=\"pilot-evidence/benton/activation-ledger\" --evidence-ref=\"artifacts/pilot-evidence/benton-2026-06.json\" --owner=\"operator-name\"\n```\n\nUse `pnpm pilot:kpi --tenant=pilot-benton-202606 --summary` before generating a monthly evidence packet. A ready packet requires one latest entry for each required KPI:\n\n| Metric | Meaning |\n|---|---|\n| `pilot.first_value_days` | Calendar days from usable source receipt to first reviewed value. |\n| `pilot.imported_record_count` | Count of records imported for the pilot tenant. |\n| `pilot.customer_view_count` | Count of customer review views or equivalent named reviewer access events. |\n| `pilot.support_minutes` | Operator support minutes spent during the packet period, including zero when documented. |\n| `pilot.validation_critical_open_count` | Open critical validation issues at packet close. |\n| `pilot.retention_signal_count` | Count of explicit continue, convert, expand-scope, or renewal signals from the customer. |\n| `pilot.gross_margin_percent` | Gross-margin percentage for the pilot period, backed by invoice revenue minus support, infra, and operator cost evidence. |\n\n## Monthly Evidence Packet Template\n\nGenerate the current operator packet with:\n\n```powershell\npnpm pilot:evidence --tenant=pilot-benton-202606 --account=benton-museum-of-art-at-pomona-college --markdown\n```\n\nUse `--check` in closeout, CI, or pre-send review when the packet must be\nready rather than merely generated:\n\n```powershell\npnpm pilot:evidence --tenant=pilot-benton-202606 --account=benton-museum-of-art-at-pomona-college --markdown --check\n```\n\nThe command writes `artifacts/pilot-evidence/pilot-evidence-latest.json`, `artifacts/pilot-evidence/pilot-evidence-latest.md`, and timestamped packet files. The JSON packet is the machine-readable source of truth; the Markdown packet is the customer/buyer-facing summary for email, docs, or procurement review. Each packet includes invoice-backed commercial evidence, support-load counts from `pilot-support-issues.json`, and KPI evidence from `pilot-kpi-events.json`. A packet is `ready` only when the exact tenant has an active manual entitlement with a real invoice reference that is not demo, fixture, internal, placeholder, sample, smoke, or test evidence, at least one named outreach account has a sent/replied event, all activation milestones have dated evidence, support-load evidence is tied to an invoice-backed pilot period with `pilot.support_minutes` recorded, no blocking support issue remains open, no open support issue is past `nextResponseAt`, all required KPI metrics have real tenant evidence, `pilot.retention_signal_count` records a real continue, convert, expand-scope, or renewal signal, and `pilot.gross_margin_percent` records real invoice-minus-cost evidence for the pilot period; otherwise it is `blocked` with explicit open blockers. An empty support ledger before an invoice-backed pilot exists is a pending capture state, not strict support-load proof.\nWith `--check`, a blocked packet exits non-zero while still writing the JSON and\nMarkdown artifacts, so missing real outreach, entitlement, activation, or\nsupport or KPI evidence cannot pass an automated readiness check silently.\n\nEach monthly packet must include:\n\n1. Pilot summary\n   - tenant ID\n   - source namespace\n   - record count\n   - publication mode\n   - current status\n2. Activation status\n   - seven-day checklist result\n   - first-value date\n   - reviewer access status\n3. Data quality\n   - validation summary\n   - critical issues\n   - unresolved mapping questions\n   - enrichment coverage when available\n4. Rights and provenance\n   - rights/reuse status summary\n   - records held for review\n   - provenance risks\n5. Product usage\n   - review sessions or customer views\n   - API/export examples used\n   - AI review runs consumed\n6. Support load\n   - open issues\n   - resolved issues\n   - operator minutes estimate\n7. Next decision\n   - continue pilot\n   - expand source scope\n   - pause\n   - convert to recurring subscription\n\n## Exit Criteria\n\nA pilot can be called successful when:\n\n- first value is reached within seven days\n- customer review owner can inspect records without routine developer help\n- monthly evidence packet is delivered\n- support load is recorded\n- conversion decision is explicit\n\nDo not claim profitable SaaS readiness from this runbook alone. Profitability still needs recurring revenue, support-load evidence, retention, gross-margin, and acquisition-channel proof.\n","sections":[{"level":2,"heading":"Scope","anchor":"scope"},{"level":2,"heading":"Buyer And Commercial Readiness Packet","anchor":"buyer-and-commercial-readiness-packet"},{"level":2,"heading":"Commercial Readiness Gate","anchor":"commercial-readiness-gate"},{"level":2,"heading":"Buyer Onboarding Pack","anchor":"buyer-onboarding-pack"},{"level":2,"heading":"SaaS Packaging Gate","anchor":"saas-packaging-gate"},{"level":2,"heading":"Workspace Setup","anchor":"workspace-setup"},{"level":2,"heading":"Tenant Namespace Convention","anchor":"tenant-namespace-convention"},{"level":2,"heading":"Manual Plan Entitlement","anchor":"manual-plan-entitlement"},{"level":2,"heading":"Outreach Evidence","anchor":"outreach-evidence"},{"level":2,"heading":"Pilot Usage Gate","anchor":"pilot-usage-gate"},{"level":2,"heading":"Seven-Day Activation Checklist","anchor":"seven-day-activation-checklist"},{"level":2,"heading":"Usage And Activation Events","anchor":"usage-and-activation-events"},{"level":2,"heading":"Support Intake","anchor":"support-intake"},{"level":2,"heading":"KPI Evidence","anchor":"kpi-evidence"},{"level":2,"heading":"Monthly Evidence Packet Template","anchor":"monthly-evidence-packet-template"},{"level":2,"heading":"Exit Criteria","anchor":"exit-criteria"}],"html":"<h1 id=\"managed-linked-art-pilot-runbook\">Managed Linked Art Pilot Runbook</h1>\n<p>This runbook covers the first concierge paid pilots for the &quot;Managed Linked Art Launch Pilot&quot; offer. It is an operator checklist for onboarding one collection export into a hosted Meta Museum workspace without waiting for self-serve signup or automated billing.</p>\n<h2 id=\"scope\">Scope</h2>\n<p>Use this runbook when a prospect has agreed to a bounded pilot conversation and a human operator is preparing a workspace, entitlement record, support path, and monthly evidence packet.</p>\n<p>The pilot covers:</p>\n<ul><li>one customer organization</li><li>one source data export or one bounded source API</li><li>one hosted workspace namespace</li><li>one public or review-only collection slice</li><li>one monthly evidence packet</li><li>manual invoice-backed entitlement tracking</li></ul>\n<p>The pilot does not cover:</p>\n<ul><li>self-serve signup</li><li>automated billing</li><li>custom feature development</li><li>bulk migration guarantees</li><li>publication without human approval</li></ul>\n<h2 id=\"buyer-and-commercial-readiness-packet\">Buyer And Commercial Readiness Packet</h2>\n<p>Use these artifacts as one controlled sequence:</p>\n<ol><li>`/museum-pilot-discovery-call-guide.html` qualifies a specific problem and reviewer.</li></ol>\n<ol><li>`/managed-linked-art-pilot-brief.html` explains the bounded offer.</li></ol>\n<ol><li>`/museum-pilot-data-request-template.html` requests a public source sample.</li></ol>\n<ol><li>`/museum-linked-art-pilot-demonstration.html` shows the four-step review path.</li></ol>\n<ol><li>`/museum-pilot-pricing-options.html` states the current unvalidated pricing hypothesis.</li></ol>\n<ol><li>`/museum-pilot-sample-agreement.html` supplies counsel-review scope language.</li></ol>\n<ol><li>`/museum-pilot-results-report-template.html` records observed delivery results and acceptance.</li></ol>\n<ol><li>`paid-pilot-commercial-evidence-process.md`(paid-pilot-commercial-evidence-process.md) records invoice-through-margin proof.</li></ol>\n<ol><li>`../sales/museum-outreach-pipeline.md`(../sales/museum-outreach-pipeline.md) records sent outreach, follow-up drafts, and unsent research prospects.</li></ol>\n<p>Do not interpret a completed template as signed scope, a listed price as validated</p>\n<p>demand, or a prepared follow-up as sent evidence.</p>\n<h2 id=\"commercial-readiness-gate\">Commercial Readiness Gate</h2>\n<p>The public `/pilot` page must stay explicit about the pre-revenue state until</p>\n<p>real commercial evidence exists:</p>\n<p>  entitlement, source data received, and seven-day activation evidence</p>\n<ul><li>paid pilots: `0`</li><li>billing path: manual invoice-backed entitlement only</li><li>in-app billing: not built</li><li>next revenue evidence: first signed pilot with invoice reference, active</li></ul>\n<p>Do not treat a researched account, warm conversation, demo, or internal dataset</p>\n<p>as revenue evidence. A pilot becomes commercial evidence only after all of the</p>\n<p>following are true:</p>\n<ol><li>Signed scope or written approval names the customer organization, price,</li></ol>\n<p>   publication boundary, workspace owner, and customer review owner.</p>\n<ol><li>A real manual invoice reference exists and is recorded in the pilot</li></ol>\n<p>   entitlement. Demo, fixture, internal, placeholder, sample, smoke, or test</p>\n<p>   invoice references do not count as commercial evidence.</p>\n<ol><li>The entitlement is active, exact-scoped by `tenantId` or `orgId`, and</li></ol>\n<p>   exportable through managed storage.</p>\n<ol><li>Source data has been received for the named tenant.</li></ol>\n<ol><li>The activation ledger has dated customer evidence, not demo or smoke data.</li></ol>\n<p>Only after at least one invoice-referenced pilot reaches first value should the</p>\n<p>roadmap consider checkout, subscription webhooks, pricing pages, or self-serve</p>\n<p>plan changes.</p>\n<h2 id=\"buyer-onboarding-pack\">Buyer Onboarding Pack</h2>\n<p>Before turning a signed pilot into launch evidence, generate the buyer-specific</p>\n<p>capture pack:</p>\n<pre><code>\npnpm pilot:buyer-pack -- --account &lt;real-account-id&gt; --tenant &lt;tenant-id&gt; --organization &quot;&lt;buyer organization&gt;&quot; --invoice-ref &lt;real-invoice-ref&gt; --owner &quot;&lt;operator owner&gt;&quot;\n</code></pre>\n<p>For web forms or first-touch enquiries where pricing would be premature, generate</p>\n<p>a form-safe draft that keeps pricing and invoice language out of the outbound</p>\n<p>message body while preserving private evidence fields in the response template:</p>\n<pre><code>\npnpm pilot:buyer-pack -- --account &lt;real-account-id&gt; --tenant &lt;tenant-id&gt; --organization &quot;&lt;buyer organization&gt;&quot; --invoice-ref &lt;real-invoice-ref&gt; --owner &quot;&lt;operator owner&gt;&quot; --submission-mode=form --omit-pricing\n</code></pre>\n<p>The command writes:</p>\n<ul><li>`artifacts/pilot-evidence/pilot-buyer-onboarding-pack-latest.json`</li><li>`artifacts/pilot-evidence/pilot-buyer-onboarding-pack-latest.md`</li><li>`artifacts/pilot-evidence/runs/pilot-buyer-onboarding-pack-&lt;timestamp&gt;.json`</li></ul>\n<p>The pack is `needs-buyer-evidence` until the operator supplies a real account,</p>\n<p>tenant, buyer organization, owner, and invoice reference. It rejects</p>\n<p>demo/fixture/local/placeholder/sample/smoke/test-looking account, tenant, and</p>\n<p>invoice values unless explicitly run as a placeholder rehearsal, and placeholder</p>\n<p>rehearsals do not count as external pilot evidence. A `ready-to-send` pack is</p>\n<p>still only an operator handoff; the 10/10 gate clears only after the real</p>\n<p>entitlement, outreach, activation, support, KPI, retention, gross-margin, and</p>\n<p>packet artifacts pass. Until then, the buyer pack is not strict paid-pilot</p>\n<p>proof.</p>\n<h2 id=\"saas-packaging-gate\">SaaS Packaging Gate</h2>\n<p>Use `pnpm pilot:packaging` before promising that the concierge path is</p>\n<p>supportable as SaaS packaging. The command reads the managed</p>\n<p>`pilot-entitlements.json` ledger and writes:</p>\n<ul><li>`artifacts/pilot-packaging/pilot-packaging-latest.json`</li><li>`artifacts/pilot-packaging/pilot-packaging-&lt;timestamp&gt;.json`</li></ul>\n<p>Default concierge check:</p>\n<pre><code>\npnpm pilot:packaging\npnpm pilot:packaging:check\n</code></pre>\n<p>Repeatable SaaS check:</p>\n<pre><code>\npnpm pilot:packaging -- --target=repeatable-saas --check\n</code></pre>\n<p>Packaging rules:</p>\n<p>  active pilots with invoice-backed entitlements, workspace owner, review owner,</p>\n<p>  publication boundary, and monthly evidence cadence.</p>\n<p>  support limit or when the target is repeatable SaaS.</p>\n<p>  entitlement sync, customer billing portal, and plan-change audit evidence are</p>\n<p>  implemented and configured.</p>\n<p>  alone; the `institution` tier is package intent until billing and onboarding</p>\n<p>  workflows are executable.</p>\n<ul><li>Manual invoice billing is supportable only for bounded concierge load: 1-3</li><li>Subscription billing is required when active concierge pilots exceed the</li><li>Repeatable SaaS remains blocked until subscription checkout, webhook</li><li>Do not mark an institution plan as available from commercial plan metadata</li></ul>\n<h2 id=\"workspace-setup\">Workspace Setup</h2>\n<ol><li>Assign an owner and reviewer.</li></ol>\n<ol><li>Create the pilot namespace:</li></ol>\n<ol><li>Create the source dataset namespace:</li></ol>\n<ol><li>Record publication boundary:</li></ol>\n<ol><li>Confirm source data minimums:</li></ol>\n<ol><li>Run import, validation, and review smoke checks against the pilot dataset.</li></ol>\n<ol><li>Capture first-value proof:</li></ol>\n<ul><li>Operator: Sun &amp; Rain Works pilot owner.</li><li>Customer: one named collection-side review owner.</li><li>`pilot-{org_slug}-{YYYYMM}`</li><li>Example: `pilot-benton-202606`</li><li>`pilot/{org_slug}/{source_slug}/v1`</li><li>Example: `pilot/benton/collection-export/v1`</li><li>public slice allowed</li><li>review-only slice allowed</li><li>internal-only records excluded from public projection</li><li>stable identifiers</li><li>titles or display labels</li><li>dates or timespan notes</li><li>makers or creator notes when available</li><li>rights text or rights review status</li><li>image references when available</li><li>searchable records</li><li>at least one reviewed public or review-only collection slice</li><li>one record detail page</li><li>one Linked Art JSON response</li><li>one unresolved-risk list</li></ul>\n<h2 id=\"tenant-namespace-convention\">Tenant Namespace Convention</h2>\n<p>Until every route and persisted store propagates tenant context, every pilot artifact must include an explicit namespace string so it can be separated later without guessing from file paths or record labels.</p>\n<p>Required namespace fields:</p>\n<ul><li>`tenantId`: `pilot-{org_slug}-{YYYYMM}`</li><li>`sourceNamespace`: `pilot/{org_slug}/{source_slug}/v1`</li><li>`plan`: `pilot`</li><li>`billingMode`: `manual_invoice`</li><li>`publicationMode`: `review_only`, `public_slice`, or `mixed`</li></ul>\n<p>Do not infer tenant identity from a URL, display label, or provider name. The namespace must be explicit in operator notes, entitlement records, evidence packets, and any pilot-specific storage export.</p>\n<p>Service-level scoped storage now exists for records, manual jobs, and persisted AgentTask review artifacts through `orgId`/`tenantId` options. Tenant-tagged records, jobs, and AgentTask route callers now pass the exact tenant ID into their scoped backing stores. Operators should still record the namespace explicitly and avoid mixing real pilot data in remaining shared routes until activity, annotation, audit, export, and backup evidence paths are covered.</p>\n<h2 id=\"manual-plan-entitlement\">Manual Plan Entitlement</h2>\n<p>Create a manual entitlement record before onboarding data. `src/services/pilot-entitlements.ts` is the executable contract for the interim plan gates, namespace shape, manual invoice fields, durable ledger storage, exact tenant lookup, and validation rules until a first-class entitlement table exists. The entitlement validator rejects synthetic invoice references that tokenize as demo, fixture, internal, placeholder, sample, smoke, or test evidence.</p>\n<p>The durable interim ledger is `storage/pilot-entitlements.json`. It is registered as a managed storage document, so `pnpm storage:export:postgres` exports it with the other storage-of-record JSON documents during Postgres cutover.</p>\n<pre><code>\n{\n  &quot;tenantId&quot;: &quot;pilot-benton-202606&quot;,\n  &quot;organizationName&quot;: &quot;Benton Museum of Art at Pomona College&quot;,\n  &quot;organizationSlug&quot;: &quot;benton&quot;,\n  &quot;sourceNamespace&quot;: &quot;pilot/benton/collection-export/v1&quot;,\n  &quot;plan&quot;: &quot;pilot&quot;,\n  &quot;workspaceOwner&quot;: &quot;operator-name&quot;,\n  &quot;reviewOwner&quot;: &quot;customer-name&quot;,\n  &quot;publicationBoundary&quot;: &quot;Public browse slice after rights review; sensitive records held.&quot;,\n  &quot;evidencePacketCadence&quot;: &quot;monthly&quot;,\n  &quot;effectiveFrom&quot;: &quot;2026-06-14&quot;,\n  &quot;billing&quot;: {\n    &quot;invoiceMode&quot;: &quot;manual&quot;,\n    &quot;invoiceReference&quot;: &quot;INV-2026-001&quot;\n  },\n  &quot;status&quot;: &quot;active-pilot&quot;,\n  &quot;planLimits&quot;: {\n    &quot;importsPerMonth&quot;: 3,\n    &quot;aiCallsPerMonth&quot;: 250,\n    &quot;storageGb&quot;: 25,\n    &quot;users&quot;: 5,\n    &quot;exportsPerMonth&quot;: 4,\n    &quot;apiRateLimitPerMinute&quot;: 120\n  }\n}\n</code></pre>\n<p>Operator rules:</p>\n<ul><li>Do not enable production publication until publication boundary and review owner are recorded.</li><li>Do not exceed the `pilot` plan gates without written scope approval.</li><li>Do not promise self-serve billing, automated entitlements, or custom integrations during this pilot.</li><li>Do not search by loose organization slug when checking access; read by exact `tenantId`.</li><li>Do not run tenant-tagged imports from a public role. Provider import paths are generated from the capability registry and require `researcher` or higher for both direct legacy and `/api/providers/{provider}/import` facade routes.</li><li>Run `pnpm test -- tests/services/pilot-entitlements.test.ts` after changing plan IDs, gates, namespace rules, or manual invoice evidence.</li><li>Run `node --import tsx --test tests/services/org-storage-isolation.test.ts` after changing records, jobs, AgentTask artifact persistence, or scoped storage path rules.</li></ul>\n<h2 id=\"outreach-evidence\">Outreach Evidence</h2>\n<p>Record real outreach status with `pnpm pilot:outreach` instead of changing the static offer page by hand. The command writes to managed `pilot-outreach-events.json`, validates the account id against the named `/pilot` outreach queue, and rejects incomplete or out-of-sequence stage evidence before changing the ledger.</p>\n<pre><code>\npnpm pilot:outreach --account=benton-museum-of-art-at-pomona-college --stage=sent --occurred-at=2026-06-19T16:00:00Z --owner=&quot;operator-name&quot; --evidence=channel=email --evidence=messageRef=outreach/benton/2026-06-19 --evidence=followUpAt=2026-06-26\n</code></pre>\n<p>Use `pnpm pilot:outreach --summary` before updating buyer-facing notes. Do not claim first outreach has been sent until the `sent` event has `accountId`, `owner`, `channel`, `messageRef`, `sentAt`, and `followUpAt` evidence for one named account. The `followUpAt` date must be on or after `sentAt`, and `replied` evidence requires a prior `sent` event for the same named account with `repliedAt` on or after `sentAt`.</p>\n<h2 id=\"pilot-usage-gate\">Pilot Usage Gate</h2>\n<p>Use `evaluatePilotUsage` for dry-run plan checks, `assertPilotUsageAllowed` for service callers, and `enforcePilotRouteUsageGate` for route handlers before work consumes monthly or per-minute plan capacity. The first enforced dimensions are:</p>\n<ul><li>imports per month</li><li>AI calls per month</li><li>storage GB</li><li>exports per month</li><li>API requests per minute</li></ul>\n<p>Route-level gates are now wired for:</p>\n<ul><li>`app/api/providers/[provider]/import` through the shared provider facade, counting one import and one API request</li><li>`app/api/providers/[provider]/profile` and `app/api/providers/[provider]/search` through the shared provider facade, counting one API request</li><li>`app/api/ai/query`, `app/api/ai/chat`, `app/api/ai/embeddings`, `app/api/ai/visual-similarity`, and `app/api/ai/mapping-assist`, counting one AI call and one API request</li><li>`app/api/content/generate`, counting one AI call and one API request</li><li>`app/api/records`, counting tenant-tagged API reads/writes and one export when `?export=1`, `?download=1`, `?format=export`, `?format=jsonl`, `?format=csv`, or `x-metamuseum-export-request: true` is present</li></ul>\n<p>Pilot automation must send the exact tenant ID. Route gates now derive current usage from `storage/pilot-usage-counters.json` through `src/services/pilot-usage-counters.ts`; that document is registered as managed storage, so `pnpm storage:export:postgres` carries usage counters alongside entitlement records during Postgres cutover.</p>\n<p>| Header | Meaning |</p>\n<p>|---|---|</p>\n<p>| `x-metamuseum-tenant-id` | Exact tenant ID, for example `pilot-benton-202606`. |</p>\n<p>| `x-metamuseum-usage-imports-this-month` | Legacy override only: imports already consumed in the current billing month. |</p>\n<p>| `x-metamuseum-usage-ai-calls-this-month` | Legacy override only: AI calls already consumed in the current billing month. |</p>\n<p>| `x-metamuseum-usage-storage-gb-used` | Legacy override only: current tenant storage usage in GB. |</p>\n<p>| `x-metamuseum-usage-exports-this-month` | Legacy override only: exports already consumed in the current billing month. |</p>\n<p>| `x-metamuseum-usage-api-requests-this-minute` | Legacy override only: API calls already consumed in the current rate-limit minute. |</p>\n<p>Requests without `x-metamuseum-tenant-id` remain public/evaluation behavior. Tenant-tagged requests require an exact active entitlement, read the current month/minute counter snapshot by exact tenant ID, reject malformed legacy usage snapshot headers when those overrides are present, and return a CORS-preserving `402` response before import, AI, export, or API work runs when the requested usage would exceed the `pilot` plan.</p>\n<p>Successful tenant-tagged `2xx` responses on those gated shared route paths increment the same counter ledger after route work completes. Denied, malformed, validation-error, and upstream-error responses do not consume quota.</p>\n<p>Direct provider-specific routes such as `/api/met/import`, `/api/getty/sparql`, or `/api/rijks/ldes` remain public/evaluation legacy surfaces only when no pilot tenant header is present. `proxy.ts` blocks tenant-tagged direct provider routes with `409` and points supported `profile`, `search`, and `import` operations at `/api/providers/{provider}/{operation}` so pilot usage cannot bypass facade gates and counters before multi-org hosting.</p>\n<p>Focused tenant-isolation tests now prove one over-plan pilot tenant cannot deny or mutate another tenant&#39;s counter snapshot at the entitlement/counter gate layer, service-level storage tests prove records, manual jobs, and persisted AgentTask artifacts can be isolated under the same storage root by exact org/tenant scope, and route tests prove tenant-tagged records, jobs, and AgentTask history do not bleed into sibling tenants or the unscoped default store. This does not replace the SaaS-2 requirement to propagate tenant identity through the remaining shared route callers or to add isolation coverage for activity metrics, annotations, audit logs, exports, and backup/restore evidence before shared multi-org hosting.</p>\n<h2 id=\"seven-day-activation-checklist\">Seven-Day Activation Checklist</h2>\n<p>The pilot reaches first value only when all items below are true within seven calendar days of receiving usable source data:</p>\n<ul><li>workspace namespace assigned</li><li>manual entitlement recorded</li><li>source export ingested or staged</li><li>imported records are searchable</li><li>one representative record detail page is reviewable</li><li>Linked Art JSON response is available for at least one record</li><li>rights/reuse status is visible to the reviewer</li><li>critical validation issues are listed</li><li>customer review owner has viewed the workspace or evidence packet</li><li>next customer decision is recorded</li></ul>\n<h2 id=\"usage-and-activation-events\">Usage And Activation Events</h2>\n<p>Track these events manually until product analytics is tenant-aware:</p>\n<p>The public `/pilot` activation evidence ledger mirrors these event names, and `src/services/pilot-activation-events.ts` records the same events in managed `pilot-activation-events.json` by exact tenant id. Keep every public milestone at `not_started` until a real tenant has dated evidence; do not mark a milestone complete from a demo, seed fixture, or internal smoke run. Later milestones require prior activation evidence for the same tenant, and every event&#39;s evidence `tenantId` must match the top-level tenant id.</p>\n<p>Use the operator command to append real tenant evidence instead of hand-editing JSON:</p>\n<pre><code>\npnpm pilot:activation --tenant=pilot-benton-202606 --event=pilot.workspace.created --occurred-at=2026-06-19T12:00:00Z --evidence=workspaceOwner=&quot;operator-name&quot; --evidence=createdAt=2026-06-19T12:00:00Z\n</code></pre>\n<p>Use `pnpm pilot:activation --tenant=pilot-benton-202606 --summary` before sending a customer update to confirm the completed milestone count and the next required evidence. The command writes through the same managed storage service, auto-attaches `tenantId` to evidence, and rejects incomplete, tenant-mismatched, or out-of-sequence required fields before changing the ledger.</p>\n<p>| Event | Required fields | Why it matters |</p>\n<p>|---|---|---|</p>\n<p>| `pilot.workspace.created` | `tenantId`, `workspaceOwner`, `createdAt` | Starts the seven-day activation clock. |</p>\n<p>| `pilot.source.received` | `tenantId`, `sourceNamespace`, `recordEstimate`, `receivedAt` | Proves data readiness and source scope. |</p>\n<p>| `pilot.records.imported` | `tenantId`, `sourceNamespace`, `recordCount`, `importedAt` | Confirms first ingestion. |</p>\n<p>| `pilot.review.slice_ready` | `tenantId`, `recordCount`, `sliceUrl`, `readyAt` | Confirms first value for reviewers. |</p>\n<p>| `pilot.customer.viewed` | `tenantId`, `reviewOwner`, `viewedAt` | Confirms non-engineer access. |</p>\n<p>| `pilot.evidence.sent` | `tenantId`, `packetPath`, `sentAt` | Confirms recurring evidence delivery. |</p>\n<h2 id=\"support-intake\">Support Intake</h2>\n<p>Use one support channel per pilot. Record every issue with:</p>\n<ul><li>`tenantId`</li><li>requester</li><li>severity: `blocking`, `high`, `normal`, or `question`</li><li>record or source reference when relevant</li><li>decision owner</li><li>next response date</li><li>resolution summary</li></ul>\n<p>Record support load with `pnpm pilot:support` instead of keeping issue state in ad hoc notes. The command writes to managed `pilot-support-issues.json`, validates severity/status fields, keeps issues scoped by exact tenant id, rejects response deadlines before `openedAt`, rejects existing issue updates that rewrite the original `requester`, `summary`, `openedAt`, or `severity`, rejects updates to already resolved issues that rewrite `resolvedAt` or `resolutionSummary`, rejects open issues that include resolution evidence, and rejects resolved issues without both `resolvedAt` and `resolutionSummary` or with `resolvedAt` before `openedAt`.</p>\n<pre><code>\npnpm pilot:support --tenant=pilot-benton-202606 --issue=SUP-1 --opened-at=2026-06-20T10:00:00Z --requester=&quot;customer-name&quot; --severity=normal --title=&quot;Question about rights warning wording&quot; --decision-owner=&quot;operator-name&quot; --next-response-at=2026-06-24T18:00:00Z\n</code></pre>\n<p>Use `pnpm pilot:support --tenant=pilot-benton-202606 --summary` before sending customer updates or monthly evidence packets. Support severities are `blocking`, `high`, `normal`, and `question`; support statuses are `open` and `resolved`.</p>\n<p>Support boundaries:</p>\n<ul><li>Blocking import or access issues get a next-business-day response.</li><li>Mapping, provenance, and rights questions are triaged weekly unless blocking publication.</li><li>Feature requests are logged as product feedback, not accepted as pilot scope by default.</li></ul>\n<h2 id=\"kpi-evidence\">KPI Evidence</h2>\n<p>Record monthly outcome evidence with `pnpm pilot:kpi` instead of deriving business readiness from usage counters alone. The command writes to managed `pilot-kpi-events.json`, keeps entries scoped by exact tenant id, validates known metric IDs, requires a numeric value, source, evidence reference, and owner, and rejects evidence references that look like demo, fixture, smoke, or sample data.</p>\n<pre><code>\npnpm pilot:kpi --tenant=pilot-benton-202606 --metric=pilot.first_value_days --value=4 --measured-at=2026-06-24T12:00:00Z --source=&quot;pilot-evidence/benton/activation-ledger&quot; --evidence-ref=&quot;artifacts/pilot-evidence/benton-2026-06.json&quot; --owner=&quot;operator-name&quot;\n</code></pre>\n<p>Use `pnpm pilot:kpi --tenant=pilot-benton-202606 --summary` before generating a monthly evidence packet. A ready packet requires one latest entry for each required KPI:</p>\n<p>| Metric | Meaning |</p>\n<p>|---|---|</p>\n<p>| `pilot.first_value_days` | Calendar days from usable source receipt to first reviewed value. |</p>\n<p>| `pilot.imported_record_count` | Count of records imported for the pilot tenant. |</p>\n<p>| `pilot.customer_view_count` | Count of customer review views or equivalent named reviewer access events. |</p>\n<p>| `pilot.support_minutes` | Operator support minutes spent during the packet period, including zero when documented. |</p>\n<p>| `pilot.validation_critical_open_count` | Open critical validation issues at packet close. |</p>\n<p>| `pilot.retention_signal_count` | Count of explicit continue, convert, expand-scope, or renewal signals from the customer. |</p>\n<p>| `pilot.gross_margin_percent` | Gross-margin percentage for the pilot period, backed by invoice revenue minus support, infra, and operator cost evidence. |</p>\n<h2 id=\"monthly-evidence-packet-template\">Monthly Evidence Packet Template</h2>\n<p>Generate the current operator packet with:</p>\n<pre><code>\npnpm pilot:evidence --tenant=pilot-benton-202606 --account=benton-museum-of-art-at-pomona-college --markdown\n</code></pre>\n<p>Use `--check` in closeout, CI, or pre-send review when the packet must be</p>\n<p>ready rather than merely generated:</p>\n<pre><code>\npnpm pilot:evidence --tenant=pilot-benton-202606 --account=benton-museum-of-art-at-pomona-college --markdown --check\n</code></pre>\n<p>The command writes `artifacts/pilot-evidence/pilot-evidence-latest.json`, `artifacts/pilot-evidence/pilot-evidence-latest.md`, and timestamped packet files. The JSON packet is the machine-readable source of truth; the Markdown packet is the customer/buyer-facing summary for email, docs, or procurement review. Each packet includes invoice-backed commercial evidence, support-load counts from `pilot-support-issues.json`, and KPI evidence from `pilot-kpi-events.json`. A packet is `ready` only when the exact tenant has an active manual entitlement with a real invoice reference that is not demo, fixture, internal, placeholder, sample, smoke, or test evidence, at least one named outreach account has a sent/replied event, all activation milestones have dated evidence, support-load evidence is tied to an invoice-backed pilot period with `pilot.support_minutes` recorded, no blocking support issue remains open, no open support issue is past `nextResponseAt`, all required KPI metrics have real tenant evidence, `pilot.retention_signal_count` records a real continue, convert, expand-scope, or renewal signal, and `pilot.gross_margin_percent` records real invoice-minus-cost evidence for the pilot period; otherwise it is `blocked` with explicit open blockers. An empty support ledger before an invoice-backed pilot exists is a pending capture state, not strict support-load proof.</p>\n<p>With `--check`, a blocked packet exits non-zero while still writing the JSON and</p>\n<p>Markdown artifacts, so missing real outreach, entitlement, activation, or</p>\n<p>support or KPI evidence cannot pass an automated readiness check silently.</p>\n<p>Each monthly packet must include:</p>\n<ol><li>Pilot summary</li></ol>\n<ol><li>Activation status</li></ol>\n<ol><li>Data quality</li></ol>\n<ol><li>Rights and provenance</li></ol>\n<ol><li>Product usage</li></ol>\n<ol><li>Support load</li></ol>\n<ol><li>Next decision</li></ol>\n<ul><li>tenant ID</li><li>source namespace</li><li>record count</li><li>publication mode</li><li>current status</li><li>seven-day checklist result</li><li>first-value date</li><li>reviewer access status</li><li>validation summary</li><li>critical issues</li><li>unresolved mapping questions</li><li>enrichment coverage when available</li><li>rights/reuse status summary</li><li>records held for review</li><li>provenance risks</li><li>review sessions or customer views</li><li>API/export examples used</li><li>AI review runs consumed</li><li>open issues</li><li>resolved issues</li><li>operator minutes estimate</li><li>continue pilot</li><li>expand source scope</li><li>pause</li><li>convert to recurring subscription</li></ul>\n<h2 id=\"exit-criteria\">Exit Criteria</h2>\n<p>A pilot can be called successful when:</p>\n<ul><li>first value is reached within seven days</li><li>customer review owner can inspect records without routine developer help</li><li>monthly evidence packet is delivered</li><li>support load is recorded</li><li>conversion decision is explicit</li></ul>\n<p>Do not claim profitable SaaS readiness from this runbook alone. Profitability still needs recurring revenue, support-load evidence, retention, gross-margin, and acquisition-channel proof.</p>","updatedAt":"2018-10-20T01:46:40.000Z","checksum":"da146a8c268ca275c4f53b6244f8c648e82c7f9931c88ba11b3d1d985140e387","checksumPrefix":"da146a8c268c","anchorCount":16,"lineCount":428,"rawUrl":"/api/docs/content?path=ops%2Fmanaged-linked-art-pilot-runbook.md","htmlUrl":"/docs?doc=ops%2Fmanaged-linked-art-pilot-runbook.md","apiUrl":"/api/docs/content?path=ops%2Fmanaged-linked-art-pilot-runbook.md"}