Lolly
App öffnen

IntelligenceBank live-verify runbook (kind: intelligencebank)

Notiz: Lolly Work

This guide covers the optional organisation service. Configuration, console and API paths refer to your Work instance. The packaged console keeps its release-matched copy of this guide.

The tenant-day checklist for the intelligencebank driver. Every endpoint path and field name in that driver comes from IntelligenceBank's public documentation and has never been confirmed against a real tenant; this pass confirms them. Nothing here writes to the tenant, and it takes about 30 minutes. The driver targets the v3 Graph API only - the one v2-named call is the login handshake IntelligenceBank documents as the auth mechanism for v3.

Before you start

Step 1: auth

export LW_BASE=https://lolly.example
lw login --email you@acme.example          # or: lw login --cookie 'lw_session=…'

lw providers preview --kind intelligencebank \
    --options '{"platformUrl":"https://acme.intelligencebank.com"}'

The credential prompt is hidden - paste the API key. preview builds an ephemeral provider record, asks the tenant and throws it away: nothing is created, stored or enabled, so a wrong option costs a retry. health ok means the login handshake, the discovered v3 base and the first list call all worked. Step 2 needs one resource id: re-run this command with --json and read sample[].id (the last segment of ext/preview/<id>), because the printed table truncates that column.

SymptomWhat it meansWhat to fix
health FAILED: intelligencebank login 401 (or 403)the login call was refusedThe API key.
health FAILED: intelligencebank login 404the login call reached a path that is not thereThe login path and body (row 1).
health FAILED: intelligencebank login returned no sid/apiV3url (live-verify: the login response field names …)the login succeeded and the driver could not read the responseOnly the response key names are wrong: rows 2 and 3.
health FAILED: intelligencebank api 401 for /resources?per_page=100&page=1the session was established and the v3 API refused itThe sid/clientid headers, not the login (row 4).
health FAILED: intelligencebank platformUrl outside intelligencebank.comthe host guard refused the URL you passedA custom-domain tenant (row 21).
health FAILED: intelligencebank apiV3url outside intelligencebank.comthe login handed back a base off the familyRow 21. The guard is deliberate: a poisoned login response must not redirect the driver.

Exit code 2 means health failed. --shape calls the tenant only when health is ok.

Step 2: capture the shape

One command, one file, using a resource id from step 1:

lw providers preview --kind intelligencebank --shape --remote-id r1 \
    --options '{"platformUrl":"https://acme.intelligencebank.com"}' > intelligencebank-shape.txt

The file holds two reports - the list call, then the /resource/<id> detail call the bytes come from (rows 19 and 20). Both are key names and value types only: no values, no asset content, no credential, and the prompt goes to stderr. Read the three groups in this order:

  1. EXPECTED BY THIS DRIVER, ABSENT - the wrong guesses, and the answer this page exists for. Each entry reads key|alternatives (CONSTANT_NAME), so it identifies the constant to widen. (none) means every guess matched.
  2. IN THE RESPONSE, NOT MAPPED - what your tenant sent that the driver ignores. The fix for an absent guess is usually sitting here: ABSENT expiry_date|review_date (AVAILABLE_UNTIL_KEYS) beside NOT MAPPED expiration is one constant edit.
  3. MAPPED BY THIS DRIVER - confirmed.

Read the record: block too. Keys are unioned across the page, so a key one resource omits does not read as absent, and this is the governance-rich kind: a second expiry, a review cycle or a rights window sitting in NOT MAPPED is worth reporting even though no row below asks for that field.

The assumption table

One row per LIVE-VERIFY bullet in the driver header (server/src/catalog/providers/intelligencebank.ts), the field-names bullet expanded per constant. If a row and that header disagree, the header is right and this table is stale.

