{"ref":"artifact:kamilkov-supply-chain-rescue","page":"/artifacts/kamilkov-supply-chain-rescue","json":"/artifacts/kamilkov-supply-chain-rescue.json","generated":"2026-10-26","drafted_with_ai":true,"entity":{"id":"kamilkov-supply-chain-rescue","name":"Supply Chain Rescue","artifact_type":"sample","source_available":true,"ecosystem":"cap","serves_ecosystems":["ui5","abap"],"flavors":[{"key":"node","source":{"url":"https://raw.githubusercontent.com/Kamilkov/supply-chain-rescue/main/PRODUCT.md","title":"Kamilkov/supply-chain-rescue — PRODUCT.md, Stack","checked":"2026-10-19","quote":"SAP CAP Node.js 10.1 on Node 24, with persistent SQLite."}},{"key":"standard-abap","source":{"url":"https://github.com/kamilkov/supply-chain-rescue","title":"Kamilkov/supply-chain-rescue — README, Recall Rescue (A4H)","checked":"2026-10-19","quote":"openCypher runs through ADBC (native SQL, classic ABAP only): AMDP rejects it, and ADBC is not released for ABAP Cloud."}}],"domain":"process-and-workflow","secondary_domains":["ai-and-agents","data-and-persistence"],"origin_ring":"independent","description":{"one_line":"A CAP and SAPUI5 demo of recovery from a supply disruption: the server calculates every proposal and an approver applies it, with a battery recall traced in an ABAP system through HANA Graph openCypher.","short":"CAP and SAPUI5 demo of recovery from a supply disruption","what_it_solves":"Disrupt a supplier or a plant in a fictional network of 40 nodes and the app says which motorcycle models are affected and why, then lets a planner pick standby suppliers or a qualified assembly move at another plant; the server calculates the proposal and keeps it pending, and nothing in the network changes until an approver approves it; a rejection or a cancellation leaves the network as it was. The manual flow needs no model, no LLM and no network access on the backend, and each AI part is a separate launch command on top of it: ten past-incident suggestions from one pinned local embedding model, shown as unverified and never changing the preview; a [@cap-js/agents](artifact:cap-js-agents) agent that proposes one of the listed routes and pauses for an approver; and a background draft that picks at most one comparable incident and sends one approval email. The recall half moves the authority to ABAP: graph queries in [SAP HANA](artifact:sap-hana) trace a defective cell lot through the battery genealogy in the A4H system, ABAP applies the approved remedies all or nothing, and CAP keeps the plan, the policy and the decisions in [SQLite](external:sqlite). What the repository will not claim is written down beside what it does: automatic relevance matching is deferred because its quality gates failed, a planner's incident mark records who judged what rather than that anyone read the incident, and the public profile is code that was never deployed.","when_not_to_use":"The data is illustrative: availability is binary and backup capacity unlimited, and the model carries no inventory; nothing in it is forecast or priced. The recall half runs only against classic ABAP, because its openCypher trace goes through ADBC, which is not released for ABAP Cloud, and it expects an SSH tunnel to the A4H system it was built against. A plain `npm start` passes no model key, so the agent cannot be used on a server started that way.","to_build_on_it":"It was built in gated milestones that each left their own written record, and only the evidence files code and tests read are published; the planning documents the code comments cite stayed private. Taking the proactive path further means producing a new acceptance record with `scripts/proactive-eval.mjs`, because editing the adapter, the selector, the simulation or the incident corpus turns selection off."},"links":{"repo":"https://github.com/Kamilkov/supply-chain-rescue"},"identity":{"author":"Kamilkov"},"compat":{"runtimes":["node"]},"requires":[{"ref":"artifact:sap-cds","for":"The backend: the services, the OData V4 endpoints the app reads and the test suites run on the CAP Node.js runtime.","requirement":"required","basis":"binding","sources":[{"url":"https://raw.githubusercontent.com/Kamilkov/supply-chain-rescue/main/PRODUCT.md","title":"Kamilkov/supply-chain-rescue — PRODUCT.md, Stack","checked":"2026-10-19","quote":"SAP CAP Node.js 10.1 on Node 24, with persistent SQLite."},{"url":"https://raw.githubusercontent.com/Kamilkov/supply-chain-rescue/main/PRODUCT.md","title":"Kamilkov/supply-chain-rescue — PRODUCT.md, Stack","checked":"2026-10-19","quote":"All app data goes through OData V4."}]},{"ref":"external:sqlite","for":"The database: one file created and seeded before the first start, which keeps the plans and the decision history across restarts.","requirement":"required","basis":"binding","sources":[{"url":"https://github.com/kamilkov/supply-chain-rescue","title":"Kamilkov/supply-chain-rescue — README","checked":"2026-10-19","quote":"Built with SAP CAP (Node.js 24, SQLite) and SAPUI5 1.136 (Horizon)."},{"url":"https://github.com/kamilkov/supply-chain-rescue","title":"Kamilkov/supply-chain-rescue — README, Recall Rescue (A4H)","checked":"2026-10-19","quote":"ABAP owns the world and its integrity; CAP owns the plan and the policy (customers first) and keeps plans and decisions in SQLite."}]},{"ref":"artifact:cap-js-agents","for":"The optional agents: the recovery agent reads the current impact and proposes one of the listed routes, and pauses before anything changes.","requirement":"conditional","condition":"the optional recovery agent or the Recall Agent is used","basis":"binding","role":"agent framework","sources":[{"url":"https://github.com/kamilkov/supply-chain-rescue","title":"Kamilkov/supply-chain-rescue — README, Recovery agent (optional)","checked":"2026-10-19","quote":"The agent is a CAP agent (`@cap-js/agents` 0.9.6) with a fixed tool list: it reads the same current impact and proposes **one of the listed routes**."},{"url":"https://github.com/kamilkov/supply-chain-rescue","title":"Kamilkov/supply-chain-rescue — README, Recovery agent (optional)","checked":"2026-10-19","quote":"At the pause there is only a pending proposal with an **Agent proposal** badge."}]},{"ref":"artifact:cap-js-notifications","for":"The one notification after an applied decision, in console mode in every profile.","requirement":"required","basis":"binding","sources":[{"url":"https://github.com/kamilkov/supply-chain-rescue","title":"Kamilkov/supply-chain-rescue — README, Local notification","checked":"2026-10-19","quote":"After an **Applied** decision, and only after it is committed, one `RecoveryApplied` notification for the fictional recipient `supply-planning@example.com` is printed to the **local server console** (`@cap-js/notifications`, console mode in every profile)."}]},{"ref":"external:abap-platform","for":"The system the recall half runs in: the local package `$ZRECALL_RESCUE` holds its tables, classes, CDS views and RAP behaviour, and ABAP applies an approved plan there all or nothing.","requirement":"conditional","condition":"the Recall Rescue part is run","basis":"binding","sources":[{"url":"https://github.com/kamilkov/supply-chain-rescue","title":"Kamilkov/supply-chain-rescue — README, Recall Rescue (A4H)","checked":"2026-10-19","quote":"An SSH tunnel to A4H on `localhost:50000` (`A4H_URL`, default `http://localhost:50000`; `A4H_CLIENT`, default `001`)."},{"url":"https://github.com/kamilkov/supply-chain-rescue","title":"Kamilkov/supply-chain-rescue — README, Recall Rescue (A4H)","checked":"2026-10-19","quote":"An approver approves, and ABAP applies the plan in A4H, all or nothing."}]},{"ref":"artifact:sap-hana","for":"The trace: HANA Graph follows the defective cell lot through the battery genealogy, in openCypher over ADBC.","requirement":"conditional","condition":"the Recall Rescue part is run","basis":"binding","role":"graph query engine","sources":[{"url":"https://github.com/kamilkov/supply-chain-rescue","title":"Kamilkov/supply-chain-rescue — README, Recall Rescue (A4H)","checked":"2026-10-19","quote":"HANA Graph in the SAP system A4H traces it through the battery genealogy (cell lot > module > pack > motorcycle > customer or storage location), over current links only."},{"url":"https://github.com/kamilkov/supply-chain-rescue","title":"Kamilkov/supply-chain-rescue — README, Recall Rescue (A4H)","checked":"2026-10-19","quote":"openCypher runs through ADBC (native SQL, classic ABAP only): AMDP rejects it, and ADBC is not released for ABAP Cloud."}]},{"ref":"external:anthropic-claude-api","for":"The model behind the optional agent, `claude-sonnet-5`, read from a key the launch command passes to the one server child.","requirement":"conditional","condition":"the optional agent is started with its key","basis":"binding","sources":[{"url":"https://github.com/kamilkov/supply-chain-rescue","title":"Kamilkov/supply-chain-rescue — README","checked":"2026-10-19","quote":"The optional agent is the only part that calls an LLM over the network (Anthropic, `claude-sonnet-5`), and only when started with its key (see *Recovery agent*)."},{"url":"https://github.com/kamilkov/supply-chain-rescue","title":"Kamilkov/supply-chain-rescue — README","checked":"2026-10-19","quote":"The manual flow needs **no model, no LLM and no network access** on the backend (verified by the no-model tests)."}]},{"ref":"external:postmark","for":"Sending the email that links one configured approver to a pending manual proposal, and the automatic approval email of the proactive path.","requirement":"conditional","condition":"the email approval request is configured with a Postmark server token","basis":"binding","sources":[{"url":"https://github.com/kamilkov/supply-chain-rescue","title":"Kamilkov/supply-chain-rescue — README, Email approval request (Postmark)","checked":"2026-10-19","quote":"A planner can ask one configured approver to review a **manual** proposal by email."},{"url":"https://github.com/kamilkov/supply-chain-rescue","title":"Kamilkov/supply-chain-rescue — README, Email approval request (Postmark)","checked":"2026-10-19","quote":"Store the Postmark **Server** Token in the Keychain, typed at the hidden prompt: `security add-generic-password -s scr-email-postmark -a \"$USER\" -w`"}]}],"connects":[{"ref":"external:anthropic-claude-api","kind":"data","direction":"outbound","condition":"the server is started with the agent's key","for":"The agent's model calls; the README names this as the only part of the backend that reaches the network.","sources":[{"url":"https://github.com/kamilkov/supply-chain-rescue","title":"Kamilkov/supply-chain-rescue — README","checked":"2026-10-19","quote":"The optional agent is the only part that calls an LLM over the network (Anthropic, `claude-sonnet-5`), and only when started with its key (see *Recovery agent*)."}]},{"ref":"external:abap-platform","kind":"data","direction":"outbound","condition":"the Recall Rescue part is run","for":"Reading the genealogy trace out of A4H and applying the approved plan there, over an SSH tunnel to the system on localhost:50000.","sources":[{"url":"https://github.com/kamilkov/supply-chain-rescue","title":"Kamilkov/supply-chain-rescue — README, Recall Rescue (A4H)","checked":"2026-10-19","quote":"An SSH tunnel to A4H on `localhost:50000` (`A4H_URL`, default `http://localhost:50000`; `A4H_CLIENT`, default `001`)."},{"url":"https://github.com/kamilkov/supply-chain-rescue","title":"Kamilkov/supply-chain-rescue — README, Recall Rescue (A4H)","checked":"2026-10-19","quote":"An approver approves, and ABAP applies the plan in A4H, all or nothing."}]},{"ref":"external:postmark","kind":"data","direction":"outbound","condition":"a Postmark server token and the approval addresses are configured","for":"The approval-request email, which only links to the proposal; a send that may have arrived is never retried, because Postmark has no idempotency key.","sources":[{"url":"https://github.com/kamilkov/supply-chain-rescue","title":"Kamilkov/supply-chain-rescue — README, Email approval request (Postmark)","checked":"2026-10-19","quote":"**Sending rules:** Postmark has no idempotency key, so a send that may have reached Postmark (timeout, network error, unexpected answer) is never retried and ends as *outcome unknown*."},{"url":"https://github.com/kamilkov/supply-chain-rescue","title":"Kamilkov/supply-chain-rescue — README, Email approval request (Postmark)","checked":"2026-10-19","quote":"The email only **links** to that proposal."}]}],"provenance":{"discovered_via":[{"source":"source:github"}],"first_seen":"2026-10-19"},"drafted_with_ai":true,"maintainers":["actor:kamilkov"],"contributors":["actor:kamilkov"]},"effective_normative_relations":[],"readings":{"liveness":[{"label":"Maintenance","tier":"unknown","evidence":"no release data"},{"label":"Continuity","tier":"fair","evidence":"one contributor, personally owned"},{"label":"Repository","tier":"good","evidence":"pushed 2026-10, not archived"}],"compatibility":[{"label":"Declared for","tier":"fair","evidence":"nothing declared"},{"label":"Survived majors","tier":"unknown","evidence":"no release dates"},{"label":"Maintainer's CI","tier":"fair","evidence":"no CI configured"}],"practice":[{"label":"Tests","tier":"good","evidence":"97 test files"},{"label":"Docs","tier":"good","evidence":"docs/ with 2 pages, README 21 KB"},{"label":"Changelog","tier":"fair","evidence":"none in the repo"}],"reach":[{"value":null,"unit":"installs/week"},{"value":0,"unit":"watching"}]},"signals":{"crawled_at":"2026-10-24","npm":"not published under this name","stars":0,"forks":0,"open_issues":0,"archived":false,"pushed_at":"2026-10-18","license_spdx":null,"org_owned":false,"default_branch":"main","created_at":"2026-10-18T11:18:44Z","open_prs":0,"tree_truncated":false,"test_files":97,"workflows":0,"other_ci":false,"readme_bytes":21116,"docs_files":2,"changelog":false,"license_file":false,"dts_files":0,"first_commit":"2026-10-18","last_commit":"2026-10-18","commits":1,"contributors":1,"readme_path":"README.md","readme_sha":"170955d91cbae02aa07eaef74edaed1e6998d071","repo_read":"2026-10-24"},"edges":{"maintainers":[{"ref":"actor:kamilkov","name":"Kamil Kováč","json":"/actors/kamilkov.json"}],"contributors":[{"ref":"actor:kamilkov","name":"Kamil Kováč","json":"/actors/kamilkov.json"}],"explained_by":[],"alternative_to_this":[],"needed_by":[],"available_via":[],"parts":[],"add_ons":[],"answered_through_parts":[]}}