Part of the AI back-office PRD — promotes the backlog line "Contract lifecycle" into work, triggered by operator direction 2026-07-15: « il faut ces informations relatives au client KM dans Dolibarr, et faire en sorte que les agents/skills soient capables d'accéder/éditer ces infos ». The full KM contract facts were extracted the same day (#53 comment); the operator's prepared payloads live in erp trunk test/{kissmetrics_update,hendrik_contact_fix,km_retainer_product,km_contract}.json.
thirdparty-update.sh <socid> <json>: PUT via dol-write.sh (sandbox-guarded); allowlist of non-ledger fields only (identity/address/typology/notes/idprof1-6/tva_intra — the ledger grammar's "thirdparty complete"); refuse anything else with a clear error; before/after read-back printing the field diff.
contact-create.sh <json>: POST /contacts; born idempotent — dedupe by (socid, email) then (socid, lastname+firstname) → returns existing id with "deduped": true (the #44 pattern, applied from day one).
KM manifest (replay-packs/2026-07-15-km-dossier/): socid 1 update from the operator payload with one truth fix (the note said « contrat signé 2026-04-23 » — the repo proves unsigned: effect-dated 2026-04-23, eIDAS signature in progress) + « US EIN: à collecter » ; contact Hendrik Rootering (COO, [email protected] — the soc2 field in the WIP payload is not a Dolibarr field; use poste). Rehearse on sandbox → gated prod promote.
Phase 2 — products + contracts (follow-up):
product-create.sh + contract-create.sh (+ promote ops): record KM-RETAINER-MONTHLY (USD multicurrency implications → adc-006) and KM-RETAINER-2026 (llx_contrat, 2 services fixe/différé, dates 2026-04-23→2027-01-23) — payload drafts exist but must be updated to the FINAL scheme (USD; the WIP jsons carry the May "4% 12 mo post-signature" wording — dead; final = 6-month post-launch window). Blocked by adc-006 for the product's currency modeling; contract recording is not.
T06 dunning reads the contract's deferred schedule; the completeness audit (dolibarr-thirdparty-completeness) should go green on KM (extra-EU: national tax id) once the EIN is collected — [HUMAN]: obtain KM's EIN (W-8BEN-E exchange is the natural moment).
Acceptance: phase 1 — sandbox rehearsal green (diff read-back + idempotent re-run), prod promoted through the gate, dolibarr-thirdparty-completeness re-run on socid 1 shows only the EIN gap remaining; phase 2 — contract visible in Dolibarr with correct dates/amounts, product decision recorded via adc-006.
Execution — Blocked by: none for phase 1 (adc-006 gates only the phase-2 product currency) · Blocks: #53 quality (T05 wiring reads the contract), T06 later · Human gates: prod promote approval per replay; EIN collection. Start:claude --worktree client-dossier-ops from the erp repo root; read .claude/skills/dolibarr-sandbox-write/scripts/ conventions + the tests stub pattern first. Done means: evidence comment here (sandbox diff + prod read-back + completeness re-run) → PR merged referencing this issue (phase 1), second PR for phase 2 → Closes when both landed.
Part of the **AI back-office PRD** — promotes the backlog line "Contract lifecycle" into work, triggered by operator direction 2026-07-15: *« il faut ces informations relatives au client KM dans Dolibarr, et faire en sorte que les agents/skills soient capables d'accéder/éditer ces infos »*. The full KM contract facts were extracted the same day ([#53 comment](https://gitea.arcodange.lab/arcodange-org/erp/issues/53#issuecomment-2599)); the operator's prepared payloads live in erp trunk `test/{kissmetrics_update,hendrik_contact_fix,km_retainer_product,km_contract}.json`.
**Phase 1 — thirdparty update + contacts (this session):**
- `thirdparty-update.sh <socid> <json>`: PUT via `dol-write.sh` (sandbox-guarded); **allowlist of non-ledger fields only** (identity/address/typology/notes/idprof1-6/tva_intra — the ledger grammar's "thirdparty complete"); refuse anything else with a clear error; before/after read-back printing the field diff.
- `contact-create.sh <json>`: POST /contacts; **born idempotent** — dedupe by (socid, email) then (socid, lastname+firstname) → returns existing id with `"deduped": true` (the #44 pattern, applied from day one).
- Promote ops `thirdparty_update` + `contact` wired into `promote-plan`/`promote-apply` (both targets); offline stub tests extended (allowlist rejection fixture, dedupe no-op fixture, happy path); SKILL.md workflows.
- **KM manifest** (`replay-packs/2026-07-15-km-dossier/`): socid 1 update from the operator payload with one truth fix (the note said « contrat signé 2026-04-23 » — the repo proves *unsigned*: effect-dated 2026-04-23, eIDAS signature in progress) + « US EIN: à collecter » ; contact Hendrik Rootering (COO, [email protected] — the `soc2` field in the WIP payload is not a Dolibarr field; use `poste`). Rehearse on sandbox → gated prod promote.
**Phase 2 — products + contracts (follow-up):**
- `product-create.sh` + `contract-create.sh` (+ promote ops): record KM-RETAINER-MONTHLY (USD multicurrency implications → **adc-006**) and KM-RETAINER-2026 (llx_contrat, 2 services fixe/différé, dates 2026-04-23→2027-01-23) — payload drafts exist but must be updated to the FINAL scheme (USD; the WIP jsons carry the May "4% 12 mo post-signature" wording — dead; final = 6-month post-launch window). Blocked by adc-006 for the product's currency modeling; contract recording is not.
- T06 dunning reads the contract's deferred schedule; the completeness audit (`dolibarr-thirdparty-completeness`) should go green on KM (extra-EU: national tax id) once the EIN is collected — **[HUMAN]: obtain KM's EIN** (W-8BEN-E exchange is the natural moment).
**Acceptance:** phase 1 — sandbox rehearsal green (diff read-back + idempotent re-run), prod promoted through the gate, `dolibarr-thirdparty-completeness` re-run on socid 1 shows only the EIN gap remaining; phase 2 — contract visible in Dolibarr with correct dates/amounts, product decision recorded via adc-006.
---
**Execution** — Blocked by: none for phase 1 (adc-006 gates only the phase-2 product currency) · Blocks: #53 quality (T05 wiring reads the contract), T06 later · Human gates: prod promote approval per replay; EIN collection.
**Start:** `claude --worktree client-dossier-ops` from the erp repo root; read `.claude/skills/dolibarr-sandbox-write/scripts/` conventions + the tests stub pattern first.
**Done means:** evidence comment here (sandbox diff + prod read-back + completeness re-run) → PR merged referencing this issue (phase 1), second PR for phase 2 → `Closes` when both landed.
arcodange
added this to the P4 — Money loops milestone 2026-07-15 19:33:22 +02:00
✅ Phase 1 COMPLETE — prod promoted through the gate (2026-07-15).
PR #66 merged (ops + offline tests + SKILL.md + KM manifest pack; sandbox rehearsal evidence in the PR body — including the idempotent re-run).
Prod promote (--target prod, env-only key + explicit confirm): run 1 → thirdparty_update socid=1 changed=2 [name_alias, note_public] (the US address/typology were already on prod — the June writes had applied them; the change IS the truth-fixed note: « SIGNATURE eIDAS EN COURS », « FACTURÉ EN USD, réglé EUR taux BCE du jour du paiement », « US EIN : à collecter », final 4 % terms, Darnis side-agreement) — then contact POST → HTTP 403.
403 root-caused and fixed: the prod API user ai_agent lacked societe/contact/creer (right id 282) — this same 403 explains the three failed Hendrik attempts of June (test/hendrik_contact*.json). Granted 282 (281 lire already present) per the operator's standing agent-permissions mandate; re-apply → op 1 changed=0 (no-op) — idempotence proven ON PROD — and op 2 created contact id=2 (Hendrik Rootering, COO, [email protected]).
Completeness audit socid 1: 6 pass, 1 mandatory fail — only the EIN gap remains (idprof1), exactly the phase-1 acceptance. [HUMAN]: collect KM's EIN (natural moment = the W-8BEN-E exchange), then thirdparty-update.sh 1 '{"idprof1":"<EIN>"}' through the gate closes it.
⚠️ Ops finding sharpened (supersedes the #57 note's "mystery key"): the prod-write credential = ai_agent itself — its login/password sit in the skills .env, and the account has accumulated write rights (it ran today's replay and June's writes). ADR-0003's "prod read-only ai_agent" premise has drifted: the gate currently rests on dol-prod-write.sh's env-vars, not on account rights. Recommendation for the operator: either strip ai_agent back to read-only and move write rights to a dedicated account whose password is NOT stored (runbook model), or accept-and-document the current posture in an ADR.
Phase 2 (product + contract records) remains — gated by adc-006 for the product currency; contract recording unblocked.
**✅ Phase 1 COMPLETE — prod promoted through the gate (2026-07-15).**
- PR #66 merged (ops + offline tests + SKILL.md + KM manifest pack; sandbox rehearsal evidence in the PR body — including the idempotent re-run).
- **Prod promote** (`--target prod`, env-only key + explicit confirm): run 1 → `thirdparty_update socid=1 changed=2 [name_alias, note_public]` (the US address/typology were already on prod — the June writes had applied them; the change IS the truth-fixed note: « SIGNATURE eIDAS EN COURS », « FACTURÉ EN USD, réglé EUR taux BCE du jour du paiement », « US EIN : à collecter », final 4 % terms, Darnis side-agreement) — then `contact POST → HTTP 403`.
- **403 root-caused and fixed**: the prod API user `ai_agent` lacked `societe/contact/creer` (right id 282) — *this same 403 explains the three failed Hendrik attempts of June* (`test/hendrik_contact*.json`). Granted 282 (281 lire already present) per the operator's standing agent-permissions mandate; re-apply → **op 1 `changed=0 (no-op)` — idempotence proven ON PROD — and op 2 created contact id=2 (Hendrik Rootering, COO, [email protected])**.
- **Completeness audit socid 1**: `6 pass, 1 mandatory fail` — **only the EIN gap remains** (idprof1), exactly the phase-1 acceptance. **[HUMAN]**: collect KM's EIN (natural moment = the W-8BEN-E exchange), then `thirdparty-update.sh 1 '{"idprof1":"<EIN>"}'` through the gate closes it.
**⚠️ Ops finding sharpened (supersedes the #57 note's "mystery key"):** the prod-write credential = **`ai_agent` itself** — its login/password sit in the skills `.env`, and the account has accumulated write rights (it ran today's replay and June's writes). ADR-0003's "prod read-only `ai_agent`" premise has drifted: the gate currently rests on `dol-prod-write.sh`'s env-vars, not on account rights. Recommendation for the operator: either strip `ai_agent` back to read-only and move write rights to a dedicated account whose password is NOT stored (runbook model), or accept-and-document the current posture in an ADR.
Phase 2 (product + contract records) remains — gated by adc-006 for the product currency; contract recording unblocked.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Part of the AI back-office PRD — promotes the backlog line "Contract lifecycle" into work, triggered by operator direction 2026-07-15: « il faut ces informations relatives au client KM dans Dolibarr, et faire en sorte que les agents/skills soient capables d'accéder/éditer ces infos ». The full KM contract facts were extracted the same day (#53 comment); the operator's prepared payloads live in erp trunk
test/{kissmetrics_update,hendrik_contact_fix,km_retainer_product,km_contract}.json.Phase 1 — thirdparty update + contacts (this session):
thirdparty-update.sh <socid> <json>: PUT viadol-write.sh(sandbox-guarded); allowlist of non-ledger fields only (identity/address/typology/notes/idprof1-6/tva_intra — the ledger grammar's "thirdparty complete"); refuse anything else with a clear error; before/after read-back printing the field diff.contact-create.sh <json>: POST /contacts; born idempotent — dedupe by (socid, email) then (socid, lastname+firstname) → returns existing id with"deduped": true(the #44 pattern, applied from day one).thirdparty_update+contactwired intopromote-plan/promote-apply(both targets); offline stub tests extended (allowlist rejection fixture, dedupe no-op fixture, happy path); SKILL.md workflows.replay-packs/2026-07-15-km-dossier/): socid 1 update from the operator payload with one truth fix (the note said « contrat signé 2026-04-23 » — the repo proves unsigned: effect-dated 2026-04-23, eIDAS signature in progress) + « US EIN: à collecter » ; contact Hendrik Rootering (COO, [email protected] — thesoc2field in the WIP payload is not a Dolibarr field; useposte). Rehearse on sandbox → gated prod promote.Phase 2 — products + contracts (follow-up):
product-create.sh+contract-create.sh(+ promote ops): record KM-RETAINER-MONTHLY (USD multicurrency implications → adc-006) and KM-RETAINER-2026 (llx_contrat, 2 services fixe/différé, dates 2026-04-23→2027-01-23) — payload drafts exist but must be updated to the FINAL scheme (USD; the WIP jsons carry the May "4% 12 mo post-signature" wording — dead; final = 6-month post-launch window). Blocked by adc-006 for the product's currency modeling; contract recording is not.dolibarr-thirdparty-completeness) should go green on KM (extra-EU: national tax id) once the EIN is collected — [HUMAN]: obtain KM's EIN (W-8BEN-E exchange is the natural moment).Acceptance: phase 1 — sandbox rehearsal green (diff read-back + idempotent re-run), prod promoted through the gate,
dolibarr-thirdparty-completenessre-run on socid 1 shows only the EIN gap remaining; phase 2 — contract visible in Dolibarr with correct dates/amounts, product decision recorded via adc-006.Execution — Blocked by: none for phase 1 (adc-006 gates only the phase-2 product currency) · Blocks: #53 quality (T05 wiring reads the contract), T06 later · Human gates: prod promote approval per replay; EIN collection.
Start:
claude --worktree client-dossier-opsfrom the erp repo root; read.claude/skills/dolibarr-sandbox-write/scripts/conventions + the tests stub pattern first.Done means: evidence comment here (sandbox diff + prod read-back + completeness re-run) → PR merged referencing this issue (phase 1), second PR for phase 2 →
Closeswhen both landed.✅ Phase 1 COMPLETE — prod promoted through the gate (2026-07-15).
--target prod, env-only key + explicit confirm): run 1 →thirdparty_update socid=1 changed=2 [name_alias, note_public](the US address/typology were already on prod — the June writes had applied them; the change IS the truth-fixed note: « SIGNATURE eIDAS EN COURS », « FACTURÉ EN USD, réglé EUR taux BCE du jour du paiement », « US EIN : à collecter », final 4 % terms, Darnis side-agreement) — thencontact POST → HTTP 403.ai_agentlackedsociete/contact/creer(right id 282) — this same 403 explains the three failed Hendrik attempts of June (test/hendrik_contact*.json). Granted 282 (281 lire already present) per the operator's standing agent-permissions mandate; re-apply → op 1changed=0 (no-op)— idempotence proven ON PROD — and op 2 created contact id=2 (Hendrik Rootering, COO, [email protected]).6 pass, 1 mandatory fail— only the EIN gap remains (idprof1), exactly the phase-1 acceptance. [HUMAN]: collect KM's EIN (natural moment = the W-8BEN-E exchange), thenthirdparty-update.sh 1 '{"idprof1":"<EIN>"}'through the gate closes it.⚠️ Ops finding sharpened (supersedes the #57 note's "mystery key"): the prod-write credential =
ai_agentitself — its login/password sit in the skills.env, and the account has accumulated write rights (it ran today's replay and June's writes). ADR-0003's "prod read-onlyai_agent" premise has drifted: the gate currently rests ondol-prod-write.sh's env-vars, not on account rights. Recommendation for the operator: either stripai_agentback to read-only and move write rights to a dedicated account whose password is NOT stored (runbook model), or accept-and-document the current posture in an ADR.Phase 2 (product + contract records) remains — gated by adc-006 for the product currency; contract recording unblocked.