#The assumptionHow the report answers itFix it in providers/intelligencebank.ts
1The login call is POST <platformUrl>/webapp/1.0/api/authenticate with body {"apikey": "…"}Not in the report: a wrong path or body fails step 1 as intelligencebank login 404 before there is anything to reportThe fetchImpl call inside session() - path and body together
2The login response carries the session id as sid, then sessionNot in the report - it is the handshake, not a list. A 200 the driver cannot read is step 1's third row, which identifies this constantSESSION_ID_KEYS
3The login response carries the v3 base as apiV3urlSame as row 2, same messageAPI_BASE_KEYS
4The login response carries clientid (a header on every v3 call) and expires_in (the session TTL)Not in the report. A missing clientid omits the header, so it shows as a 401 on the first v3 call; a missing expires_in falls back to a 30 minute sessionCLIENT_ID_KEYS / SESSION_TTL_KEYS
5Listing is GET <apiV3url>/resources?per_page=100&page=<n>, plus folderid=<id> when scopedThe first report line identifies the exact call; envelope: resources: object[] (N) says how many came backlistPath and PAGE_SIZE
6The resource array rides resources, then responseThe record: line identifies the key that held it, or says no record array was found and lists `resources\response (LIST_ENVELOPE_KEYS)` under ABSENT with the real key in NOT MAPPEDLIST_ENVELOPE_KEYS
7The next-page cursor is meta.next_pageenvelope: meta: { next_page: … } shows both levels. ABSENT meta (META_KEYS) means the envelope calls it something else; a meta with a differently named cursor inside stops paging after page 1, silentlyMETA_KEYS / NEXT_PAGE_KEYS
8The resource id is resourceid, then idABSENT `resourceid\id (RECORD_ID_KEYS)`. A resource with no readable id throws rather than federating silentlyRECORD_ID_KEYS
9The filename is filename and the title is nameABSENT `filename\name (FILENAME_KEYS / DISPLAY_NAME_KEYS)`, with the real names in NOT MAPPEDFILENAME_KEYS / DISPLAY_NAME_KEYS
10The format is extensionABSENT extension (FORMAT_KEYS). Recoverable: the driver falls back to the filename extensionFORMAT_KEYS
11The byte size is sizeABSENT size (SIZE_KEYS). Whether the number is bytes is a value question - compare it against the UI in step 3SIZE_KEYS
12The change stamp is updated, then updated_dateABSENT `updated\updated_date (UPDATED_AT_KEYS). lw providers drift` compares this field, so a wrong guess reads as "nothing ever changes upstream"UPDATED_AT_KEYS
13Approval is a workflow state under workflow_state, then statusABSENT `workflow_state\status (WORKFLOW_STATE_KEYS)`WORKFLOW_STATE_KEYS
14The approved states are whatever options.approvedStates names; absent, approval is unfilteredNot in the report - these are values. Set approvedStates and re-run step 1 (or sync): a page nothing matched prints intelligencebank treated all N resource(s) on this page as not approved (live-verify: the workflow-state VALUES …)options.approvedStates on the provider entry, not a constant. Only your org can answer this row
15Availability starts at publish_dateABSENT publish_date (AVAILABLE_FROM_KEYS), with the real name in NOT MAPPEDAVAILABLE_FROM_KEYS
16Availability ends at expiry_date, then review_dateABSENT `expiry_date\review_date (AVAILABLE_UNTIL_KEYS)`. Check the order: the driver takes the first it finds, report cases where your tenant carries both and means different things by themAVAILABLE_UNTIL_KEYS
17The folder is folder, and its name is folder.namefolder: { id: string, name: string } in the record: block shows both levels. ABSENT folder (FOLDER_KEYS) means no folder section is ever readFOLDER_KEYS / FOLDER_NAME_KEYS
18Categories ride category, and fold into sections beside the folder nameABSENT category (CATEGORY_KEYS). A string or an array of strings both workCATEGORY_KEYS
19The single-resource call is GET <apiV3url>/resource/<id>, wrapping the record in resource (or nothing)The detail report identifies the wrapper the tenant used, or says the record came back unwrapped. Left unfixed it fails in step 3 with intelligencebank resource has no download url in the response to GET /resource/<id> (live-verify: …)DETAIL_WRAPPER_KEYS, and the path in resolveBlob
20The signed link is download_url, and it serves the original bytesThe name is in the detail report: ABSENT download_url (DOWNLOAD_URL_KEYS) with the real name in NOT MAPPED. Whether it serves the original is a value question - step 3's checksum answers itDOWNLOAD_URL_KEYS
21Every host - platform, discovered v3 base and CDN - is inside the intelligencebank.com familyNot in the report. Each guard has its own message: platformUrl outside, apiV3url outside, or url outside allowed hosts on the blob fetchALLOWED_HOSTS - add the custom domain explicitly, never as a wildcard

Step 3: bytes

Only a blob fetch proves the export capability the exit depends on, so this step creates a real provider record.

lw providers add acme-ib --kind intelligencebank --label "Acme IntelligenceBank" \
    --options '{"platformUrl":"https://acme.intelligencebank.com","folderId":"f1","approvedStates":["Approved","Published"]}' \
    --exposure '{"groups":["admin"]}'    # verification pass: admins only, not the whole org
lw providers credential acme-ib          # hidden prompt, same API key as step 1
lw providers enable acme-ib              # owner-only
lw providers sync acme-ib                # federate: confirm the count, read any notes
lw providers materialize acme-ib --remote-id r1 --json

--remote-id filters the walk rather than skipping it, so keep options.folderId narrow. Every per-asset failure prints under the summary as <remoteId>: <message>, and each message identifies the assumption, the constant and this page. A materialize that fails partway through and then works on a re-run is the session TTL (row 4).

Fidelity - the true original, or a rendition?

curl -sS -b "$(cat ~/.config/lolly-work/session)" \
    "$LW_BASE/catalog/ext/acme-ib/r1/download" -o /tmp/ib-lolly.bin
shasum -a 256 /tmp/ib-lolly.bin
file /tmp/ib-lolly.bin

Download the same resource from the IntelligenceBank UI as the original and checksum that too. A matching checksum strikes row 20. A different one means the link is a rendition or a preview - compare sizes, pixel dimensions and EXIF/ICC metadata, and report it as row 20 rather than a materialize bug (materialize checksums whatever it is given, so a rendition arrives silently as the wrong bytes). Repeat per file type you plan to exit: a governance-rich DAM often serves office and design files through a different link than images. A failure on the blob route surfaces as 502 PROVIDER_UNAVAILABLE; the diagnosis is in the materialize output, not there.

Last, the stamp the exit cadence depends on:

lw providers drift acme-ib

compared counts only the copies that got a real answer; every other copy prints under its own reason. not compared: … carries no change stamp the driver can read and … would not parse as a date (shape …) are both row 12 - send the shape it prints. … no longer in the listing at all means those resources left the scope you federated. read with care: … names no timezone did compare, in this server's timezone, so those answers can be off by its UTC offset.

Then take the pass down. Materialized copies are instance-owned and survive the delete:

lw providers disable acme-ib
lw providers rm acme-ib

Step 4: sign off

See also: the IntelligenceBank guide · off-boarding · the CLI · the other runbooks: canto · imagerelay · acquia-dam.