Retire le TTL des fiches (#8) et rend la KB lisible par un humain (#9) - #10
Conversation
Le champ imposait une péremption automatique que rien n'appliquait : aucun outil ne le lisait, aucune revue ne s'en servait. Il donnait une fausse impression de fraîcheur pilotée. - clé ttl_days retirée des 29 fiches active/**/*.json et des entrées d'index.json - KB-CONVENTIONS.md : champ retiré du schéma, règle de passage en `suspect` réécrite comme une décision de revue explicite, `validated` restant le marqueur de dernière vérification - deux fiches citaient ttl_days dans leur contenu (codex-models, splunk-cim-data-models) : phrases reformulées sans changer le fond Closes #8 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vh5PK8eE5U3PKNQ9tu8GxF
Une fiche JSON dont tout le corps est une chaîne échappée est illisible sur GitHub, et un changement de contenu apparaît en PR comme une unique ligne de plusieurs milliers de caractères. La KB gagne donc une projection Markdown, sans cesser d'être consommée en JSON. Le JSON sous active/ reste la source canonique : les repos consommateurs et le skill maxime-kb ne changent pas. index.json, index.md et md/ sont dérivés, jamais édités à la main. - tools/kb.py : convertisseur bidirectionnel (sync, sync --from md, check, validate), Python 3 stdlib seule. Frontmatter YAML restreint au schéma réel, parsable sans dépendance ; aller-retour sans perte, vérifié octet à octet sur les 29 fiches. - md/active/**.md : miroir généré, lisible et diffable. - index.json régénéré : il ne déclarait que 19 fiches sur 29, les 10 autres étaient invisibles pour le skill qui ne charge que l'index. - index.md devient un catalogue généré par thème ; sa prose de conventions, redondante et périmée (thèmes obsolètes), rejoint KB-CONVENTIONS.md. - fiches JSON recanonicalisées (indentation, ordre des clés, saut de ligne final) pour rendre la comparaison déterministe. - .github/workflows/kb-sync.yml : régénère et committe les fichiers dérivés à chaque push ; se rabat sur une vérification en lecture seule pour les PR de fork. - validate rejette explicitement ttl_days, pour que le champ retiré en #8 ne revienne pas par copier-coller. Closes #9 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vh5PK8eE5U3PKNQ9tu8GxF
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vh5PK8eE5U3PKNQ9tu8GxF
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ca4e5e5301
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| for rel in md_paths(): | ||
| if rel not in files: | ||
| (ROOT / rel).unlink() |
There was a problem hiding this comment.
Delete JSON orphans during Markdown-source sync
When sync --from md follows deletion or renaming of a Markdown fiche, the expected tree excludes the old fiche, but cleanup only traverses Markdown paths. The old canonical JSON therefore remains while the indexes are rewritten without it; the command exits successfully, the subsequent check fails, and a later default sync recreates the deleted Markdown fiche. Cleanup needs to remove orphaned JSON paths when Markdown is the selected source.
Useful? React with 👍 / 👎.
| else: | ||
| ids[fid] = rel | ||
| for rel, fiche in sorted(fiches.items()): | ||
| for link in fiche.get("links", []) or []: |
There was a problem hiding this comment.
Guard link traversal after recording a type error
When a malformed fiche supplies a truthy non-list value such as "links": 1, validate_fiche records the intended type error, but this loop immediately attempts to iterate the integer and raises an uncaught TypeError. Consequently validate, check, and sync emit a traceback instead of the actionable schema diagnostics; only traverse links after confirming the value is a list.
Useful? React with 👍 / 👎.
| # Une valeur doit être mise entre guillemets si elle est vide, porte une espace | ||
| # en tête/fin, contient un séparateur YAML (`: ` ou ` #`), ou commence par un | ||
| # caractère indicateur. | ||
| _NEEDS_QUOTES = re.compile(r"^$|^\s|\s$|:\s|\s#|^[-?:,\[\]{}#&*!|>'\"%@`]") |
There was a problem hiding this comment.
Quote multiline frontmatter scalars
A schema-valid string containing an internal newline, for example a multiline title or source, does not match this quoting expression unless whitespace also occurs at an endpoint. _dump_scalar consequently writes the newline directly into frontmatter, and the generated mirror cannot be parsed back (validate --from md reports the continuation as an unreadable line), violating the advertised lossless round trip. Quote values containing line breaks or other unsupported control characters.
Useful? React with 👍 / 👎.
index.json liste toutes les fiches, archivées comprises, pour qu'une fiche archivée reste trouvable sur demande explicite. Mais c'est aussi le seul fichier chargé systématiquement : si un consommateur ne filtre pas, une fiche archivée peut être resservie comme connaissance courante, et l'archivage devient cosmétique. Le filtre repose sur `status`, donc `status` ne doit jamais pouvoir diverger du dossier : - validate refuse une fiche dans archived/ dont le statut n'est pas `archived` ; - validate refuse une fiche marquée `archived` restée dans active/ — archiver, c'est la déplacer. - KB-CONVENTIONS.md documente explicitement le contrat : le consommateur filtre sur `status` ou sur le préfixe `archived/` du champ `path`. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Vh5PK8eE5U3PKNQ9tu8GxF
Traite les deux issues ouvertes, dans l'ordre : d'abord le TTL, puis le format.
#8 — Durée de vie
ttl_daysimposait une péremption automatique que rien n'appliquait : aucun outil ne le lisait, aucune revue ne s'en servait. Il donnait une fausse impression de fraîcheur pilotée.active/**/*.jsonet des entrées d'index.json;KB-CONVENTIONS.md: champ retiré du schéma, règle de passage ensuspectréécrite comme une décision de revue explicite —validatedreste le marqueur de dernière vérification ;ttl_daysdans leur texte (codex-models,splunk-cim-data-models) : phrases reformulées sans changer le fond ;kb.py validaterejette désormais le champ explicitement, pour qu'il ne revienne pas par copier-coller d'une ancienne fiche.Zéro occurrence de
ttldans le repo après ce changement.#9 — Format
Une fiche JSON dont tout le corps est une chaîne échappée est illisible sur GitHub, et une modification de contenu apparaît en PR comme une unique ligne de plusieurs milliers de caractères.
Deux arborescences commitées, une seule source de vérité. Le JSON sous
active/reste canonique : les repos consommateurs et le skillmaxime-kbne changent pas.md/,index.jsonetindex.mdsont dérivés et ne s'éditent jamais à la main.active/<thème>/<id>.jsonmd/active/<thème>/<id>.mdindex.jsonindex.mdtools/kb.pyCommandes :
sync(JSON → Markdown),sync --from md(le « vice versa » de l'issue),check(vérifie sans écrire),validate.L'aller-retour est sans perte, vérifié octet à octet sur les 29 fiches : reconstruire le JSON depuis le Markdown redonne exactement le JSON de départ. Le frontmatter est un sous-ensemble YAML restreint au schéma réel (scalaires texte et séquences de textes), ce qui permet de le parser sans dépendance tout en restant du YAML valide — GitHub l'affiche en tableau.
validatecontrôle la présence et le type des 14 attributs, les valeurs contrôlées,id= nom de fichier,theme= dossier parent, le format des dates, l'unicité desidet la résolution deslinks.Workflow
kb-syncIl ne se contente pas de vérifier : sur push, il régénère les index et le miroir et committe le résultat, pour qu'une modification de fiche n'oblige personne à lancer quoi que ce soit en local. Sur pull request depuis un fork, où pousser est impossible, il se rabat sur
checken lecture seule.Testé en conditions réelles sur une branche jetable : un commit modifiant un titre de fiche sans
synclocal a bien produit un commitgithub-actions[bot]mettant à jour exactement les 3 fichiers dérivés concernés, sans boucle de déclenchement.Points à connaître avant de relire
index.jsonne déclarait que 19 fiches sur 29. Les 10 autres étaient invisibles pour le skill, qui ne charge que ce que l'index déclare. Régénéré à 29 — c'est un correctif de fond, pas de la mise en forme.index.mdchange de rôle : il devient un catalogue généré. Sa prose de conventions était redondante avecKB-CONVENTIONS.mdet sa liste de thèmes périmée (elle citaitcoreapi, qui n'existe pas) ; elle a été fusionnée dans les conventions.checkdéterministe.md/générés — le code à relire tient danstools/kb.py,.github/workflows/kb-sync.ymletKB-CONVENTIONS.md.tmp/kb-sync-selftesta servi au test du workflow et reste à supprimer : le proxy git de la session renvoie 403 sur les suppressions de branche.Closes #8
Closes #9
Generated by Claude Code