Compare commits

...
Author SHA1 Message Date
arcodangeandClaude Fable 5 ec49706952 fix(dns): import coredns custom *.server blocks at Corefile root — inside .:53 it crashes CoreDNS
The never-yet-applied k3s_dns.yml placed 'import /etc/coredns/custom/*.server'
INSIDE the .:53 server block. *.server files hold full server blocks
(arcodange.lab:53 {…}), which only parse at Corefile root — inside a block
CoreDNS dies at startup with "Unknown directive 'arcodange.lab:53'"
(CrashLoopBackOff, cluster DNS fully down; lived it on 2026-07-24 while
restoring the expired *.arcodange.lab certificate).

Also restores the stock 'loadbalance' plugin dropped by the playbook.

Context: cluster CoreDNS forwarded to the node's resolv.conf, which lists the
ISP box's IPv6 RDNSS next to the Pi-holes — NXDOMAIN roulette for *.lab names.
That's what left step-issuer unable to reach ssl-ca.arcodange.lab:8443 and let
the 24h wildcard cert expire this morning. The (fixed) playbook pins .lab
resolution to the Pi-holes via the coredns-custom ConfigMap; applied live on
2026-07-24, wildcard renewed, strict TLS verified on gitea/argocd/grafana.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-24 10:13:41 +02:00
arcodange 1f22669ac6 feat(argocd): apps override destination namespace; kadans-jobs → kadans (#38)
Co-authored-by: Gabriel Radureau <[email protected]>
Co-committed-by: Gabriel Radureau <[email protected]>
2026-07-20 10:23:34 +02:00
arcodange 342026a3d9 fix(argocd): stop the document separator gluing itself to the last chart value (#37)
Co-authored-by: Gabriel Radureau <[email protected]>
Co-committed-by: Gabriel Radureau <[email protected]>
2026-07-20 09:22:49 +02:00
arcodange 34c1ad697f fix(argocd): let the image-updater trust the lab CA — the last blocker to rollouts (#36)
Co-authored-by: Gabriel Radureau <[email protected]>
Co-committed-by: Gabriel Radureau <[email protected]>
2026-07-20 09:11:25 +02:00
arcodangeandClaude Opus 4.8 d3261bc8c4 feat(argocd): enroll kadans-jobs — the Kadans analysis-jobs façade (#35)
kadans-jobs is the tier-2 (homelab, 24/7) piece of the Kadans topology: a job
queue plus the store of published analysis results, decoupling the product from
the volatile Mac worker.

org: arcodange — the repo does not live under the default arcodange-org.
Digest-based image-updater annotations follow the fleet pattern; the
cluster-wide ImageUpdater CR (namePattern "*", useAnnotations) picks them up,
so there is no per-app CR to maintain. The image is already in the registry.

No postgres/iac/terraform.tfvars entry, on purpose: the façade runs a memory
store in v0, so it needs neither a database nor Vault. That is the runbook's
degraded mode — the DB, the Vault JWT role and the app's own iac/ will land
together with the Postgres store.

Chart realigned on the runbook conventions first, in kadans-jobs#1.

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Claude-Session: https://claude.ai/code/session_013ws8L74dVZmp97Wu36fm8j
Co-authored-by: Gabriel Radureau <[email protected]>
Co-committed-by: Gabriel Radureau <[email protected]>
2026-07-20 09:07:44 +02:00
arcodange 655ef61fc5 fix(argocd): restore fleet image rollouts — image-updater v1 needs an ImageUpdater CR (#34)
Co-authored-by: Gabriel Radureau <[email protected]>
Co-committed-by: Gabriel Radureau <[email protected]>
2026-07-20 08:58:47 +02:00
arcodange e9d10113aa Merge pull request 'docs(prd): STATUS — erp#39/#40/#54 shipped and merged under the operator's go' (#33) from arcodange/status-morning into main 2026-07-19 09:23:49 +02:00
arcodangeandClaude Fable 5 39809dcec8 docs(prd): STATUS — #39/#40/#54 shipped and merged under the operator's go
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VRShc4QhLLU73FLHx9vskh
2026-07-19 09:23:34 +02:00
arcodange 37b9e183d9 Merge pull request 'docs(prd): STATUS truth-pass — erp#43/#44 shipped, #40 built (bar met), entry points re-baselined' (#32) from arcodange/status-20260719 into main 2026-07-19 00:32:34 +02:00
arcodangeandClaude Fable 5 8587b4ad00 docs(prd): STATUS truth-pass — #43/#44 shipped, #40 built (bar met), entry points re-baselined
Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VRShc4QhLLU73FLHx9vskh
2026-07-19 00:32:14 +02:00
arcodange c8ea130ff6 Merge pull request 'docs(prd): cross-family verification rule + STATUS truth-pass (erp#56/#63/#39)' (#31) from arcodange/harness-portability-qa into main 2026-07-18 20:23:13 +02:00
arcodangeandClaude Fable 5 c55714d892 docs(prd): cross-family verification rule + STATUS truth-pass (erp#56/#63/#39)
- qa-strategy › Independent verification: with Mistral (vibe -p,
  mistral-medium-3.5) and Ornith 35B admitted to verifier duty by verdict
  parity (erp#63 evidence, blind-judged), the independent verifier SHOULD be
  a different model family than the builder; journal records which family
  verified what.
- STATUS: #63  (PR erp#69, harness home erp:fleet/harness/), #56 
  (PR erp#68, authored by the Mistral builder bench), #39 built on local
  branch (push+PR = operator step), PR-log rows, P3 flipped to in-progress.

Paired with erp#69 (Closes erp#63).

Co-Authored-By: Claude Fable 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01VRShc4QhLLU73FLHx9vskh
2026-07-18 20:21:55 +02:00
arcodangeandClaude Fable 5 a4be009e3e chore(argocd): retire le bloc repoServer mort des values image-updater
Ajouté par bda53f29 pour « monter les credentials dans le repo-server »,
mais ces values sont passées au chart argocd-image-updater (HelmChart
kube-system) qui n'a pas de clé repoServer : no-op intégral. Le vrai
repo-server ArgoCD est déployé par l'addon k3s et n'a pas besoin de ce
montage — les credentials repo passent par les secrets étiquetés
argocd.argoproj.io/secret-type.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-16 20:37:58 +02:00
arcodangeandClaude Fable 5 3698ab3c73 fix(argocd): retire usernameSecret/passwordSecret de spec.source — champs inexistants du CRD Application
Ces champs (commit 7aa789d1) n'existent pas dans le schéma Application
d'ArgoCD : l'API server les élague à l'apply, d'où un diff permanent →
factory OutOfSync en boucle (296 tentatives selfHeal) sur kadans,
telegram-gateway et dance-lessons-coach. L'authentification aux repos
privés passe par un secret repo-creds (label
argocd.argoproj.io/secret-type: repo-creds, url préfixe
https://gitea.arcodange.lab/arcodange) — corrigé côté cluster sur le
secret gitea-credentials existant.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-16 20:37:29 +02:00
arcodange bf32afc217 Merge pull request 'docs(prd): contract lifecycle is live — erp#65 phase 1 shipped, erp#67 official-doc skill (T18)' (#29) from arcodange/contract-lifecycle-live into main 2026-07-15 19:57:00 +02:00
arcodangeandClaude Fable 5 92c1be9780 docs(prd): contract lifecycle is live — erp#65 phase 1 shipped, erp#67 official-doc skill (T18 candidate)
Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-15 19:56:28 +02:00
arcodange 96751f9fcd Merge pull request 'docs(prd): harness portability — Claude as escalation tier, not hard dependency' (#28) from arcodange/harness-portability into main 2026-07-15 18:50:20 +02:00
arcodangeandClaude Fable 5 c7320d2811 docs(prd): STATUS — erp#63 harness-portability spike joins P3
Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-15 18:50:05 +02:00
arcodangeandClaude Fable 5 5aea83749d docs(prd): harness portability — Claude as escalation tier, not hard dependency
Operator direction 2026-07-15: the orchestration layer itself (builder
sessions, cold verifiers) must run on Mistral or hermes+Ornith/MLX too.
The protocol already carries everything in files+issues; new model-fleet
section defines the evidence-gated ladder — verifier roles migrate
first (cross-family refutation is stronger verification), scoped
builders benched on unchanged acceptance gates, Claude default until
the bench says otherwise. D2 row records the direction; spike = erp#63.

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-15 18:49:05 +02:00
arcodange 72cca8a3b0 Merge pull request 'docs(prd): D8 settled — fleet/ landed with erp#62; STATUS truth-pass' (#27) from arcodange/d8-settled into main 2026-07-15 18:43:57 +02:00
arcodangeandClaude Fable 5 8232ed7987 docs(prd): D8 settled — fleet/ landed with erp#62; STATUS truth-pass
erp#38 shipped 2026-07-15 (PR erp#62, independent locate-test PASS):
D8 row flipped leaning→settled, P1 phase row 🟡 in progress with the
first , cold-start entry point advances to erp#39 (golden set).

Co-Authored-By: Claude Fable 5 <[email protected]>
2026-07-15 18:43:34 +02:00
arcodange bda53f299a fix: monter credentials dans repo-server 2026-07-13 19:15:40 +02:00
arcodange 7aa789d1cf fix: ajouter credentials gitea pour repos privés 2026-07-13 19:07:15 +02:00
arcodange 1d477a4c6e fix: corriger organisation kadans vers arcodange 2026-07-13 19:05:05 +02:00
12 changed files with 122 additions and 17 deletions
@@ -54,7 +54,11 @@
cache 30
loop
reload
loadbalance
import /etc/coredns/custom/*.override
import /etc/coredns/custom/*.server
forward . {{ pihole_ips | map('regex_replace', '^(.*)$', '\1:53') | join(' ') }}
}
# Les fichiers *.server contiennent des BLOCS SERVEUR complets (ex: `arcodange.lab:53 {…}`) :
# leur import doit vivre au niveau racine du Corefile. À l'intérieur de `.:53 {}`,
# CoreDNS crashe au parse (« Unknown directive 'arcodange.lab:53' ») — vécu le 2026-07-24.
import /etc/coredns/custom/*.server
+12
View File
@@ -0,0 +1,12 @@
-----BEGIN CERTIFICATE-----
MIIBwDCCAWagAwIBAgIRAJzOnXbHdqAB0QnEjNw21xgwCgYIKoZIzj0EAwIwPjEZ
MBcGA1UEChMQQXJjb2RhbmdlIExhYiBDQTEhMB8GA1UEAxMYQXJjb2RhbmdlIExh
YiBDQSBSb290IENBMB4XDTI1MTIyOTA5Mjk0NVoXDTM1MTIyNzA5Mjk0NVowPjEZ
MBcGA1UEChMQQXJjb2RhbmdlIExhYiBDQTEhMB8GA1UEAxMYQXJjb2RhbmdlIExh
YiBDQSBSb290IENBMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAERTF3M6MtqK4m
q4e38e1KzHP7TRrf/DwEwxyafyp9iONE6na0+dgPvXPurG0kmom9PIYA2aE2eCzz
hFkQ2DO1TqNFMEMwDgYDVR0PAQH/BAQDAgEGMBIGA1UdEwEB/wQIMAYBAf8CAQEw
HQYDVR0OBBYEFJCxc6tumAlVAaUjoKExPcNZsVoYMAoGCCqGSM49BAMCA0gAMEUC
IGtrew3FOPh16x3XevWCO8suH7laCn8kTV2ZZpAK0UkhAiEA/bA7HiDqEaXHSc35
b7fZX1fuKI6SdEWN9hj5EwP45Z8=
-----END CERTIFICATE-----
+5 -2
View File
@@ -1,5 +1,8 @@
{{- range $app_name, $app_attr := .Values.gitea_applications -}}
{{- $org := default "arcodange-org" $app_attr.org -}}
{{- /* Namespace defaults to the app name; override lets siblings share one
(e.g. kadans-jobs deploys into the `kadans` namespace). */ -}}
{{- $ns := default $app_name $app_attr.namespace -}}
---
apiVersion: argoproj.io/v1alpha1
kind: Application
@@ -20,7 +23,7 @@ spec:
path: chart
destination:
server: https://kubernetes.default.svc
namespace: {{ $app_name }}
namespace: {{ $ns }}
syncPolicy:
{{- if $app_attr.syncPolicy }}
{{- toYaml $app_attr.syncPolicy | nindent 4 }}
@@ -74,4 +77,4 @@ spec:
syncOptions:
- CreateNamespace=true
{{- end }}
{{ end }}
{{ end }}
+1 -2
View File
@@ -10,5 +10,4 @@ spec:
targetNamespace: argocd
valuesContent: |-
{{- toYaml . | nindent 4 }}
{{- end -}}
---
{{- end }}
+19
View File
@@ -0,0 +1,19 @@
{{- /*
The lab's root CA, as a ConfigMap the image-updater pod can mount.
Nodes trust it through the OS store (/usr/local/share/ca-certificates), which
is why kubelet pulls images fine — but a container carries its own trust store,
so argocd-image-updater failed every registry query with
"x509: certificate signed by unknown authority" and updated nothing.
A root CA certificate is public material (no private key here), so it lives in
git next to the chart that consumes it.
*/ -}}
apiVersion: v1
kind: ConfigMap
metadata:
name: homelab-ca
namespace: argocd
data:
arcodange-root.crt: |
{{ .Files.Get "files/arcodange-root.crt" | indent 4 }}
+22
View File
@@ -0,0 +1,22 @@
{{- /*
argocd-image-updater v1+ ships a CRD-based controller: it no longer scans
Application annotations on its own and idles with "No ImageUpdater CRs to
process" — which silently froze image rollouts for the WHOLE fleet (kadans,
webapp, cms, dance-lessons-coach, prospection, telegram-gateway) after the
un-pinned HelmChart pulled the new major.
This single CR restores the previous behaviour: select every Application in
the argocd namespace and read the existing
`argocd-image-updater.argoproj.io/*` annotations (useAnnotations mode). Apps
without annotations are simply ignored — no per-app CR to maintain, the
annotations in values.yaml stay the one source of truth.
*/ -}}
apiVersion: argocd-image-updater.argoproj.io/v1alpha1
kind: ImageUpdater
metadata:
name: annotated-applications
namespace: argocd
spec:
applicationRefs:
- namePattern: "*"
useAnnotations: true
+25 -2
View File
@@ -40,9 +40,17 @@ gitea_applications:
argocd-image-updater.argoproj.io/image-list: prospection=gitea.arcodange.lab/arcodange-org/prospection:latest
argocd-image-updater.argoproj.io/prospection.update-strategy: digest
kadans:
org: arcodange
annotations:
argocd-image-updater.argoproj.io/image-list: kadans=gitea.arcodange.lab/arcodange-org/kadans:latest
argocd-image-updater.argoproj.io/image-list: kadans=gitea.arcodange.lab/arcodange/kadans:latest
argocd-image-updater.argoproj.io/kadans.update-strategy: digest
kadans-jobs:
org: arcodange
# La façade d'analyse vit dans le namespace de l'app qu'elle sert.
namespace: kadans
annotations:
argocd-image-updater.argoproj.io/image-list: kadans-jobs=gitea.arcodange.lab/arcodange/kadans-jobs:latest
argocd-image-updater.argoproj.io/kadans-jobs.update-strategy: digest
argocd_image_updater_chart_values:
config:
@@ -50,4 +58,19 @@ argocd_image_updater_chart_values:
grpcWeb: false
serverAddress: "https://argocd.arcodange.lab/"
insecure: true
plaintext: true
plaintext: true
# The lab CA, so the updater can talk to the Gitea registry over TLS.
# Go reads every file in /etc/ssl/certs on top of the bundle, so dropping our
# root in there (subPath — the image's own certs stay untouched) is enough.
# Without it every query died on "certificate signed by unknown authority"
# and no image was ever rolled out. The registry itself allows anonymous
# pulls, so no credentials are needed — trust was the only missing piece.
volumes:
- name: homelab-ca
configMap:
name: homelab-ca
volumeMounts:
- name: homelab-ca
mountPath: /etc/ssl/certs/arcodange-root.crt
subPath: arcodange-root.crt
readOnly: true
+15 -6
View File
@@ -2,8 +2,8 @@
# STATUS — implementation tracker
> **Status:** 🟢 Current — backlog decomposed into issues (2026-07-11); sharpened with per-issue Execution footers + splits #59/#60 (2026-07-12)
> **Last Updated:** 2026-07-12
> **Status:** 🟢 Current — backlog decomposed into issues (2026-07-11); sharpened with per-issue Execution footers + splits #59/#60 (2026-07-12); execution started — erp#38 shipped, D8 settled (2026-07-15); harness portability proven — erp#63 + #56 closed, Mistral + Ornith admitted to verifier duty (2026-07-18); **P1 write-skill + atom sprint — #44/#43/#39/#40 shipped (invoice-extract at the 98 % bar: 100 % criticals, 6/6 injections quarantined), #54 Accepted + merged (2026-07-19)**
> **Last Updated:** 2026-07-19
> **Up:** [AI back-office hub](README.md)
> **Related:** [POC plan](poc-plan.md) · [Roadmap](roadmap.md) (dated plan; actuals and slips land here)
@@ -12,9 +12,9 @@
| Phase | Scope | State |
| --- | --- | --- |
| 0 — Foundations | read skills, sandbox + promote, backups, snapshots, bank reco, email ingest, Telegram gateway MVP | ✅ shipped pre-PRD (ledger below) |
| 1 — Flagship pipeline | [POC-1](poc-plan.md#poc-1--supplier-invoice-end-to-end) + [POC-5](poc-plan.md#poc-5--model-routing-bench) | ⬜ decomposed → [erp milestone P1](https://gitea.arcodange.lab/arcodange-org/erp/milestone/1) (erp#3845, #47 — due 2026-10-09) |
| 1 — Flagship pipeline | [POC-1](poc-plan.md#poc-1--supplier-invoice-end-to-end) + [POC-5](poc-plan.md#poc-5--model-routing-bench) | 🟡 in progress → [erp milestone P1](https://gitea.arcodange.lab/arcodange-org/erp/milestone/1) (erp#3845, #47 — due 2026-10-09) · **#38 ✅ 2026-07-15** ([PR erp#62](https://gitea.arcodange.lab/arcodange-org/erp/pulls/62)) |
| 2 — Urgent compliance | [POC-6](poc-plan.md#poc-6--e-invoicing-readiness-spike) — **hard deadline 2026-09-01** | ⬜ decomposed → [erp milestone P2](https://gitea.arcodange.lab/arcodange-org/erp/milestone/2) (erp#46 — due 2026-09-01) |
| 3 — Standing fleet | [POC-2](poc-plan.md#poc-2--pi-sentinel), queue, digest + approval cards | ⬜ decomposed → [erp milestone P3](https://gitea.arcodange.lab/arcodange-org/erp/milestone/3) (erp#4850, #59 — due 2026-11-13) + [gateway#1](https://gitea.arcodange.lab/arcodange/telegram-gateway/issues/1)/[#2](https://gitea.arcodange.lab/arcodange/telegram-gateway/issues/2) |
| 3 — Standing fleet | [POC-2](poc-plan.md#poc-2--pi-sentinel), queue, digest + approval cards, harness portability | 🟡 in progress → [erp milestone P3](https://gitea.arcodange.lab/arcodange-org/erp/milestone/3) (erp#4850, #59 — due 2026-11-13) + [gateway#1](https://gitea.arcodange.lab/arcodange/telegram-gateway/issues/1)/[#2](https://gitea.arcodange.lab/arcodange/telegram-gateway/issues/2) · **#63 ✅ 2026-07-18** ([PR erp#69](https://gitea.arcodange.lab/arcodange-org/erp/pulls/69): harness home `erp:fleet/harness/`, Mistral `vibe -p` + Ornith 35B at verifier parity, builder bench = #56 by Mistral, 0 corrections) |
| Ledger compliance (cross-cutting) | [Dolibarr verifications](compliance.md#dolibarr-verifications-sandbox-first) | ⬜ decomposed → [erp milestone](https://gitea.arcodange.lab/arcodange-org/erp/milestone/4) (erp#51 — due 2026-11-27) |
| 4 — Money loops | [POC-3](poc-plan.md#poc-3--reconciliation--payment-recording), dunning, cash report | ⬜ decomposed → [erp milestone P4](https://gitea.arcodange.lab/arcodange-org/erp/milestone/5) (erp#5253 — due 2026-12-24) |
| 5 — Fiscal autopilot | [POC-4](poc-plan.md#poc-4--tva-dry-run), compliance calendar | ⬜ decomposed → [erp milestone P5](https://gitea.arcodange.lab/arcodange-org/erp/milestone/6) (erp#5455, #60 — due 2027-05-04) |
@@ -22,11 +22,11 @@
## Backlog map
Every phase is decomposed into **self-contained issues** (context, deliverables, acceptance criteria, dependencies, PRD links); since 2026-07-12 each issue also carries an **Execution footer***Blocked by / Blocks / Human gates / Start (worktree + first command) / Done means (evidence comment → PR with `Closes #N` → doc sweep)*. How a future session resumes: **order open milestones by due date, pick the top issue whose "Blocked by" is clear — and skip issues whose only open step is a `[HUMAN]` gate** (surface those in the digest instead of stalling on them; e.g. erp#46 step 1 is operator-owned). Cold-start entry points as of 2026-07-12: **erp#38** (the fleet entry issue), **erp#51** (startable today), **erp#41/#42/#43/#44** (write-skill side, independent of the scaffold). **Arbitration: one session = one lane** — take the entry issue; an orchestrator may fan the independent lanes out in parallel (#38#51#4144 touch disjoint directories); everything else follows due-date order (dates in the phase tracker above). The issue body carries everything; on any doubt the trust order is live system > code > STATUS > leaves. Cross-cutting decisions get their ADRs via [factory#22](https://gitea.arcodange.lab/arcodange-org/factory/issues/22).
Every phase is decomposed into **self-contained issues** (context, deliverables, acceptance criteria, dependencies, PRD links); since 2026-07-12 each issue also carries an **Execution footer***Blocked by / Blocks / Human gates / Start (worktree + first command) / Done means (evidence comment → PR with `Closes #N` → doc sweep)*. How a future session resumes: **order open milestones by due date, pick the top issue whose "Blocked by" is clear — and skip issues whose only open step is a `[HUMAN]` gate** (surface those in the digest instead of stalling on them; e.g. erp#46 step 1 is operator-owned). Cold-start entry points as of 2026-07-19 (post-#39/#40/#54): **erp#45** (routing bench — golden set + atom + dual-run journals all on main), **erp#41/#42** (write-skill side, independent), **erp#51** (startable today), **erp#60** (T11 loop — its data files landed with #54). Operator-gated, not session-startable: #46 step 1 (Qonto UI, hard 2026-09-01), #53 July manual invoice ~07-23, prod replay of the GED manifest-C. **Arbitration: one session = one lane** — take the entry issue; an orchestrator may fan the independent lanes out in parallel (#39#51#4144 touch disjoint directories); everything else follows due-date order (dates in the phase tracker above). The issue body carries everything; on any doubt the trust order is live system > code > STATUS > leaves. Cross-cutting decisions get their ADRs via [factory#22](https://gitea.arcodange.lab/arcodange-org/factory/issues/22).
| Repo | Issues |
| --- | --- |
| [erp](https://gitea.arcodange.lab/arcodange-org/erp/issues) | **P1:** #38 fleet scaffold+AGENTS.md (D8, **entry issue**) · #39 golden set+injection fixtures · #40 invoice-extract atom · #41 provenance checker · #42 compliance linter · #43 GED attach op · #44 idempotency keys · #45 POC-5 routing bench (D5) · #47 POC-1 exit gate (umbrella) — **P2:** #46 POC-6 Qonto-as-PA (D4; step 1 = [HUMAN] Qonto UI) — **P3:** #48 T13 drift watchdog · #59 T14 backup freshness+drill · #49 T17 second-brain hooks (D7; meeting lane D9 parked) · #50 POC-2 Pi sentinel (D6) — **Compliance:** #51 Dolibarr verifications (FEC/BlockedLog, startable today) — **P4:** #52 POC-3 reco+payments · #53 T05 client invoice (D3, ⚠️ July manual ~07-23) — **P5:** #54 fiscal profile+calendar files+ADC register · #60 T11 reminder loop · #55 POC-4 TVA dry-runs — **Ops (post-replay):** #56 known-patterns fix · #57 bucket C + document gaps |
| [erp](https://gitea.arcodange.lab/arcodange-org/erp/issues) | **P1:** #38 fleet scaffold ✅ 2026-07-15 (D8 settled, PR erp#62) · #39 golden set+injection fixtures **✅ 2026-07-19** ([PR erp#73](https://gitea.arcodange.lab/arcodange-org/erp/pulls/73) — 16 invoices + 6 injection + 1824 mails + scorer) · #40 invoice-extract atom **✅ 2026-07-19** ([PR erp#74](https://gitea.arcodange.lab/arcodange-org/erp/pulls/74) — **critical-field 100 % on the 98 % bar, 6/6 injections quarantined pre-model**, A1, journals = #45 raw material) · #41 provenance checker · #42 compliance linter · #43 GED attach op **✅ 2026-07-19** ([PR erp#72](https://gitea.arcodange.lab/arcodange-org/erp/pulls/72)) · #44 idempotency keys **✅ 2026-07-19** ([PR erp#70](https://gitea.arcodange.lab/arcodange-org/erp/pulls/70) — the 2026-07-11 manifest-B replays 5/5 deduped) · #45 POC-5 routing bench (D5) · #47 POC-1 exit gate (umbrella) — **P2:** #46 POC-6 Qonto-as-PA (D4; step 1 = [HUMAN] Qonto UI) — **P3:** #48 T13 drift watchdog · #59 T14 backup freshness+drill · #49 T17 second-brain hooks (D7; meeting lane D9 parked) · #50 POC-2 Pi sentinel (D6) — **Compliance:** #51 Dolibarr verifications (FEC/BlockedLog, startable today) — **P4:** #52 POC-3 reco+payments · #53 T05 client invoice (D3, ⚠️ July manual ~07-23) · #65 client-dossier ops (phase 1 ✅ 07-15) · #67 official-doc drafting skill (T18) — **P5:** #54 fiscal profile+calendar files+ADC register **✅ 2026-07-19** ([PR erp#71](https://gitea.arcodange.lab/arcodange-org/erp/pulls/71) merged = adc-001…005 Accepted by the operator's go; adc-006/007 stay Proposed → #53/#51) · #60 T11 reminder loop · #55 POC-4 TVA dry-runs — **Ops (post-replay):** #57 bucket C + document gaps (#56 ✅ 2026-07-18, PR erp#68 — authored by the Mistral builder bench) |
| [telegram-gateway](https://gitea.arcodange.lab/arcodange/telegram-gateway/issues) | #1 Postgres durable queue (D1) · #2 daily digest + approval cards |
| [factory](https://gitea.arcodange.lab/arcodange-org/factory/issues) | #22 ADRs as decisions close (D1/D2/D4/D6/D7) |
@@ -69,3 +69,12 @@ The bricks this PRD builds on, in the [erp](https://gitea.arcodange.lab/arcodang
| Date | PR | What shipped |
| --- | --- | --- |
| 2026-07-11 | [factory#21](https://gitea.arcodange.lab/arcodange-org/factory/pulls/21) | PRD authored: hub + task inventory + agent architecture + model fleet + challenges + POC plan + QA strategy. |
| 2026-07-18 | [erp#68](https://gitea.arcodange.lab/arcodange-org/erp/pulls/68) | #56 known-patterns fix — authored end-to-end by the Mistral runtime (`vibe -p`) under the builder bench; acceptance `bank match` clean (0 UNKNOWN). |
| 2026-07-18 | [erp#69](https://gitea.arcodange.lab/arcodange-org/erp/pulls/69) | #63 harness portability: `fleet/harness/` (verifier tests, `run-verifier.sh`, `vibe-builder.sh`) + parity/bench evidence — Mistral + Ornith admitted to verifier duty (blind-judged, 16/16 unanimous). |
| 2026-07-18 | [factory#31](https://gitea.arcodange.lab/arcodange-org/factory/pulls/31) | Cross-family verification rule codified in the [qa-strategy](qa-strategy.md#independent-verification--no-self-grading); STATUS truth-pass for #56/#63/#39. |
| 2026-07-19 | [erp#70](https://gitea.arcodange.lab/arcodange-org/erp/pulls/70) | #44 idempotency keys — replay is a no-op, proven live (historic manifest-B 5/5 deduped). |
| 2026-07-19 | [erp#71](https://gitea.arcodange.lab/arcodange-org/erp/pulls/71) | #54 fiscal profile + calendar + ADC register — merged under the operator's go: adc-001…005 Accepted. |
| 2026-07-19 | [erp#73](https://gitea.arcodange.lab/arcodange-org/erp/pulls/73) | #39 golden set — push gate released by the operator. |
| 2026-07-19 | [erp#74](https://gitea.arcodange.lab/arcodange-org/erp/pulls/74) | #40 invoice-extract atom — acceptance met (100 % criticals, 0 injection leaks). |
| 2026-07-19 | [erp#72](https://gitea.arcodange.lab/arcodange-org/erp/pulls/72) | #43 GED attach op — idempotent by (object, filename, sha256), rehearsed live (4 created → 4 deduped). |
| 2026-07-19 | this PR | STATUS truth-pass for #43/#44/#40/#54; entry points re-baselined. |
@@ -185,13 +185,13 @@ To be settled by POC evidence, each closing with a short ADR:
| # | Decision | Options (leaning) |
| --- | --- | --- |
| D1 | Work queue | telegram-gateway's planned Postgres durable queue (**leaning, operator-endorsed 2026-07** — already roadmapped, transactional, one less system) vs. flat files in git vs. Redis |
| D2 | Orchestration runtime | Claude Agent SDK headless for cluster-triggered jobs + **hermes** for M4-side lanes (**leaning** — hermes already runs skills + cron there) vs. bespoke TS orchestrator (erp `test/` Deno codebase) vs. pure CronJobs + scripts |
| D2 | Orchestration runtime | Claude Agent SDK headless for cluster-triggered jobs + **hermes** for M4-side lanes (**leaning** — hermes already runs skills + cron there) vs. bespoke TS orchestrator (erp `test/` Deno codebase) vs. pure CronJobs + scripts. **Operator direction 2026-07-15: the harness itself must be multi-runtime — Claude is an escalation tier, not a hard dependency; the same protocol must run on Mistral or on hermes + Ornith/MLX locally.** Verifier roles migrate first (bounded, read-only — and cross-family refutation is *stronger* verification than same-family); builder roles are benched on a scoped issue before trust ([model fleet harness portability](model-fleet.md#harness-portability)) |
| D3 | KM monthly invoice firing | enable Dolibarr template auto-fire (`frequency>0`) vs. agent-fired via sandbox+promote (**leaning** — keeps the gate + mention audit in-line) |
| D4 | PA — e-invoicing platform (*plateforme agréée*, ex-PDP) | **Leaning: Qonto** (operator direction, 2026-07 — the capital-deposit bank, DGFiP-registered PA, e-invoicing included in every plan, and the fleet's richest existing API integration); POC-6 validates reception + API pull before the ADR — **must close before 2026-09-01** ([C12](challenges.md#c12--e-invoicing-reform-unknowns)) |
| D5 | OCR provider for scanned docs | Mistral OCR (EU cloud) vs. local vision model on M4 vs. Tesseract baseline |
| D6 | Pi inference serving | llama.cpp server vs. Ollama on arm64, resource limits, node pinning ([C5](challenges.md#c5--slm-capability-ceiling-on-pi-hardware)) |
| D7 | Cluster↔vault access | git clone/pull of the SecondBrain remote (**leaning** — the Gitea remote exists, offline-friendly, reviewable) vs. tunneled Obsidian REST API (M4-only today) vs. keeping vault access M4-exclusive |
| D8 | Fleet code home | erp repo `fleet/` next to the skills (**leaning** — the atoms are ERP-domain today; revisit into a dedicated repo when a second domain joins) vs. dedicated fleet repo vs. scattered per existing repo |
| D8 | Fleet code home | **Settled 2026-07-15: erp repo `fleet/`** next to the skills — landed with [erp#62](https://gitea.arcodange.lab/arcodange-org/erp/pulls/62) (registry, 7 class skeletons, worked example, AGENTS.md Fleet section; locate-test passed by an independent cold reader). The atoms are ERP-domain today revisit into a dedicated repo when a second domain joins |
| D9 | Meeting capture tool (client-project notes lane) — **parked 2026-07-12, nice-to-have** (first client calls happen on the iPhone: a phone call precedes the Meet, which desktop capture doesn't cover; revisit when desktop meetings become routine) | **Leaning: Hyprnote free tier** (rebranded "Char" — local capture + transcription with **speaker diarization and Google Calendar sync both on the free plan**; manual trigger only, auto-record stays off by consent stance) vs. **Meetily** as OSS fallback (MIT, diarization in the community core, no calendar sync — `sb.py` can compensate by matching recording timestamps to the calendar ICS) vs. bare Whisper-class + Ornith |
D4D6 close with their mapped POCs ([POC-6](poc-plan.md#poc-6--e-invoicing-readiness-spike), [POC-5](poc-plan.md#poc-5--model-routing-bench), [POC-2](poc-plan.md#poc-2--pi-sentinel)); D1D2 are settled while building phase 3's standing fleet (the queue and scheduler *are* its skeleton); D3 lands with phase 4's money loops; D7 closes when the first cluster-side atom needs vault context (phase 3 at the earliest); D8 rides POC-1 — the first atoms need their home on day one; D9 is **parked** (nice-to-have; calls are iPhone-first today) — erp#49 carries the wake-up steps (gate: diarization quality on a real bilingual call).
D4D6 close with their mapped POCs ([POC-6](poc-plan.md#poc-6--e-invoicing-readiness-spike), [POC-5](poc-plan.md#poc-5--model-routing-bench), [POC-2](poc-plan.md#poc-2--pi-sentinel)); D1D2 are settled while building phase 3's standing fleet (the queue and scheduler *are* its skeleton); D3 lands with phase 4's money loops; D7 closes when the first cluster-side atom needs vault context (phase 3 at the earliest); D8 settled with the scaffold landing (erp#62, 2026-07-15); D9 is **parked** (nice-to-have; calls are iPhone-first today) — erp#49 carries the wake-up steps (gate: diarization quality on a real bilingual call).
+12
View File
@@ -44,6 +44,18 @@ The format guarantee never rests on the model:
…and regardless of tier, every payload passes the same deterministic validators downstream ([agent architecture](agent-architecture.md#atom-contract)). Constrained decoding guarantees *shape*; validators guarantee *truth conditions* (arithmetic, checksums, plausibility).
## Harness portability
The **atoms** above are multi-model by construction. The **harness** — the orchestration layer that executes backlog issues (builder sessions), verifies them (cold readers, locate-tests) and files PRs — ran its first full loop on Claude (erp#38 → PR erp#62, 2026-07-15). **Operator direction (2026-07-15): that layer must not have Anthropic as a hard dependency either — the same loop should run on Mistral, or on hermes + Ornith / MLX-served local models.**
The protocol was built for this: everything an executing agent needs lives in **files and issues** — AGENTS.md orientation, per-issue Execution footers (first command, done-means), acceptance tests defined in the issue itself, deterministic validators around every output. Nothing load-bearing lives in a vendor's context window. Any runtime that can read the forge and run a shell can attempt an issue; the acceptance gates don't care who built the thing.
Migration ladder (evidence-gated like everything else — erp#63):
1. **Verifier roles first** — locate-tests, cold-reader audits, refutation passes: bounded, read-only, cheap. Re-run the already-passed erp#38 locate-test on **Ornith** (hermes, `127.0.0.1:18080`) and on an **MLX-served candidate** (Qwen3 14B/30B-A3B, Mistral Small 3.x class); require verdict parity with the Claude run. Once parity holds, **prefer cross-family verification**: a different model family refuting the builder is stronger evidence than the builder's family agreeing with itself.
2. **Scoped builders benched** — one small, tightly-footered issue (a #56-class fix) attempted end-to-end by a Mistral-driven runtime against the unchanged acceptance gates; measure completion rate and intervention count.
3. **Claude stays the default** for multi-file builders, ambiguity and fiscal reasoning **until the bench says otherwise** — a routing-policy fact (complexity ceiling above), not an allegiance.
## Degraded modes
| Outage | Keeps working | Queues | Lost until recovery |
+2
View File
@@ -58,6 +58,8 @@ Per atom, mechanical, recorded in the registry ([ladder](README.md#the-autonomy-
Work is never attested by the session that produced it. **Milestone closures** ([closure protocol](STATUS.md#closure-protocol--per-milestone)), **POC exit gates**, and **autonomy promotions** are verified by a *context-free subagent prompted to refute* ("find why this is NOT done / NOT at the bar"), whose only inputs are the repo, the issues, and the run journals — never the author's conversation. A refutation the author cannot resolve with evidence blocks the gate; the verifier's verdict is attached to the artifact it gates (milestone, registry autonomy field, POC record). This extends to the process level the principle the pipelines already run at the data level (dual independent extraction, seeded-wrong fixtures that must FAIL) and that the PRD itself was built with (fresh-reader review before first publication).
**Cross-family verification.** The harness runs on more than one model family ([model-fleet harness portability](model-fleet.md#harness-portability)); a runtime is admitted to verifier duty by verdict parity with the Claude baseline on the two canonical verifier tests (locate-test + cold-reader backlog audit — [erp#63](https://gitea.arcodange.lab/arcodange-org/erp/issues/63), harness home `erp:fleet/harness/`). Once at least one non-Claude verifier is admitted, **the independent verifier SHOULD be a different model family than the builder** — a foreign family refuting the builder is stronger evidence than the builder's family agreeing with itself. Same-family verification stays acceptable when no admitted cross-family verifier fits the role, and the run journal records which family verified what.
## Evidence trail
Every month yields an audit pack: the coherence audit ([T15](task-inventory.md#t15--monthly-coherence-audit)), the month's run journals, snapshot content-hashes, approval-card decisions, and fiscal sheets — archived in git + GED. This pack is deliberately shaped as the documented-control set of the **piste d'audit fiable** (CGI art. 289 VII — [compliance](compliance.md#obligations--fleet-mechanisms)): the invoice ↔ service ↔ payment linkage is evidenced continuously, not reconstructed under audit. The pack is written for a third party (expert-comptable, auditor, or a future operator): it must let them reconstruct *what the fleet did and why* without access to this PRD or any chat history. A distilled summary of each pack also lands in the second brain ([T17](task-inventory.md#t17--knowledge-capture--retrieval-second-brain)), so institutional memory outlives both chat logs and this repo.
+1 -1
View File
@@ -251,5 +251,5 @@ Explicitly out of the current inventory; each becomes a task fiche when its trig
- **Expense reports / personal-account visibility** — movements on the personal CCA (`fk_account=3`) are API-invisible; a manual CSV import lane or a banking-app export would open T07 coverage.
- **Payroll & DSN** — dormant until the first salary is paid (see hub non-goals).
- **Prospection/CRM admin** — the `prospection` repo exists (its own PRD, daily pipeline, Mode A/B scoring); its admin loops (follow-ups, pipeline hygiene) and the conversion bridge (a Mode-B prospect becoming a Dolibarr thirdparty + proposal through the gated write path) reuse this fleet's patterns later. Audited 2026-07-11: Dolibarr's propal/contrat/projet modules are enabled but empty — proposals and contracts live outside the ERP today.
- **Contract lifecycle**record contracts in the ERP (the KM retainer terms exist only as WIP JSON today: $5,500/mo = $2,500 net-30 + $3,000 deferred +3 months — the deferred schedule is the source of truth T06 dunning needs), renewal reminders, obligation extraction (the KM 4 % new-business clause), signed originals in the GED. Needs write-skill ops for contacts/contracts/products (same extension pattern as the GED-attach issue).
- **Contract lifecycle**promoted to [erp#65](https://gitea.arcodange.lab/arcodange-org/erp/issues/65) (client-dossier write ops: **thirdparty update + contacts shipped 2026-07-15** — the KM dossier lives in the ERP with the FINAL contract terms; phase 2 = contract + services objects, product currency gated by adc-006) and [erp#67](https://gitea.arcodange.lab/arcodange-org/erp/issues/67) (**official-document drafting skill — T18 candidate**: bilingual FR/EN signable sets, deterministic legal checklist, human-gated e-signature dispatch, billing linkage so T05 reads the contract). The KM deferred schedule is now IN the ERP (FAC005/FAC007 validated, due 2026-08-23 & 2026-09-23 — what T06 dunning needs); renewal reminders + the 4 %-window obligation ride the compliance calendar (#54/#60).
- **Client delivery agents — the third family.** Agents working *on* client projects (the KM architecture notes in the vault are the embryo) share the [client dossiers](agent-architecture.md#knowledge-layer--the-second-brain) with this fleet: they deposit decisions, meeting notes (via a **local capture lane** — [D9](agent-architecture.md#open-decisions), **parked as nice-to-have 2026-07-12** (calls are iPhone-first today): Hyprnote free tier on the M4 — local transcription + speaker diarization + Google Calendar sync, manual trigger; Meetily as OSS fallback; markdown export → `sb.py` ingest matched to the calendar event → Ornith summary, per the vault doctrine — no cloud notetaker) and new-business sightings; they retrieve contract scope, contacts and billing state. Reuses T17 rails and the vault routing doctrine; REX at project close feeds `03-Resources` → prospection Mode B evidence → CMS case studies.