0.0.2-alpha.4

This commit is contained in:
2026-09-28 22:42:48 +02:00
parent b9508b0228
commit 3f8c795cc0
34 changed files with 2108 additions and 249 deletions

View File

@@ -15,7 +15,7 @@ members = [
] ]
[workspace.package] [workspace.package]
version = "0.0.2-alpha.3.fix.1" version = "0.0.2-alpha.4"
edition = "2024" edition = "2024"
publish = false publish = false
repository = "https://git.sasedev.com/Sasedev/sasedev-knowledge" repository = "https://git.sasedev.com/Sasedev/sasedev-knowledge"

View File

@@ -1,5 +1,5 @@
<!-- file: README.md --> <!-- file: README.md -->
<!-- version: 13 --> <!-- version: 14 -->
# SaseDev Knowledge # SaseDev Knowledge
@@ -11,9 +11,9 @@ Le dépôt applicatif retenu est `sasedev-knowledge`. Le nom court du projet et
La version courante est définie par [`VERSION`](VERSION). La version courante est définie par [`VERSION`](VERSION).
`0.0.1` est la première stable de fondation de SaseDev Knowledge. `0.0.2-alpha.3` a démontré fonctionnellement le chemin Git générique de lecture, mais sa gate est `FAIL` sur hygiène/formatage/documentation de test. `0.0.2-alpha.3.fix.1` corrige ces défauts et enregistre un REPLAN de la release. `0.0.1` est la première stable de fondation de SaseDev Knowledge. `0.0.2-alpha.3.fix.1` ferme en `PASS` le chemin Git générique de lecture. `0.0.2-alpha.4` termine l'autonomie normative après l'adoption ponctuelle PGR `v0.1.3` et normalise les crate-roots bibliothèque comme façades.
`knowledge-git-lib` implémente désormais `knowledge-git-api::GitRepository` pour des sources physiques enregistrées : mirror contrôlé, refresh avec pruning, résolution d'une référence vers un commit et snapshot/worktree détaché adressé par révision. Les preuves fonctionnelles reposent sur des repositories Git temporaires locaux et n'exigent aucune API de forge. Avant le cas d'usage de synchronisation, `alpha.4` rendra la gouvernance Knowledge autonome après l'adoption PGR et auditera l'organisation interne des crates ; l'ancien scope de synchronisation devient `alpha.5`. `knowledge-git-lib` implémente `knowledge-git-api::GitRepository` pour des sources physiques enregistrées : mirror contrôlé, refresh avec pruning, résolution d'une référence vers un commit et snapshot/worktree détaché adressé par révision. `alpha.4` ne change pas cette sémantique. Les règles nécessaires au développement courant sont désormais possédées localement sous `docs/rules/`, et les futurs prompts Knowledge ne chargent pas PGR sauf réévaluation explicitement engagée. Le cas d'usage de synchronisation reste réservé à `alpha.5`.
## Topologie produit de fondation ## Topologie produit de fondation
@@ -69,6 +69,9 @@ Le runtime exige un bind configuré par launcher et l'une des deux sources d'ass
- [`docs/objectives/001-PROJECT_OBJECTIVES.md`](docs/objectives/001-PROJECT_OBJECTIVES.md) — objectifs et non-objectifs ; - [`docs/objectives/001-PROJECT_OBJECTIVES.md`](docs/objectives/001-PROJECT_OBJECTIVES.md) — objectifs et non-objectifs ;
- [`docs/architecture/001-PROJECT_PROFILE.md`](docs/architecture/001-PROJECT_PROFILE.md) — baseline PGR, profils/skeletons et matrice de décisions ; - [`docs/architecture/001-PROJECT_PROFILE.md`](docs/architecture/001-PROJECT_PROFILE.md) — baseline PGR, profils/skeletons et matrice de décisions ;
- [`docs/architecture/002-KNOWLEDGE_ARCHITECTURE.md`](docs/architecture/002-KNOWLEDGE_ARCHITECTURE.md) — architecture de fondation multi-app Git/forge/PostgreSQL et frontières de contenu ; - [`docs/architecture/002-KNOWLEDGE_ARCHITECTURE.md`](docs/architecture/002-KNOWLEDGE_ARCHITECTURE.md) — architecture de fondation multi-app Git/forge/PostgreSQL et frontières de contenu ;
- [`docs/architecture/003-PGR_ADOPTION_MAP.md`](docs/architecture/003-PGR_ADOPTION_MAP.md) — mapping final de l'adoption PGR `v0.1.3` vers les owners locaux Knowledge ;
- [`docs/rules/000-README.md`](docs/rules/000-README.md) — index des règles normatives locales autonomes ;
- [`docs/templates/001-NEW_SESSION_PROMPT.md`](docs/templates/001-NEW_SESSION_PROMPT.md) — pattern de reprise d'une future session sans consultation PGR automatique ;
- [`docs/studies/001-AUTH_ADMIN_CORPUS_STUDY.md`](docs/studies/001-AUTH_ADMIN_CORPUS_STUDY.md) — étude des deux corpus historiques auth/admin et décisions de réutilisation conceptuelle ; - [`docs/studies/001-AUTH_ADMIN_CORPUS_STUDY.md`](docs/studies/001-AUTH_ADMIN_CORPUS_STUDY.md) — étude des deux corpus historiques auth/admin et décisions de réutilisation conceptuelle ;
- [`docs/studies/002-ACTIX_MAUD_VITE_CORPUS_STUDY.md`](docs/studies/002-ACTIX_MAUD_VITE_CORPUS_STUDY.md) — étude ciblée du pattern Vite manifest / Actix / Maud à adapter pour Knowledge ; - [`docs/studies/002-ACTIX_MAUD_VITE_CORPUS_STUDY.md`](docs/studies/002-ACTIX_MAUD_VITE_CORPUS_STUDY.md) — étude ciblée du pattern Vite manifest / Actix / Maud à adapter pour Knowledge ;
- [`docs/studies/003-V0_0_1_FOUNDATION_RECONCILIATION.md`](docs/studies/003-V0_0_1_FOUNDATION_RECONCILIATION.md) — réconciliation `beta.1`, état matérialisé, DEFER conservés et revue d'horizon ; - [`docs/studies/003-V0_0_1_FOUNDATION_RECONCILIATION.md`](docs/studies/003-V0_0_1_FOUNDATION_RECONCILIATION.md) — réconciliation `beta.1`, état matérialisé, DEFER conservés et revue d'horizon ;

View File

@@ -1,5 +1,5 @@
<!-- file: RULES.md --> <!-- file: RULES.md -->
<!-- version: 13 --> <!-- version: 14 -->
# Règles SaseDev Knowledge # Règles SaseDev Knowledge
@@ -29,31 +29,18 @@ Une future version de PGR n'a aucun effet automatique sur Knowledge. Elle n'est
`0.0.2-alpha.4` est la tranche de réconciliation qui doit terminer l'autonomie normative de l'adoption `v0.1.3` : inventorier les owners réellement retenus, vérifier où chaque contrat nécessaire est possédé localement, adapter les règles/templates/audits manquants sans recopier mécaniquement l'arborescence PGR et supprimer les références externes nécessaires à la compréhension courante du projet. `0.0.2-alpha.4` est la tranche de réconciliation qui doit terminer l'autonomie normative de l'adoption `v0.1.3` : inventorier les owners réellement retenus, vérifier où chaque contrat nécessaire est possédé localement, adapter les règles/templates/audits manquants sans recopier mécaniquement l'arborescence PGR et supprimer les références externes nécessaires à la compréhension courante du projet.
## Owners PGR applicables ## Owners normatifs locaux
La fondation retient les owners suivants dans leur scope réel : Le développement courant est gouverné par les owners Knowledge suivants :
```text - [`docs/rules/200-GOVERNANCE.md`](docs/rules/200-GOVERNANCE.md) — baseline, autonomie et décisions ;
200 gouvernance et lifecycle - [`docs/rules/210-WORKFLOW.md`](docs/rules/210-WORKFLOW.md) — plan/delta/history/fix/handoff ;
210 workflow plan/delta/history/handoff - [`docs/rules/300-DOCUMENTATION.md`](docs/rules/300-DOCUMENTATION.md) — structure documentaire, headers et prompts ;
220 composition des skeletons pendant l'instanciation - [`docs/rules/400-VALIDATION.md`](docs/rules/400-VALIDATION.md) — preuves proportionnées et autorité opérateur ;
230 adoption d'une nouvelle baseline PGR par un projet existant - [`docs/rules/510-RUST_CARGO.md`](docs/rules/510-RUST_CARGO.md) — Rust/Cargo strict, façade crate-root et tests ;
300 documentation - [`docs/rules/530-WEB_FRONTEND.md`](docs/rules/530-WEB_FRONTEND.md) — TypeScript/npm/Vite/Sass/Bootstrap/Maud.
400 validation proportionnée
500 famille langage/écosystème
510 Rust/Cargo
530 TypeScript
540 écosystème de packages JavaScript
550 Vite lorsque Vite est sélectionné
560 CSS/Sass
700 famille framework pour les frameworks réellement utilisés
```
Les skeletons `001-PROJECT_GOVERNANCE_FOUNDATION`, `002-RUST_CARGO_WORKSPACE` et `003-WEB_FRONTEND` documentent la provenance de composition de l'état existant. Ils ne sont pas des dépendances documentaires à relire pour développer Knowledge. `alpha.4` doit vérifier que les responsabilités effectivement retenues sont possédées localement avant de considérer l'adoption `v0.1.3` comme complètement matérialisée. Le mapping complet de provenance et de décisions `ADOPT / KEEP-LOCAL / OVERRIDE / DEFER` est conservé dans [`docs/architecture/003-PGR_ADOPTION_MAP.md`](docs/architecture/003-PGR_ADOPTION_MAP.md). Les owners PGR non matérialisés localement ne sont pas des dépendances documentaires du développement quotidien.
Le profil `710-TAURI` reste `DEFER` / non applicable au produit Web actuel. Aucun skeleton Tauri n'est adopté.
Les owners Java/Maven/Gradle réorganisés en PGR `0.1.2`, le profil Android réévalué en `0.1.3` et les autres technologies absentes du projet restent hors scope.
## Priorité et décisions locales ## Priorité et décisions locales
@@ -188,7 +175,7 @@ Le package manager sélectionné est npm. Le fichier `package-lock.json` produit
Le package utilise TypeScript strict, Vite, Sass et Bootstrap. Bootstrap est un choix local Knowledge ; il ne devient pas une règle PGR universelle. Le package utilise TypeScript strict, Vite, Sass et Bootstrap. Bootstrap est un choix local Knowledge ; il ne devient pas une règle PGR universelle.
Le skeleton Web PGR `003-WEB_FRONTEND` et sa validation associée sont obligatoires pour `0.0.1`. Le frontend contrôlé doit utiliser la chaîne réellement sélectionnée TypeScript + Vite + Sass + Bootstrap pour valider indépendamment du backend les assets, comportements client et templates statiques de référence. Le contrat Web courant est possédé par [`docs/rules/530-WEB_FRONTEND.md`](docs/rules/530-WEB_FRONTEND.md). Le frontend contrôlé utilise la chaîne réellement sélectionnée TypeScript + Vite + Sass + Bootstrap pour valider indépendamment du backend les assets, comportements client et templates statiques de référence.
Les templates statiques servent de support de conception, prévisualisation et validation navigateur. Ils MUST NOT devenir silencieusement une seconde implémentation runtime divergente : le HTML servi en production par les applications Actix est rendu avec Maud, et toute adaptation depuis le template de référence doit préserver explicitement les contrats utiles de structure, classes, attributs et assets. Les templates statiques servent de support de conception, prévisualisation et validation navigateur. Ils MUST NOT devenir silencieusement une seconde implémentation runtime divergente : le HTML servi en production par les applications Actix est rendu avec Maud, et toute adaptation depuis le template de référence doit préserver explicitement les contrats utiles de structure, classes, attributs et assets.
@@ -196,7 +183,7 @@ Le build Vite de production MUST produire un mapping machine-readable des entré
Le pattern de loader observé dans `actix-auth-app` est un corpus d’inspiration. Sa reprise doit être réévaluée selon les règles Rust Knowledge : pas de `panic!`/`unwrap`/`expect`, erreurs récupérables, API minimale, tests ciblés et séparation claire entre debug/dev et production. Le pattern de loader observé dans `actix-auth-app` est un corpus d’inspiration. Sa reprise doit être réévaluée selon les règles Rust Knowledge : pas de `panic!`/`unwrap`/`expect`, erreurs récupérables, API minimale, tests ciblés et séparation claire entre debug/dev et production.
`knowledge-web-lib` possède ce contrat partagé à partir d'`alpha.5`. En développement, `KNOWLEDGE_VITE_DEV_ORIGIN` MUST fournir l'origin du dev server et le renderer charge `@vite/client` puis `src/main.ts`. En production, `KNOWLEDGE_VITE_MANIFEST_PATH` MUST désigner le manifest généré et les noms hashés sont résolus depuis l'entrée stable `src/main.ts`. `KNOWLEDGE_ASSET_BASE_PATH` MAY remplacer le préfixe de production `/`. `knowledge-web-lib` possède ce contrat partagé depuis la fondation `0.0.1`. En développement, `KNOWLEDGE_VITE_DEV_ORIGIN` MUST fournir l'origin du dev server et le renderer charge `@vite/client` puis `src/main.ts`. En production, `KNOWLEDGE_VITE_MANIFEST_PATH` MUST désigner le manifest généré et les noms hashés sont résolus depuis l'entrée stable `src/main.ts`. `KNOWLEDGE_ASSET_BASE_PATH` MAY remplacer le préfixe de production `/`.
Les trois launchers MUST recevoir leur socket de bind par configuration (`KNOWLEDGE_PGR_BIND_ADDRESS`, `KNOWLEDGE_HOWTOS_BIND_ADDRESS`, `KNOWLEDGE_SNIPPETS_BIND_ADDRESS`). Aucun port de déploiement n'est choisi par le code. Les seules routes matérialisées par la fondation sont `/` et `/healthz`; cela ne fixe aucune convention future pour l'authentification ou l'administration. Les trois launchers MUST recevoir leur socket de bind par configuration (`KNOWLEDGE_PGR_BIND_ADDRESS`, `KNOWLEDGE_HOWTOS_BIND_ADDRESS`, `KNOWLEDGE_SNIPPETS_BIND_ADDRESS`). Aucun port de déploiement n'est choisi par le code. Les seules routes matérialisées par la fondation sont `/` et `/healthz`; cela ne fixe aucune convention future pour l'authentification ou l'administration.
@@ -204,9 +191,7 @@ Les trois launchers MUST recevoir leur socket de bind par configuration (`KNOWLE
### Politique `Cargo.lock` ### Politique `Cargo.lock`
PGR `v0.1.1` exige une décision explicite de lockfile selon le type de produit et le besoin de reproductibilité ; il n'impose pas universellement le versionnement de `Cargo.lock`. Knowledge possède localement la politique de lockfile suivante :
Knowledge sélectionne localement la politique suivante :
```text ```text
Cargo.lock généré localement par Cargo Cargo.lock généré localement par Cargo
@@ -220,7 +205,7 @@ Cette décision ne s'applique pas au frontend npm : `Web/knowledge-template-lab/
### Layout des tests ### Layout des tests
Knowledge sélectionne localement la convention `unit_tests/` séparée que PGR `0.1.1` autorise sans l'imposer globalement. Knowledge sélectionne localement la convention `unit_tests/` séparée.
Pour toutes les crates Rust de ce workspace : Pour toutes les crates Rust de ce workspace :
@@ -239,17 +224,15 @@ Exemple :
mod tests; mod tests;
``` ```
Cette convention locale est plus stricte que le `MAY` générique de PGR, mais reste conforme à celui-ci. Si PGR doit l'imposer à tous les futurs workspaces, cette évolution appartient à une version ultérieure du référentiel PGR et non à Knowledge.
Le préfixe de crate retenu est `knowledge-`. Le préfixe de crate retenu est `knowledge-`.
Les responsabilités candidates sont documentées dans l'architecture. Une crate n'est matérialisée que lorsqu'elle possède une responsabilité réelle. Le suffixe `-api` n'est utilisé que pour une frontière passive dont des implémentations distinctes/remplaçables sont réellement prévues. Les responsabilités candidates sont documentées dans l'architecture. Une crate n'est matérialisée que lorsqu'elle possède une responsabilité réelle. Le suffixe `-api` n'est utilisé que pour une frontière passive dont des implémentations distinctes/remplaçables sont réellement prévues.
`alpha.3` matérialise ainsi `knowledge-git-api` pour la frontière `GitRepository` et `knowledge-sync-api` pour la frontière `RepositoryEventSource`. Ces crates restent passives, sans runtime ni logging propre, et dépendent seulement des types de domaine nécessaires. Les implémentations Git, hooks, polling, webhooks ou forge restent hors de ces crates de contrat. `alpha.3` matérialise ainsi `knowledge-git-api` pour la frontière `GitRepository` et `knowledge-sync-api` pour la frontière `RepositoryEventSource`. Ces crates restent passives, sans runtime ni logging propre, et dépendent seulement des types de domaine nécessaires. Les implémentations Git, hooks, polling, webhooks ou forge restent hors de ces crates de contrat.
Le contrat Rust strict retenu par Knowledge s'applique aux crates matérialisées, notamment Rust 2024, `unsafe` interdit par défaut, lints stricts, exports publics maîtrisés et chemins intra-crate explicites via la façade crate-root. `alpha.4` doit vérifier que l'ensemble des obligations réellement nécessaires de ce contrat est possédé localement sans devoir relire PGR. Le contrat Rust strict est possédé par [`docs/rules/510-RUST_CARGO.md`](docs/rules/510-RUST_CARGO.md). Pour toutes les crates bibliothèque, `src/lib.rs` reste une façade de documentation, modules et réexports ; les définitions de production résident dans des modules nommés selon leur responsabilité. Les crates `knowledge-git-api` et `knowledge-sync-api` appliquent ce contrat à partir de `0.0.2-alpha.4` sans changer leur API crate-root.
Les audits read-only sélectionnés et possédés localement avec les premiers contrats publics sont `audit_rust_blank_lines.py`, `audit_rust_item_spacing.py`, `audit_rust_module_order.py`, `audit_rust_trait_import_blocks.py`, `audit_rust_reexport_blocks.py` et `audit_rust_export_completeness.py`. L'audit `const` n'est pas sélectionné globalement : il reste opt-in par fichier lorsqu'un ordre mécanique de constantes est réellement approprié. Les audits Rust read-only possédés localement incluent `audit_rust_blank_lines.py`, `audit_rust_item_spacing.py`, `audit_rust_module_order.py`, `audit_rust_trait_import_blocks.py`, `audit_rust_reexport_blocks.py`, `audit_rust_crate_root_facades.py` et `audit_rust_export_completeness.py`. L'audit `const` n'est pas sélectionné globalement : il reste opt-in uniquement si un ordre mécanique de constantes devient réellement approprié.
## Secrets et configuration locale ## Secrets et configuration locale

View File

@@ -1 +1 @@
0.0.2-alpha.3.fix.1 0.0.2-alpha.4

View File

@@ -1,84 +1,24 @@
// file: crates/knowledge-git-api/src/lib.rs // file: crates/knowledge-git-api/src/lib.rs
// version: 3 // version: 4
//! Provider-neutral contracts for Git-backed Knowledge sources. //! Provider-neutral contracts for Git-backed Knowledge sources.
//! //!
//! This crate deliberately contains no forge API, process runner, filesystem checkout or database //! This crate deliberately contains no forge API, process runner, filesystem checkout or database
//! implementation. Concrete Git backends depend on this contract, not the reverse. //! implementation. Concrete Git backends depend on this contract, not the reverse.
mod reference;
mod repository;
mod revision;
mod snapshot;
/// Opaque Git reference requested by a caller, such as a branch, tag or object expression. /// Opaque Git reference requested by a caller, such as a branch, tag or object expression.
#[derive(Clone, Debug, Eq, Hash, PartialEq)] pub use self::reference::GitReference;
pub struct GitReference(String);
impl crate::GitReference {
/// Create an opaque Git reference without imposing one provider's reference grammar.
pub fn new(value: &str) -> crate::GitReference {
return crate::GitReference(value.to_owned());
}
/// Return the reference text.
pub fn as_str(&self) -> &str {
return self.0.as_str();
}
}
/// Resolved authoritative Git revision identity.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct GitRevision(String);
impl crate::GitRevision {
/// Create a revision identity returned by a concrete Git implementation.
pub fn new(value: &str) -> crate::GitRevision {
return crate::GitRevision(value.to_owned());
}
/// Return the revision identity as text.
pub fn as_str(&self) -> &str {
return self.0.as_str();
}
}
/// Read-only local materialization of one authoritative Git revision.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GitSnapshot {
path: std::path::PathBuf,
revision: crate::GitRevision,
}
impl crate::GitSnapshot {
/// Build a snapshot contract from a resolved revision and its local read root.
pub fn new(revision: crate::GitRevision, path: std::path::PathBuf) -> crate::GitSnapshot {
return crate::GitSnapshot { path, revision };
}
/// Return the local root containing the materialized repository content.
pub fn path(&self) -> &std::path::Path {
return self.path.as_path();
}
/// Return the authoritative revision represented by the snapshot.
pub fn revision(&self) -> &crate::GitRevision {
return &self.revision;
}
}
/// Provider-neutral operations required from a Git repository backend. /// Provider-neutral operations required from a Git repository backend.
/// pub use self::repository::GitRepository;
/// Implementations may use a local Git executable, a Rust Git library or another generic Git /// Resolved authoritative Git revision identity.
/// mechanism. Forge-only capabilities do not belong to this trait. pub use self::revision::GitRevision;
pub trait GitRepository { /// Read-only local materialization of one authoritative Git revision.
/// Implementation-specific recoverable error. pub use self::snapshot::GitSnapshot;
type Error;
/// Refresh the local view of one configured source when the backend requires it.
fn refresh(&mut self, source_id: &knowledge_domain_lib::SourceId) -> Result<(), Self::Error>;
/// Resolve one opaque reference to the authoritative revision used by synchronization.
fn resolve_revision(&self, source_id: &knowledge_domain_lib::SourceId, reference: &crate::GitReference) -> Result<crate::GitRevision, Self::Error>;
/// Prepare or validate a read-only local snapshot for one resolved revision.
fn prepare_snapshot(&self, source_id: &knowledge_domain_lib::SourceId, revision: &crate::GitRevision) -> Result<crate::GitSnapshot, Self::Error>;
}
#[cfg(test)] #[cfg(test)]
#[path = "../unit_tests/lib.rs"] #[path = "../unit_tests/lib.rs"]

View File

@@ -0,0 +1,18 @@
// file: crates/knowledge-git-api/src/reference.rs
// version: 1
/// Opaque Git reference requested by a caller, such as a branch, tag or object expression.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct GitReference(String);
impl crate::GitReference {
/// Create an opaque Git reference without imposing one provider's reference grammar.
pub fn new(value: &str) -> crate::GitReference {
return crate::GitReference(value.to_owned());
}
/// Return the reference text.
pub fn as_str(&self) -> &str {
return self.0.as_str();
}
}

View File

@@ -0,0 +1,20 @@
// file: crates/knowledge-git-api/src/repository.rs
// version: 1
/// Provider-neutral operations required from a Git repository backend.
///
/// Implementations may use a local Git executable, a Rust Git library or another generic Git
/// mechanism. Forge-only capabilities do not belong to this trait.
pub trait GitRepository {
/// Implementation-specific recoverable error.
type Error;
/// Refresh the local view of one configured source when the backend requires it.
fn refresh(&mut self, source_id: &knowledge_domain_lib::SourceId) -> Result<(), Self::Error>;
/// Resolve one opaque reference to the authoritative revision used by synchronization.
fn resolve_revision(&self, source_id: &knowledge_domain_lib::SourceId, reference: &crate::GitReference) -> Result<crate::GitRevision, Self::Error>;
/// Prepare or validate a read-only local snapshot for one resolved revision.
fn prepare_snapshot(&self, source_id: &knowledge_domain_lib::SourceId, revision: &crate::GitRevision) -> Result<crate::GitSnapshot, Self::Error>;
}

View File

@@ -0,0 +1,18 @@
// file: crates/knowledge-git-api/src/revision.rs
// version: 1
/// Resolved authoritative Git revision identity.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct GitRevision(String);
impl crate::GitRevision {
/// Create a revision identity returned by a concrete Git implementation.
pub fn new(value: &str) -> crate::GitRevision {
return crate::GitRevision(value.to_owned());
}
/// Return the revision identity as text.
pub fn as_str(&self) -> &str {
return self.0.as_str();
}
}

View File

@@ -0,0 +1,26 @@
// file: crates/knowledge-git-api/src/snapshot.rs
// version: 1
/// Read-only local materialization of one authoritative Git revision.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct GitSnapshot {
path: std::path::PathBuf,
revision: crate::GitRevision,
}
impl crate::GitSnapshot {
/// Build a snapshot contract from a resolved revision and its local read root.
pub fn new(revision: crate::GitRevision, path: std::path::PathBuf) -> crate::GitSnapshot {
return crate::GitSnapshot { path, revision };
}
/// Return the local root containing the materialized repository content.
pub fn path(&self) -> &std::path::Path {
return self.path.as_path();
}
/// Return the authoritative revision represented by the snapshot.
pub fn revision(&self) -> &crate::GitRevision {
return &self.revision;
}
}

View File

@@ -0,0 +1,14 @@
// file: crates/knowledge-sync-api/src/event_source.rs
// version: 1
/// Producer of synchronization signals.
///
/// Concrete implementations may represent explicit queues, polling, hooks, webhooks or other
/// event mechanisms. The scheduling/runtime model remains outside this passive contract.
pub trait RepositoryEventSource {
/// Implementation-specific recoverable error.
type Error;
/// Return the next available signal, or `None` when no signal is currently available.
fn next_signal(&mut self) -> Result<Option<crate::RepositorySyncSignal>, Self::Error>;
}

View File

@@ -1,57 +1,20 @@
// file: crates/knowledge-sync-api/src/lib.rs // file: crates/knowledge-sync-api/src/lib.rs
// version: 2 // version: 3
//! Contracts for provider-neutral repository synchronization signals. //! Contracts for provider-neutral repository synchronization signals.
//! //!
//! A signal requests reconciliation of a source. It is not authoritative content and does not //! A signal requests reconciliation of a source. It is not authoritative content and does not
//! replace resolution of the target Git revision by the Git repository contract. //! replace resolution of the target Git revision by the Git repository contract.
/// Coarse origin of a synchronization request. mod event_source;
#[derive(Clone, Copy, Debug, Eq, PartialEq)] mod signal;
pub enum RepositorySyncCause {
/// An explicit request from an operator or application use case.
Explicit,
/// A periodic reconciliation independent of external hooks.
Periodic,
/// A non-authoritative external signal such as a Git hook, webhook or filesystem watcher.
ExternalSignal,
}
/// Request to reconcile one logical content source.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RepositorySyncSignal {
source_id: knowledge_domain_lib::SourceId,
cause: crate::RepositorySyncCause,
}
impl crate::RepositorySyncSignal {
/// Build a synchronization signal for one source.
pub fn new(source_id: knowledge_domain_lib::SourceId, cause: crate::RepositorySyncCause) -> crate::RepositorySyncSignal {
return crate::RepositorySyncSignal { source_id, cause };
}
/// Return the source that must be reconciled.
pub fn source_id(&self) -> &knowledge_domain_lib::SourceId {
return &self.source_id;
}
/// Return the coarse trigger origin.
pub fn cause(&self) -> crate::RepositorySyncCause {
return self.cause;
}
}
/// Producer of synchronization signals. /// Producer of synchronization signals.
/// pub use self::event_source::RepositoryEventSource;
/// Concrete implementations may represent explicit queues, polling, hooks, webhooks or other /// Coarse origin of a synchronization request.
/// event mechanisms. The scheduling/runtime model remains outside this passive contract. pub use self::signal::RepositorySyncCause;
pub trait RepositoryEventSource { /// Request to reconcile one logical content source.
/// Implementation-specific recoverable error. pub use self::signal::RepositorySyncSignal;
type Error;
/// Return the next available signal, or `None` when no signal is currently available.
fn next_signal(&mut self) -> Result<Option<crate::RepositorySyncSignal>, Self::Error>;
}
#[cfg(test)] #[cfg(test)]
#[path = "../unit_tests/lib.rs"] #[path = "../unit_tests/lib.rs"]

View File

@@ -0,0 +1,37 @@
// file: crates/knowledge-sync-api/src/signal.rs
// version: 1
/// Coarse origin of a synchronization request.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RepositorySyncCause {
/// An explicit request from an operator or application use case.
Explicit,
/// A periodic reconciliation independent of external hooks.
Periodic,
/// A non-authoritative external signal such as a Git hook, webhook or filesystem watcher.
ExternalSignal,
}
/// Request to reconcile one logical content source.
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct RepositorySyncSignal {
source_id: knowledge_domain_lib::SourceId,
cause: crate::RepositorySyncCause,
}
impl crate::RepositorySyncSignal {
/// Build a synchronization signal for one source.
pub fn new(source_id: knowledge_domain_lib::SourceId, cause: crate::RepositorySyncCause) -> crate::RepositorySyncSignal {
return crate::RepositorySyncSignal { source_id, cause };
}
/// Return the source that must be reconciled.
pub fn source_id(&self) -> &knowledge_domain_lib::SourceId {
return &self.source_id;
}
/// Return the coarse trigger origin.
pub fn cause(&self) -> crate::RepositorySyncCause {
return self.cause;
}
}

283
deltas/0.0.2/alpha.4.md Normal file
View File

@@ -0,0 +1,283 @@
<!-- file: deltas/0.0.2/alpha.4.md -->
<!-- version: 1 -->
# Delta 0.0.2-alpha.4 — autonomie normative et façades de crates
## Base requise
Partir de `0.0.2-alpha.3.fix.1` après application de son history `PASS`, commit et push :
```text
history/0.0.2/alpha.3.fix.1.md PASS
```
La version devient :
```text
0.0.2-alpha.4
```
Les deltas, histories et prompts historiques ne doivent pas être réécrits.
## Mission
Fermer l'adoption PGR `v0.1.3` comme migration ponctuelle : Knowledge doit désormais posséder localement les règles, patterns et audits réellement nécessaires à son développement quotidien et ne plus devoir charger PGR au début d'une version, d'une session ou d'une tranche.
La même tranche normalise les crate-roots bibliothèque comme façades sans changer les APIs publiques ni la sémantique Git validée en `alpha.3`.
## Scope documentaire et gouvernance
Créer les owners locaux :
```text
docs/rules/000-README.md
docs/rules/200-GOVERNANCE.md
docs/rules/210-WORKFLOW.md
docs/rules/300-DOCUMENTATION.md
docs/rules/400-VALIDATION.md
docs/rules/510-RUST_CARGO.md
docs/rules/530-WEB_FRONTEND.md
```
Créer le mapping de provenance :
```text
docs/architecture/003-PGR_ADOPTION_MAP.md
```
Le mapping sélectionne et adapte uniquement ce qui est utile : gouvernance, workflow, documentation, validation, Rust/Cargo et contrats Web. Les owners locaux doivent être suffisamment complets pour retrouver sans PGR le lifecycle/versioning, les fixes/REPLAN, les contrats delta/history/handoff, les rôles documentaires et les catégories de preuve. Les meta-owners de skeleton/framework restent historiques ou locaux lorsqu'un document séparé n'apporte pas de valeur.
PGR `v0.1.3` reste mentionné uniquement comme source d'adoption. Une future version PGR n'a aucun effet automatique.
## Templates locaux
Créer :
```text
docs/templates/001-NEW_SESSION_PROMPT.md
docs/templates/002-RELEASE_PLAN.md
docs/templates/003-OPERATOR_HANDOFF.md
docs/templates/004-RUST_LIBRARY_CRATE.md
```
Le template de nouvelle session doit partir de la stable Knowledge et ne doit pas demander de rechercher une stable PGR, sauf adoption externe explicitement inscrite au scope.
## Audits localement possédés
Adopter et adapter les audits Markdown génériques nécessaires :
```text
scripts/audit_markdown_headers.py
scripts/audit_markdown_links.py
scripts/audit_markdown_tables.py
```
Ils ignorent les arbres générés usuels, y compris `builds`, `node_modules`, `target` et `.git`.
Ajouter :
```text
scripts/audit_rust_crate_root_facades.py
```
Cet audit read-only vérifie que les `src/lib.rs` des crates bibliothèque ne contiennent pas de définitions top-level de production.
## Structure des crates
`knowledge-git-api` devient :
```text
src/lib.rs
src/reference.rs
src/repository.rs
src/revision.rs
src/snapshot.rs
```
`knowledge-sync-api` devient :
```text
src/lib.rs
src/event_source.rs
src/signal.rs
```
Les noms publics crate-root restent strictement les mêmes. Aucun consommateur ne doit dépendre des modules propriétaires privés.
Les autres crates bibliothèque sont auditées. `knowledge-domain-lib`, `knowledge-git-lib` et `knowledge-web-lib` respectent déjà le contrat et ne sont pas découpées davantage sans besoin réel.
## Hors scope
Cette tranche ne doit pas :
- charger ou adopter une version PGR postérieure à `v0.1.3` ;
- recopier toute l'arborescence PGR ;
- modifier le comportement de `knowledge-git-lib` ;
- changer l'API publique crate-root des contrats Git/sync ;
- modifier `Web/` ;
- ajouter `knowledge-app-lib`, PostgreSQL, forge, auth/admin ou scheduler ;
- implémenter le cas d'usage `Changed` / `Unchanged`, réservé à `alpha.5`.
## Gate opérateur
Exécuter depuis la racine après application du delta :
```bash
test "$(cat VERSION)" = '0.0.2-alpha.4'
grep -F 'version = "0.0.2-alpha.4"' Cargo.toml
grep -A2 '^## Statut$' history/0.0.2/alpha.3.fix.1.md | grep -Fx 'PASS'
git diff --check
python3 -B scripts/audit_markdown_headers.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts deltas history
python3 -B scripts/audit_markdown_links.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts deltas history
python3 -B scripts/audit_markdown_tables.py README.md RULES.md ROADMAP.md CHANGELOG.md docs prompts deltas history
python3 - <<'PY'
from pathlib import Path
import tomllib
required = (
"docs/rules/200-GOVERNANCE.md",
"docs/rules/210-WORKFLOW.md",
"docs/rules/300-DOCUMENTATION.md",
"docs/rules/400-VALIDATION.md",
"docs/rules/510-RUST_CARGO.md",
"docs/rules/530-WEB_FRONTEND.md",
"docs/architecture/003-PGR_ADOPTION_MAP.md",
"docs/templates/001-NEW_SESSION_PROMPT.md",
"docs/templates/002-RELEASE_PLAN.md",
"docs/templates/003-OPERATOR_HANDOFF.md",
"docs/templates/004-RUST_LIBRARY_CRATE.md",
"scripts/audit_markdown_headers.py",
"scripts/audit_markdown_links.py",
"scripts/audit_markdown_tables.py",
"scripts/audit_rust_crate_root_facades.py",
)
for value in required:
assert Path(value).is_file(), value
rules = Path("RULES.md").read_text(encoding="utf-8")
assert "Owners normatifs locaux" in rules
assert "Une future version de PGR n'a aucun effet automatique sur Knowledge" in rules
assert "baseline PGR courante" not in rules
owner_contracts = {
"docs/rules/200-GOVERNANCE.md": (
"X.Y.Z-alpha.N.fix.M",
"CONTINUE-NEXT-SESSION",
"rel.1 FAIL / PARTIAL / BLOCKED",
),
"docs/rules/210-WORKFLOW.md": (
"sasedev-knowledge-<X.Y.Z>-<tranche>.delta.zip",
"Le delta suivant ne doit pas être appliqué avant matérialisation Git du history précédent.",
"rapport post-tag",
),
"docs/rules/300-DOCUMENTATION.md": (
"`ROADMAP.md` décrit les objectifs",
"Documents vivants et historiques",
"Revue d'horizon",
),
"docs/rules/400-VALIDATION.md": (
"FORMAT",
"PUBLISH",
"Une commande qui échoue dans la gate reste un `FAIL`",
),
}
for path, phrases in owner_contracts.items():
text = Path(path).read_text(encoding="utf-8")
for phrase in phrases:
assert phrase in text, (path, phrase)
mapping = Path("docs/architecture/003-PGR_ADOPTION_MAP.md").read_text(encoding="utf-8")
for phrase in (
"PGR tag v0.1.3",
"Décisions ADOPT",
"Décisions KEEP-LOCAL",
"Décisions DEFER / non applicables",
"Après `PASS` d'`alpha.4`",
):
assert phrase in mapping, phrase
session_template = Path("docs/templates/001-NEW_SESSION_PROMPT.md").read_text(encoding="utf-8")
assert "Une session normale Knowledge ne consulte pas PGR" in session_template
assert "<NEXT_RELEASE>-alpha.1" in session_template
assert "stable PGR courante" not in session_template
git_api_root = Path("crates/knowledge-git-api/src/lib.rs").read_text(encoding="utf-8")
for module in ("mod reference;", "mod repository;", "mod revision;", "mod snapshot;"):
assert module in git_api_root, module
for item in ("GitReference", "GitRepository", "GitRevision", "GitSnapshot"):
assert f"::{item};" in git_api_root, item
sync_root = Path("crates/knowledge-sync-api/src/lib.rs").read_text(encoding="utf-8")
for module in ("mod event_source;", "mod signal;"):
assert module in sync_root, module
for item in ("RepositoryEventSource", "RepositorySyncCause", "RepositorySyncSignal"):
assert item in sync_root, item
root = tomllib.loads(Path("Cargo.toml").read_text(encoding="utf-8"))
assert len(root["workspace"]["members"]) == 8
print("Knowledge 0.0.2-alpha.4 autonomy/structure audit: clean")
PY
python3 -B scripts/audit_rust_test_layout.py crates
python3 -B scripts/audit_rust_blank_lines.py crates
python3 -B scripts/audit_rust_item_spacing.py crates
python3 -B scripts/audit_rust_module_order.py crates
python3 -B scripts/audit_rust_trait_import_blocks.py crates
python3 -B scripts/audit_rust_reexport_blocks.py crates
python3 -B scripts/audit_rust_crate_root_facades.py crates
python3 -B scripts/audit_rust_export_completeness.py --root . --summary-only
cargo fmt --all -- --check
cargo metadata --format-version 1 --no-deps > /tmp/sasedev-knowledge-0.0.2-alpha.4-metadata.json
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
cargo test -p knowledge-git-api --all-targets --all-features
cargo test -p knowledge-sync-api --all-targets --all-features
cargo test -p knowledge-git-lib --all-targets --all-features
cargo test --workspace --all-targets --all-features
python3 - <<'PY'
import json
from pathlib import Path
metadata = json.loads(Path("/tmp/sasedev-knowledge-0.0.2-alpha.4-metadata.json").read_text(encoding="utf-8"))
expected = {
"knowledge-domain-lib",
"knowledge-git-api",
"knowledge-git-lib",
"knowledge-sync-api",
"knowledge-web-lib",
"knowledge-pgr-server",
"knowledge-howtos-server",
"knowledge-snippets-server",
}
assert {package["name"] for package in metadata["packages"]} == expected
assert len(metadata["workspace_members"]) == 8
print("Knowledge 0.0.2-alpha.4 Cargo metadata audit: clean")
PY
test -f Cargo.lock
git check-ignore -q Cargo.lock
if git ls-files --error-unmatch Cargo.lock >/dev/null 2>&1; then
echo 'Cargo.lock must remain untracked for Knowledge' >&2
exit 1
fi
test -z "$(git diff --name-only -- Web)"
test -z "$(git diff --name-only -- crates/knowledge-git-lib/src)"
test ! -e crates/knowledge-app-lib
test ! -e crates/knowledge-forge-gitea-lib
test ! -e crates/knowledge-store-postgres-lib
test ! -e history/0.0.2/alpha.4.md
git add -A
git diff --cached --check
git status --short
```
## Transition attendue
Si toute la gate est `PASS`, produire `history/0.0.2/alpha.4.md`, appliquer/committer/pousser ce history puis préparer seulement ensuite `0.0.2-alpha.5`.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/000-README.md --> <!-- file: docs/000-README.md -->
<!-- version: 6 --> <!-- version: 7 -->
# Documentation SaseDev Knowledge # Documentation SaseDev Knowledge
@@ -11,6 +11,18 @@
- [`architecture/001-PROJECT_PROFILE.md`](architecture/001-PROJECT_PROFILE.md) — baseline PGR, owners/skeletons applicables, décisions `ADOPT / KEEP-LOCAL / OVERRIDE / DEFER` et nomenclature ; - [`architecture/001-PROJECT_PROFILE.md`](architecture/001-PROJECT_PROFILE.md) — baseline PGR, owners/skeletons applicables, décisions `ADOPT / KEEP-LOCAL / OVERRIDE / DEFER` et nomenclature ;
- [`architecture/002-KNOWLEDGE_ARCHITECTURE.md`](architecture/002-KNOWLEDGE_ARCHITECTURE.md) — frontières application/domain, Git, forge, synchronisation, PostgreSQL, contenu et publication. - [`architecture/002-KNOWLEDGE_ARCHITECTURE.md`](architecture/002-KNOWLEDGE_ARCHITECTURE.md) — frontières application/domain, Git, forge, synchronisation, PostgreSQL, contenu et publication.
- [`architecture/003-PGR_ADOPTION_MAP.md`](architecture/003-PGR_ADOPTION_MAP.md) — provenance PGR `v0.1.3`, mapping d'adoption et owners locaux résultants.
## Règles locales
- [`rules/000-README.md`](rules/000-README.md) — index des owners normatifs autonomes Knowledge.
## Templates locaux
- [`templates/001-NEW_SESSION_PROMPT.md`](templates/001-NEW_SESSION_PROMPT.md) — reprise d'une session/version depuis la baseline Knowledge locale.
- [`templates/002-RELEASE_PLAN.md`](templates/002-RELEASE_PLAN.md) — structure canonique d'un plan multi-tranches.
- [`templates/003-OPERATOR_HANDOFF.md`](templates/003-OPERATOR_HANDOFF.md) — commandes entre history, commit/push et delta suivant.
- [`templates/004-RUST_LIBRARY_CRATE.md`](templates/004-RUST_LIBRARY_CRATE.md) — pattern de façade `lib.rs` et module propriétaire.
## Études ## Études

View File

@@ -1,5 +1,5 @@
<!-- file: docs/architecture/001-PROJECT_PROFILE.md --> <!-- file: docs/architecture/001-PROJECT_PROFILE.md -->
<!-- version: 13 --> <!-- version: 14 -->
# Profil du projet Knowledge # Profil du projet Knowledge
@@ -28,7 +28,7 @@ PGR publish report pgr-0.1.3-publish.001-report.md = PASS
Cette référence est une provenance d'adoption figée. Après matérialisation des contrats retenus, la baseline normative de Knowledge est constituée des artefacts locaux du dépôt Knowledge. Une version ou session future ne consulte pas automatiquement le PGR courant ; une nouvelle comparaison PGR exige une réévaluation explicitement engagée. Cette référence est une provenance d'adoption figée. Après matérialisation des contrats retenus, la baseline normative de Knowledge est constituée des artefacts locaux du dépôt Knowledge. Une version ou session future ne consulte pas automatiquement le PGR courant ; une nouvelle comparaison PGR exige une réévaluation explicitement engagée.
`alpha.4` doit terminer cette matérialisation locale pour l'adoption `v0.1.3`, sans recopier mécaniquement la structure PGR et sans réécrire les artefacts historiques déjà publiés. `0.0.2-alpha.4` matérialise les owners locaux nécessaires et ferme cette adoption comme migration ponctuelle. Le mapping durable est [`003-PGR_ADOPTION_MAP.md`](003-PGR_ADOPTION_MAP.md).
L'archive PGR `v0.1.3` vérifiée possède `VERSION = 0.1.3`, `332` entrées ZIP, `290` fichiers, `42` répertoires, une racine unique `pgr/`, aucun symlink et aucun `.git`. Son rapport post-tag indique `48/48` tests Python et les audits Markdown propres. L'archive PGR `v0.1.3` vérifiée possède `VERSION = 0.1.3`, `332` entrées ZIP, `290` fichiers, `42` répertoires, une racine unique `pgr/`, aucun symlink et aucun `.git`. Son rapport post-tag indique `48/48` tests Python et les audits Markdown propres.
@@ -54,75 +54,64 @@ Les classifications locales restent :
- `OVERRIDE` — règle PGR applicable remplacée ou raffinée localement avec justification ; - `OVERRIDE` — règle PGR applicable remplacée ou raffinée localement avec justification ;
- `DEFER` — choix volontairement reporté avec condition de reprise. - `DEFER` — choix volontairement reporté avec condition de reprise.
## Owners et skeletons applicables ## Owners locaux après adoption
| Élément | Décision courante | État Knowledge | Motif | Les responsabilités quotidiennes sont désormais possédées par :
|----------------------------------------------|------------------------------------|-----------------|---------------------------------------------------------------|
| `200-GOVERNANCE` | `ADOPT` | actif | lifecycle/version locale |
| `210-WORKFLOW` | `ADOPT` | actif | plan/delta/history/handoff |
| `220-SKELETONS` | `ADOPT` comme référence | actif | les skeletons existants ne sont pas réappliqués mécaniquement |
| `230-ADOPTION` | `ADOPT` | `0.0.2-alpha.1` | migration explicite PGR `v0.1.1 -> v0.1.3` |
| `300-DOCUMENTATION` | `ADOPT` | actif | rôles documentaires et taxonomie |
| `400-VALIDATION` | `ADOPT` | actif | preuves proportionnées et autorité opérateur |
| `500-LANGUAGES` + `510-RUST_CARGO` | `ADOPT` | actif | backend Rust/workspace Cargo strict |
| `530-TYPESCRIPT` | `ADOPT` | actif | frontend durable TypeScript |
| `540-JAVASCRIPT_PACKAGE_ECOSYSTEM` | `ADOPT` | actif | npm/lockfile/scripts explicites |
| `550-VITE` | `ADOPT` | actif | dev server/build/cache/outputs/manifest |
| `560-CSS_SASS` | `ADOPT` | actif | CSS/Sass et outputs |
| `700-FRAMEWORKS` | `ADOPT` | actif | cadre générique des frameworks |
| `710-TAURI` | `DEFER` / non applicable | inchangé | aucun host desktop/mobile Tauri |
| skeleton `001-PROJECT_GOVERNANCE_FOUNDATION` | `ADOPT` comme référence historique | matérialisé | fondation locale existante |
| skeleton `002-RUST_CARGO_WORKSPACE` | `ADOPT` comme référence historique | matérialisé | workspace Rust existant |
| skeleton `003-WEB_FRONTEND` | `ADOPT` comme référence historique | matérialisé | frontend indépendant du host |
| validation `005-WEB_FRONTEND_VALIDATION` | `ADOPT` | actif | restore/typecheck/build/smoke proportionnés |
Les owners Java/Maven/Gradle restructurés dans PGR `0.1.2`, le profil Android réévalué en `0.1.3` et les autres technologies absentes ne sont pas sélectionnés. Leur évolution n'entraîne donc aucune migration de code Knowledge. ```text
docs/rules/200-GOVERNANCE.md
docs/rules/210-WORKFLOW.md
docs/rules/300-DOCUMENTATION.md
docs/rules/400-VALIDATION.md
docs/rules/510-RUST_CARGO.md
docs/rules/530-WEB_FRONTEND.md
```
Aucun `OVERRIDE` n'est requis par l'adoption `v0.1.3`. Le détail de la migration depuis les owners PGR `v0.1.3`, y compris les décisions `KEEP-LOCAL`, les éléments non applicables et les skeletons uniquement historiques, est conservé dans [`003-PGR_ADOPTION_MAP.md`](003-PGR_ADOPTION_MAP.md). Aucun de ces owners locaux ne nécessite de consulter PGR pour être interprété.
## Matrice des décisions importantes ## Matrice des décisions importantes
| Décision | Classification | Contrat retenu / condition de reprise | | Décision | Classification | Contrat retenu / condition de reprise |
|----------------------------------------|-----------------------------------|------------------------------------------------------------------------------------------------------------------| |----------------------------------------|-------------------------------|------------------------------------------------------------------------------------------------------------------|
| Dépôt applicatif | `KEEP-LOCAL` | `sasedev-knowledge` ; workspace unique de la plateforme | | Dépôt applicatif | `KEEP-LOCAL` | `sasedev-knowledge` ; workspace unique de la plateforme |
| Nom court / préfixe crates | `KEEP-LOCAL` | `knowledge` / `knowledge-` | | Nom court / préfixe crates | `KEEP-LOCAL` | `knowledge` / `knowledge-` |
| Dépôt normatif | `KEEP-LOCAL` | dépôt existant `pgr`, jamais fusionné dans le dépôt applicatif | | Dépôt normatif | `KEEP-LOCAL` | dépôt existant `pgr`, jamais fusionné dans le dépôt applicatif |
| Dépôt HOWTO | `KEEP-LOCAL` | dépôt séparé `howtos` | | Dépôt HOWTO | `KEEP-LOCAL` | dépôt séparé `howtos` |
| Dépôt snippets | `KEEP-LOCAL` | dépôt séparé `snippets` | | Dépôt snippets | `KEEP-LOCAL` | dépôt séparé `snippets` |
| Nombre de sources Git | `KEEP-LOCAL` | au moins trois sources initiales, sans limite codée à trois | | Nombre de sources Git | `KEEP-LOCAL` | au moins trois sources initiales, sans limite codée à trois |
| Git comme backend du contenu | `KEEP-LOCAL` | invariant d'architecture Knowledge | | Git comme backend du contenu | `KEEP-LOCAL` | invariant d'architecture Knowledge |
| Implémentation Git de `0.0.2` | `KEEP-LOCAL` | processus `git` contrôlé derrière `knowledge-git-api` ; décision réévaluable derrière le contrat | | Implémentation Git de `0.0.2` | `KEEP-LOCAL` | processus `git` contrôlé derrière `knowledge-git-api` ; décision réévaluable derrière le contrat |
| Configuration physique Git | `KEEP-LOCAL` | `knowledge-git-lib` matérialisée en `0.0.2-alpha.2` ; source locale/remote + racine d'état ; pas dans le domaine | | Configuration physique Git | `KEEP-LOCAL` | `knowledge-git-lib` matérialisée en `0.0.2-alpha.2` ; source locale/remote + racine d'état ; pas dans le domaine |
| Copies Git générées | `KEEP-LOCAL` | racine d'état explicite hors dépôt source, mirrors et snapshots adressés par clé sûre/révision | | Copies Git générées | `KEEP-LOCAL` | racine d'état explicite hors dépôt source, mirrors et snapshots adressés par clé sûre/révision |
| Partage du cache Git entre processus | `DEFER` | état root exclusif à une instance backend en `0.0.2` ; reprendre avec verrouillage inter-processus réel | | Partage du cache Git entre processus | `DEFER` | état root exclusif à une instance backend en `0.0.2` ; reprendre avec verrouillage inter-processus réel |
| Forge | `KEEP-LOCAL` | capacité optionnelle derrière adapter ; aucune API de forge dans le domaine | | Forge | `KEEP-LOCAL` | capacité optionnelle derrière adapter ; aucune API de forge dans le domaine |
| Gitea | `DEFER` | premier adapter candidat ; reprendre lorsque des capacités forge-only sont implémentées | | Gitea | `DEFER` | premier adapter candidat ; reprendre lorsque des capacités forge-only sont implémentées |
| Synchronisation sans webhook | `KEEP-LOCAL` | explicite/périodique convergent vers le même cas d'usage ; hooks/webhooks restent accélérateurs | | Synchronisation sans webhook | `KEEP-LOCAL` | explicite/périodique convergent vers le même cas d'usage ; hooks/webhooks restent accélérateurs |
| Scheduler périodique concret | `DEFER` | créer seulement lorsque son owner runtime/lifecycle est démontré | | Scheduler périodique concret | `DEFER` | créer seulement lorsque son owner runtime/lifecycle est démontré |
| Dernière révision observée en `0.0.2` | `KEEP-LOCAL` | fournie par l'appelant et retournée par le cas d'usage ; pas de pseudo-persistance locale | | Dernière révision observée en `0.0.2` | `KEEP-LOCAL` | fournie par l'appelant et retournée par le cas d'usage ; pas de pseudo-persistance locale |
| PostgreSQL | `KEEP-LOCAL` | une base logique partagée future pour état transversal/projections ; jamais vérité du contenu Git publié | | PostgreSQL | `KEEP-LOCAL` | une base logique partagée future pour état transversal/projections ; jamais vérité du contenu Git publié |
| Rust stable / édition 2024 | `ADOPT` | profil Rust/Cargo PGR | | Rust stable / édition 2024 | `ADOPT` | owner local `docs/rules/510-RUST_CARGO.md` |
| Workspace Cargo | `ADOPT` | skeleton Rust/Cargo déjà matérialisé | | Workspace Cargo | `ADOPT` | configuration locale + owner `510-RUST_CARGO.md` |
| `Cargo.lock` | `KEEP-LOCAL` | généré localement et ignoré ; manifests Cargo versionnés | | `Cargo.lock` | `KEEP-LOCAL` | généré localement et ignoré ; manifests Cargo versionnés |
| Actix Web | `KEEP-LOCAL` | trois launchers existants et composition partagée dans `knowledge-web-lib` | | Actix Web | `KEEP-LOCAL` | trois launchers existants et composition partagée dans `knowledge-web-lib` |
| Maud | `KEEP-LOCAL` | rendu SSR commun dans `knowledge-web-lib` | | Maud | `KEEP-LOCAL` | rendu SSR commun dans `knowledge-web-lib` |
| TypeScript | `ADOPT` | owner `530` | | TypeScript | `ADOPT` | owner local `docs/rules/530-WEB_FRONTEND.md` |
| Package manager frontend | `KEEP-LOCAL` | npm ; `package-lock.json` versionné | | Package manager frontend | `KEEP-LOCAL` | npm ; `package-lock.json` versionné |
| Vite | `KEEP-LOCAL` + owner `550` adopté | build/preview de références et manifest consommé par Maud | | Vite | `KEEP-LOCAL` + contrat adopté | owner local Web ; build/preview de références et manifest consommé par Maud |
| Sass | `KEEP-LOCAL` + owner `560` adopté | styles source et assets réellement servis | | Sass | `KEEP-LOCAL` + contrat adopté | owner local Web ; styles source et assets réellement servis |
| Bootstrap | `KEEP-LOCAL` | framework CSS local Knowledge, jamais règle PGR universelle | | Bootstrap | `KEEP-LOCAL` | framework CSS local Knowledge, jamais règle PGR universelle |
| Racine frontend | `KEEP-LOCAL` | package partagé `Web/knowledge-template-lab/` | | Racine frontend | `KEEP-LOCAL` | package partagé `Web/knowledge-template-lab/` |
| Templates statiques Web | `KEEP-LOCAL` | harness de conception/validation ; rendu runtime Maud | | Templates statiques Web | `KEEP-LOCAL` | harness de conception/validation ; rendu runtime Maud |
| Intégration manifest Vite / Maud | `KEEP-LOCAL` | matérialisée dans `knowledge-web-lib` | | Intégration manifest Vite / Maud | `KEEP-LOCAL` | matérialisée dans `knowledge-web-lib` |
| Driver/ORM PostgreSQL | `DEFER` | reprendre à la première implémentation persistante réelle | | Driver/ORM PostgreSQL | `DEFER` | reprendre à la première implémentation persistante réelle |
| Migrations PostgreSQL | `DEFER` | reprendre avec le premier schéma réel | | Migrations PostgreSQL | `DEFER` | reprendre avec le premier schéma réel |
| Moteur de recherche | `DEFER` | commencer par capacités PostgreSQL/index applicatif lorsque ce scope sera engagé | | Moteur de recherche | `DEFER` | commencer par capacités PostgreSQL/index applicatif lorsque ce scope sera engagé |
| Fournisseur d'auth externe | `DEFER` | reprendre lorsque le workflow utilisateur l'exige | | Fournisseur d'auth externe | `DEFER` | reprendre lorsque le workflow utilisateur l'exige |
| Surface admin par application | `KEEP-LOCAL` | chaque serveur protège ses opérations privilégiées ; URL exacte différée | | Surface admin par application | `KEEP-LOCAL` | chaque serveur protège ses opérations privilégiées ; URL exacte différée |
| Quatrième application d'administration | `DEFER` | agréger seulement si une responsabilité transverse apparaît | | Quatrième application d'administration | `DEFER` | agréger seulement si une responsabilité transverse apparaît |
| Modèle rôles/capabilities | `DEFER` | reprendre avec les cas d'usage d'autorisation réels | | Modèle rôles/capabilities | `DEFER` | reprendre avec les cas d'usage d'autorisation réels |
| Formats finaux HOWTO/snippet | `DEFER` | définir avec corpus réel | | Formats finaux HOWTO/snippet | `DEFER` | définir avec corpus réel |
| Autres noms de crates | `DEFER` | créer uniquement lorsque l'ownership est démontré | | Autres noms de crates | `DEFER` | créer uniquement lorsque l'ownership est démontré |
## Nomenclature de crates ## Nomenclature de crates
@@ -166,15 +155,15 @@ Elles justifient de conserver séparées l'identité/authentification partagée,
## Résultat de l'adoption PGR 0.1.3 ## Résultat de l'adoption PGR 0.1.3
L'adoption est bornée aux évolutions réellement applicables : `0.0.2-alpha.4` ferme l'adoption comme migration ponctuelle :
- `230-ADOPTION` devient applicable parce que Knowledge est désormais un projet existant ; - les owners nécessaires sont adaptés et possédés localement ;
- les owners déjà adoptés restent actifs ; - les règles Web externes applicables sont consolidées en un owner Knowledge plutôt que copiées en quatre documents ;
- les changements PGR Java/Maven/Gradle/Android ne s'appliquent pas ; - les skeletons restent une provenance d'instanciation, pas des dépendances normatives ;
- le `DEFER` Tauri reste inchangé ; - les scripts génériques utiles sont sélectionnés localement et les variantes locales restent autoritaires ;
- les skeletons servent de références de comparaison et ne sont pas réinstanciés ; - les futurs prompts de session repartent de Knowledge seul ;
- les anciennes gates/deltas/histories `0.0.1` conservent leur contexte historique, y compris les états `FAIL` et anciennes décisions corrigées plus tard ; - une nouvelle stable PGR n'a aucun effet tant qu'une réévaluation n'est pas explicitement planifiée ;
- aucune règle produit Git/process n'est promue en règle PGR générale. - les artefacts historiques `0.0.1` et les tranches antérieures de `0.0.2` restent inchangés.
## Décisions à rouvrir ## Décisions à rouvrir

View File

@@ -0,0 +1,136 @@
<!-- file: docs/architecture/003-PGR_ADOPTION_MAP.md -->
<!-- version: 1 -->
# Mapping d'adoption PGR v0.1.3 vers Knowledge
## Objet
Ce document ferme la réconciliation PGR explicitement engagée au démarrage de `0.0.2`. Il conserve la provenance des contrats examinés et indique leur owner Knowledge durable.
Après cette tranche, le développement courant se fonde sur les artefacts locaux Knowledge. Les règles sélectionnées ci-dessous sont adaptées et suffisamment matérialisées localement pour leur usage quotidien ; ce mapping ne crée aucune dépendance de lecture vers PGR.
## Source d'adoption observée
```text
PGR tag v0.1.3
PGR commit fe80dbbb737390a7ea99df27d979bd59ccfb86e3
PGR archive SHA-256 f3a7dffd5fe0fd3542e6b5207fda0b94bca2bd05bd5a54542d0a08d635a5d6ee
publish report pgr-0.1.3-publish.001-report.md = PASS
```
Cette source sert uniquement à expliquer les décisions ci-dessous.
## Décisions ADOPT
### Gouvernance — provenance PGR owner 200
Décision : `ADOPT`.
Owner local : [`../rules/200-GOVERNANCE.md`](../rules/200-GOVERNANCE.md).
Adaptation : proportionnalité, versioning/lifecycle, fixes, REPLAN, baseline autoritaire, décisions différées et autonomie normative sont exprimés sans dépendre d'un dépôt PGR courant.
### Workflow — provenance PGR owner 210
Décision : `ADOPT`.
Owner local : [`../rules/210-WORKFLOW.md`](../rules/210-WORKFLOW.md).
Adaptation : contrats delta/history, cycle gate/commit/push, prompts/handoffs, fixes, REPLAN, fermeture stable, tag/archive et preuve post-tag sont spécialisés pour Knowledge et `origin/master` lorsqu'il est établi.
### Adoption d'un projet existant — provenance PGR owner 230
Décision : `ADOPT`, puis scope fermé après matérialisation.
Owner local durable : gouvernance locale et présent mapping.
Adaptation : toute future adoption externe doit être explicitement engagée ; aucune surveillance continue de PGR n'est créée.
### Documentation — provenance PGR owner 300
Décision : `ADOPT`.
Owner local : [`../rules/300-DOCUMENTATION.md`](../rules/300-DOCUMENTATION.md).
Adaptation : rôles README/RULES/ROADMAP/CHANGELOG/index, familles documentaires, documents vivants/historiques, headers, plans, revue d'horizon et prompts sont possédés localement.
### Validation — provenance PGR owner 400
Décision : `ADOPT`.
Owner local : [`../rules/400-VALIDATION.md`](../rules/400-VALIDATION.md).
Adaptation : validation proportionnée, statuts, catégories de preuve, autorité opérateur, ordre des gates et scripts read-only sont possédés localement.
### Rust / Cargo — provenance PGR owners 500 + 510
Décision : `ADOPT` pour le profil Rust applicable ; le méta-owner langage 500 n'est pas matérialisé séparément.
Owner local : [`../rules/510-RUST_CARGO.md`](../rules/510-RUST_CARGO.md).
Adaptation : Rust 2024, workspace, nomenclature, façade crate-root, tests et audits stricts sont exprimés directement pour Knowledge.
### Web — provenance PGR owners 530 + 540 + 550 + 560
Décision : `ADOPT` pour les contrats réellement utilisés.
Owner local consolidé : [`../rules/530-WEB_FRONTEND.md`](../rules/530-WEB_FRONTEND.md).
Adaptation : TypeScript, npm, Vite et Sass sont regroupés avec les décisions locales Bootstrap et Maud afin d'éviter quatre owners locaux artificiellement séparés.
## Décisions KEEP-LOCAL
### Skeletons — provenance PGR owner 220
Décision : `KEEP-LOCAL` après instanciation.
Les skeletons de fondation, workspace Rust et frontend ont servi à amorcer l'état existant. Ils ne sont pas réappliqués ni conservés comme dépendances normatives. Les fichiers réellement instanciés dans Knowledge sont les propriétaires de leur configuration.
### Frameworks — provenance PGR owner 700
Décision : `KEEP-LOCAL`.
Le méta-owner framework n'apporte pas de règle quotidienne supplémentaire : Actix Web, Maud et Bootstrap sont des choix locaux documentés dans `RULES.md`, l'architecture et l'owner Web local.
### Audits Rust déjà adaptés
Décision : `KEEP-LOCAL` lorsque les scripts locaux divergent ou spécialisent la baseline générique.
Les audits Rust présents dans `scripts/` sont les copies autoritaires Knowledge. Ils ne sont pas remplacés automatiquement par des scripts PGR portant le même nom.
## Décisions DEFER / non applicables
- `710-TAURI` : `DEFER`, aucun host Tauri dans le scope courant.
- Java/Maven/Gradle : non applicables au workspace actuel.
- Android : non applicable au produit Web actuel.
- autres plateformes/langages absents : non sélectionnés.
Aucun `OVERRIDE` de règle PGR applicable n'est nécessaire pour clôturer cette adoption ; les décisions produit distinctes sont classées `KEEP-LOCAL` plutôt que présentées comme des overrides artificiels.
## Artefacts localement matérialisés
L'adoption est considérée autonome lorsque les artefacts suivants sont présents et validés :
```text
RULES.md
docs/rules/200-GOVERNANCE.md
docs/rules/210-WORKFLOW.md
docs/rules/300-DOCUMENTATION.md
docs/rules/400-VALIDATION.md
docs/rules/510-RUST_CARGO.md
docs/rules/530-WEB_FRONTEND.md
docs/templates/001-NEW_SESSION_PROMPT.md
docs/templates/002-RELEASE_PLAN.md
docs/templates/003-OPERATOR_HANDOFF.md
docs/templates/004-RUST_LIBRARY_CRATE.md
scripts/audit_markdown_headers.py
scripts/audit_markdown_links.py
scripts/audit_markdown_tables.py
scripts/audit_rust_crate_root_facades.py
```
Les configurations déjà instanciées (`Cargo.toml`, `rustfmt.toml`, `clippy.toml`, `.cargo/config.toml`, package npm, tsconfig et Vite) restent leurs propres artefacts autoritaires ; elles ne sont pas dupliquées dans un répertoire de templates uniquement pour reproduire PGR.
## Critère de fermeture
Après `PASS` d'`alpha.4`, une nouvelle session Knowledge doit pouvoir comprendre et développer le projet à partir de la stable Knowledge et de ses artefacts locaux, sans charger PGR. Une future adoption PGR demeure possible, mais seulement comme opération explicitement planifiée.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/plans/002-V0_0_2_GIT_SYNC_PLAN.md --> <!-- file: docs/plans/002-V0_0_2_GIT_SYNC_PLAN.md -->
<!-- version: 7 --> <!-- version: 8 -->
# Plan 0.0.2 — Git générique et synchronisation de lecture # Plan 0.0.2 — Git générique et synchronisation de lecture
@@ -164,7 +164,7 @@ Si la surface « configuration + runner + mirror » ne peut plus être validée
### alpha.3 — refresh, résolution et snapshot réel ### alpha.3 — refresh, résolution et snapshot réel
Statut opérateur initial : **FAIL**. Statut initial : **FAIL**. `alpha.3.fix.1` : **PASS**. Tranche fermée.
La tranche a matérialisé et prouvé sur de vrais repositories temporaires : La tranche a matérialisé et prouvé sur de vrais repositories temporaires :
@@ -186,27 +186,29 @@ La revue de tranche a déclenché un REPLAN explicite : l'autonomie normative ap
### alpha.4 — autonomie normative et structure interne des crates ### alpha.4 — autonomie normative et structure interne des crates
Finaliser l'adoption PGR `v0.1.3` comme migration ponctuelle, sans transformer PGR en dépendance documentaire permanente : Finaliser l'adoption PGR `v0.1.3` comme migration ponctuelle et rendre Knowledge autonome pour les sessions suivantes.
- inventorier les owners/contrats PGR réellement retenus par Knowledge ; Scope :
- produire un mapping durable `ADOPT / KEEP-LOCAL / OVERRIDE / DEFER` fondé sur la baseline locale actuelle ;
- pour chaque `ADOPT`, identifier l'owner local qui possède effectivement le contrat ;
- adapter et matérialiser localement uniquement les règles, templates/configurations et audits nécessaires au développement de Knowledge ;
- ne pas recopier mécaniquement l'arborescence ou les textes PGR lorsque `RULES.md` ou un owner local plus adapté suffit ;
- faire de PGR `v0.1.3` une provenance d'adoption figée, et non une « baseline courante » à recharger ;
- établir que les futurs prompts de démarrage partent de la baseline Knowledge locale et ne demandent une consultation PGR que si une réévaluation PGR est explicitement dans leur scope ;
- vérifier que les règles de gouvernance, workflow, documentation, validation, Rust/Cargo et Web réellement nécessaires sont compréhensibles et applicables depuis le dépôt Knowledge seul.
La même tranche audite l'organisation interne des crates : - matérialiser six owners locaux : gouvernance, workflow, documentation, validation, Rust/Cargo et frontend Web, avec les contrats opérationnels réellement nécessaires (lifecycle/versioning, fixes/REPLAN, delta/history/handoff, rôles documentaires et catégories de preuve) ;
- produire `docs/architecture/003-PGR_ADOPTION_MAP.md` avec le mapping `ADOPT / KEEP-LOCAL / OVERRIDE / DEFER` et les owners Knowledge réels ;
- conserver PGR `v0.1.3` uniquement comme provenance de l'adoption ;
- fournir des templates locaux de nouvelle session, plan de release, handoff opérateur et crate bibliothèque ;
- adopter localement les audits Markdown headers/liens/tables utiles au dépôt ;
- ajouter un audit Knowledge garantissant que les `src/lib.rs` des crates bibliothèque restent des façades ;
- réorganiser `knowledge-git-api` en modules `reference`, `revision`, `snapshot`, `repository` sans modifier son API crate-root ;
- réorganiser `knowledge-sync-api` en modules `signal` et `event_source` sans modifier son API crate-root ;
- auditer les autres crates et ne pas les découper davantage lorsqu'elles respectent déjà le contrat de façade ;
- conserver inchangée la sémantique Git prouvée par `alpha.3`.
- `lib.rs` reste la façade publique/documentation de crate ; Hors scope :
- les types, traits et implémentations sont déplacés vers des modules nommés selon leur responsabilité lorsqu'ils forment une responsabilité distincte ;
- les crates `knowledge-git-api` et `knowledge-sync-api` sont examinées en priorité ;
- `api.rs` n'est pas imposé comme nom générique : préférer des modules tels que `reference`, `revision`, `snapshot`, `repository`, `signal` ou autre ownership réel ;
- les petites crates/fichiers ne sont pas découpés artificiellement uniquement pour satisfaire une forme ;
- les réexports publics restent centralisés à la crate root et les consommateurs externes continuent d'utiliser la façade stable.
Cette tranche ne change pas la sémantique Git prouvée par `alpha.3` et ne matérialise pas encore le cas d'usage `Changed` / `Unchanged`. - aucune consultation d'une version PGR postérieure à `v0.1.3` ;
- aucune copie mécanique de tous les owners/skeletons/templates PGR ;
- aucun changement de comportement Git, forge, PostgreSQL, auth/admin ou Web runtime ;
- aucun `knowledge-app-lib` ni cas d'usage `Changed` / `Unchanged` avant `alpha.5`.
Gate attendue : audits Markdown locaux, audit d'autonomie, audits Rust incluant la façade crate-root, rustfmt/check/Clippy, tests ciblés des deux crates `-api` et `knowledge-git-lib`, puis tests workspace. `Web/` doit rester sans diff.
### alpha.5 — cas d'usage de synchronisation ### alpha.5 — cas d'usage de synchronisation

25
docs/rules/000-README.md Normal file
View File

@@ -0,0 +1,25 @@
<!-- file: docs/rules/000-README.md -->
<!-- version: 1 -->
# Règles locales Knowledge
## Rôle
Ce répertoire contient les owners normatifs durables nécessaires au développement de `sasedev-knowledge` après l'adoption ponctuelle de PGR `v0.1.3`.
Ces documents sont autonomes. Leur lecture ne nécessite pas d'ouvrir le dépôt PGR. Les numéros d'owner conservent une continuité de provenance lorsque cela reste utile, mais le texte local Knowledge est désormais autoritaire pour ce projet.
## Owners actifs
- [`200-GOVERNANCE.md`](200-GOVERNANCE.md) — autorité de baseline, décisions, adoption externe explicite et autonomie normative.
- [`210-WORKFLOW.md`](210-WORKFLOW.md) — plan, delta, gate opérateur, history, commit/push, fix et handoff.
- [`300-DOCUMENTATION.md`](300-DOCUMENTATION.md) — rôles documentaires, headers, plans, prompts et historique.
- [`400-VALIDATION.md`](400-VALIDATION.md) — preuves proportionnées, statuts et autorité opérateur.
- [`510-RUST_CARGO.md`](510-RUST_CARGO.md) — workspace Rust/Cargo strict, façade crate-root, tests et audits.
- [`530-WEB_FRONTEND.md`](530-WEB_FRONTEND.md) — TypeScript, npm, Vite, Sass, Bootstrap et contrat template/Maud.
Le mapping d'adoption qui explique pourquoi ces owners existent et quels owners PGR n'ont pas été matérialisés localement est conservé dans [`../architecture/003-PGR_ADOPTION_MAP.md`](../architecture/003-PGR_ADOPTION_MAP.md).
## Priorité
[`../../RULES.md`](../../RULES.md) reste le point d'entrée normatif du dépôt et possède les décisions produit spécifiques. Les owners de ce répertoire détaillent les contrats transverses. Une règle plus spécifique au produit ou à une architecture concrète prime dans son scope lorsqu'elle est explicitement documentée.

View File

@@ -0,0 +1,122 @@
<!-- file: docs/rules/200-GOVERNANCE.md -->
<!-- version: 1 -->
# Gouvernance locale Knowledge
## Principe
La gouvernance de Knowledge sert la qualité, la reprise et la réduction du risque. Elle reste proportionnée au changement : une règle ou une gate doit apporter une preuve, protéger un contrat ou rendre une décision durable ; elle ne doit pas exister uniquement pour ajouter de la cérémonie.
## Baseline autoritaire
Une version ou tranche Knowledge part des artefacts Knowledge réellement autoritaires : archive/tag ou workspace établi, `VERSION`, règles locales, architecture, plan actif, deltas/histories et preuves opérateur disponibles.
Une conversation antérieure, une copie non vérifiée ou une version plus récente d'un référentiel externe ne remplace jamais cette baseline.
## Autonomie normative et provenance PGR
Knowledge est autonome après adoption. PGR `v0.1.3` est la provenance de la réconciliation effectuée pendant `0.0.2`, pas une dépendance normative vivante.
Une nouvelle version, session ou tranche Knowledge MUST NOT rechercher ou charger automatiquement une nouvelle stable PGR. Une comparaison PGR ne peut commencer que si une réévaluation/adoption PGR est explicitement inscrite au scope.
Lors d'une telle réévaluation, les décisions sont classifiées `ADOPT / KEEP-LOCAL / OVERRIDE / DEFER`, puis les changements retenus sont adaptés et matérialisés dans Knowledge avant fermeture de l'adoption.
## Autorité locale et priorité
L'ordre d'autorité normal est :
```text
contrat spécifique de tranche/release établi
-> RULES.md et owners locaux docs/rules/
-> architecture, plan et validation locaux
-> provenance externe uniquement pour expliquer une adoption explicitement engagée
```
Un owner externe n'est jamais appliqué implicitement parce qu'il porte un numéro identique ou une version plus récente.
## Version canonique
`VERSION` contient exactement l'identité SemVer courante de la release Knowledge, sans préfixe `v`. `[workspace.package].version` est un miroir exact de `VERSION` pour le workspace Rust.
Les autres numéros restent indépendants lorsque leur sémantique l'exige : révision documentaire, lockfile/package, format ou compteur technique. Une égalité de version n'est jamais imposée uniquement parce que deux champs contiennent un numéro.
Le lifecycle Knowledge utilise :
```text
X.Y.Z-alpha.N
X.Y.Z-alpha.N.fix.M
X.Y.Z-beta.N
X.Y.Z-beta.N.fix.M
X.Y.Z-rc.N
X.Y.Z-rc.N.fix.M
X.Y.Z
```
`N` et `M` commencent à `1`. Le tag stable est `vX.Y.Z`. `rel.N` nomme une tranche de clôture et n'est pas une version produit SemVer ; sa forme canonique n'utilise pas de zéro de padding (`rel.1`).
## Rôle des phases
### Alpha
L'alpha porte cadrage, implémentation et changements de scope encore attendus. `alpha.1` sert de gate de cadrage de la release : baseline, règles, mission/plan, décisions ouvertes, risques, stratégie de validation et dimensionnement des tranches doivent être vérifiés avant l'implémentation lourde.
Une durée de l'ordre de 15 à 30 minutes peut aider au découpage, mais n'est ni une deadline ni un quota.
### Beta
La beta sert principalement à stabiliser et réconcilier un scope déjà établi. Une expansion fonctionnelle importante exige un REPLAN explicite.
### Release candidate
La RC gèle le scope sauf corrections nécessaires à la validation. Elle porte la gate complète de candidate. Un changement fonctionnel important découvert en RC retourne vers une phase adaptée ou déclenche un REPLAN ; il n'est pas masqué dans un simple fix.
### Stable
La promotion vers `X.Y.Z` doit être proche d'une opération mécanique après une RC propre, tout en exécutant la gate spécifique aux métadonnées/documents/artefacts de promotion.
Pour la clôture stable :
```text
rel.1 FAIL / PARTIAL / BLOCKED -> commit X.Y.Z-rel.1
rel.1.fix.1 FAIL / PARTIAL / BLOCKED -> commit X.Y.Z-rel.1.fix.1
première clôture réellement PASS -> commit X.Y.Z
```
Le commit `X.Y.Z` inclut le history qui établit le `PASS` stable. Le tag `vX.Y.Z` est créé seulement après ce commit. La vérification de l'archive/tag publiée est une preuve post-tag distincte.
## Correctifs de tranche
Un `.fix.M` corrige uniquement la tranche immédiatement concernée. Il conserve son scope fonctionnel et peut corriger code, configuration, documentation, validation ou packaging nécessaires à cet objectif.
Un fix ne doit pas introduire silencieusement une nouvelle fonctionnalité ou un nouveau chantier. Son compteur repart à `1` pour chaque tranche.
À partir de `.fix.3`, une revue du diagnostic et du plan est obligatoire afin de décider explicitement si la poursuite du fix reste appropriée ou si un REPLAN est préférable.
## REPLAN
Un REPLAN est une décision de pilotage, pas un suffixe SemVer. Il s'applique lorsque le plan ne décrit plus correctement la réalité : dépendance inattendue, responsabilité transverse, architecture, risque, volume ou ordre des tranches significativement modifié.
La conclusion d'un REPLAN doit être explicite :
```text
CONTINUE
SPLIT
CONTINUE-NEXT-SESSION
ABANDON
```
Une coupure de conversation ou de session ne crée jamais à elle seule une nouvelle version ou une nouvelle tranche. Le même état continue tant que le scope reste valide.
## Abandon et supersession
Une version ou prerelease commencée n'est pas forcée vers stable pour préserver une séquence esthétique. En cas d'abandon ou supersession, l'état et la raison sont documentés, les preuves et décisions utiles sont conservées, et la version déjà consommée reste dans l'historique.
## Décisions différées
Une décision `DEFER` reste indécise jusqu'à son déclencheur réel. Elle n'est pas remplacée par une valeur arbitraire issue d'un exemple, d'un autre projet ou d'un référentiel externe.
Les décisions différées structurantes restent dans le profil/architecture Knowledge et ne sont reprises que par un scope explicite ou un REPLAN.
## Immutabilité historique
Les artefacts historiques restent historiques. Une nouvelle règle s'applique à partir de son adoption et ne réécrit pas deltas, histories, prompts ou décisions anciennes uniquement pour simuler une conformité rétroactive.

123
docs/rules/210-WORKFLOW.md Normal file
View File

@@ -0,0 +1,123 @@
<!-- file: docs/rules/210-WORKFLOW.md -->
<!-- version: 1 -->
# Workflow local Knowledge
## Unité de travail
`VERSION` est l'identité canonique de la tranche courante. Une tranche est livrée par un delta, validée dans l'environnement opérateur, puis clôturée par un history qui enregistre l'observation réelle.
Le cycle normal est :
```text
delta
-> application opérateur
-> gate applicable
-> résultat PASS / FAIL / PARTIAL / BLOCKED
-> history observé
-> application du history
-> git add / diff --cached --check / status
-> commit
-> push
-> tranche suivante ou fix
```
Le delta suivant ne doit pas être appliqué avant matérialisation Git du history précédent.
## Chemins et archives canoniques
Les contrats de tranche vivent sous :
```text
deltas/<X.Y.Z>/<tranche>.md
history/<X.Y.Z>/<tranche>.md
```
Les archives échangées sont séparées :
```text
sasedev-knowledge-<X.Y.Z>-<tranche>.delta.zip
sasedev-knowledge-<X.Y.Z>-<tranche>.history.zip
```
Un history n'est jamais inclus dans le delta qu'il valide. Le delta suivant peut être livré dans la même réponse que le history précédent lorsque sa préparation est déjà déterminée, mais son application reste postérieure au commit/push du history.
## Contrat d'un delta
Un delta contient des fichiers complets à ajouter ou remplacer. Les suppressions éventuelles sont explicites via un manifeste de suppression lorsque le mécanisme d'application l'exige ; elles ne reposent pas sur une instruction manuelle ambiguë.
Le document de delta indique au minimum :
- baseline requise et version obtenue ;
- mission et scope ;
- fichiers/contrats réellement concernés ;
- hors-scope et décisions différées pertinentes ;
- gate opérateur reproductible ;
- transition autorisée après chaque statut attendu.
Un delta doit être applicable sans reconstruire à la main des patchs depuis une conversation.
## Contrat d'un history
Aucun history `PASS` n'est créé avant réception des preuves opérateur réelles. Une prévalidation de génération peut détecter des erreurs, mais ne constitue jamais le résultat autoritaire de la tranche.
Le history enregistre au minimum :
- tranche et baseline observées ;
- statut `PASS / FAIL / PARTIAL / BLOCKED` ;
- preuves réellement exécutées et leurs résultats utiles ;
- anomalies/limites pertinentes ;
- décision de transition.
Un history appliqué et committé devient immuable. Un futur fix crée son propre history ; il ne remplace pas le résultat précédent.
## Plans et REPLAN
Une release multi-responsabilités possède un plan versionné. Le plan décrit mission, état acquis, scope, hors-scope, validation, trajectoire prévisionnelle, déclencheurs de REPLAN, clôture/transition et revue d'horizon lorsque pertinente.
Les tranches de la trajectoire sont des sous-sections `###` de `## Trajectoire prévisionnelle`.
Un REPLAN modifie uniquement les parties devenues fausses ou insuffisantes. Les deltas/histories gardent la chronologie détaillée ; le plan reste un document de pilotage vivant et non un journal de terminal.
## Fixes
Un `FAIL`, `PARTIAL` ou `BLOCKED` est conservé. Une correction bornée au même scope utilise `.fix.N`. Le history en échec est appliqué, committé et poussé avant le fix.
Un fix ne doit pas absorber silencieusement une nouvelle fonctionnalité. Si le diagnostic révèle une responsabilité transverse ou une mission différente, le plan est replanifié explicitement.
## Handoff opérateur
Après livraison d'un history, les commandes de matérialisation Git sont fournies automatiquement. Pour `origin/master` établi dans ce dépôt, une tranche non stable suit normalement :
```bash
git add -A
git diff --cached --check
git status --short
git commit -m "<VERSION>"
git push origin master
git status --short
```
Les commandes ne sont pas différées à une réponse ultérieure. Lorsque le delta suivant est prêt, son application est indiquée après ce bloc afin que l'ordre soit sans ambiguïté.
## Prompts et changement de session
Un prompt de démarrage versionné décrit la baseline exacte, les sources requises, la mission et les vérifications nécessaires pour ouvrir une release. Il ne complète pas silencieusement des données manquantes par un état supposé d'une conversation ou d'un workspace non vérifié.
Une coupure de session au milieu d'une tranche ne change pas `VERSION`. Si nécessaire, un handoff local décrit l'état exact, les décisions acquises, les preuves déjà obtenues et ce qui reste à exécuter.
Le pattern normal de nouvelle session est [`../templates/001-NEW_SESSION_PROMPT.md`](../templates/001-NEW_SESSION_PROMPT.md).
## Stable et publication
La première clôture `rel.N[/fix.M]` réellement `PASS` est committée avec le message produit `X.Y.Z`; les clôtures échouées conservent leur identifiant de tranche dans le message de commit conformément à la gouvernance locale.
Le tag stable `vX.Y.Z` est créé seulement après le commit stable. L'archive téléchargée depuis ce tag est la baseline de publication autoritaire ; l'absence de `.git` dans cette archive est normale.
Le rapport post-tag `sasedev-knowledge-X.Y.Z-publish.001-report.md` est une preuve distincte. Il vérifie le tag/archive réellement publiés et ne doit pas être préfabriqué comme preuve du delta `rel.1`.
Le prompt d'une release suivante n'est préparé que si sa mission est réellement décidée. Aucune version future n'est inventée pour remplir un handoff.
## Immutabilité des artefacts historiques
Les deltas, histories et prompts déjà committés ne sont pas réécrits pour adopter une convention plus récente, corriger une esthétique ou masquer un échec passé. Une correction de contrat durable s'applique aux artefacts futurs et est documentée chez son owner local.

View File

@@ -0,0 +1,93 @@
<!-- file: docs/rules/300-DOCUMENTATION.md -->
<!-- version: 1 -->
# Documentation locale Knowledge
## Langue et identités
Les noms techniques, chemins, fichiers, crates, identifiants et code sont en anglais. La documentation normative et explicative principale est en français.
Chaque fichier Markdown gouverné par Knowledge commence par :
```text
<!-- file: <chemin relatif exact> -->
<!-- version: <entier positif> -->
```
La révision documentaire augmente lorsqu'un contenu réel du fichier change ; elle n'est pas un compteur global de release et ne doit pas être synchronisée mécaniquement avec `VERSION`.
## Rôle des documents racine
`README.md` est une entrée de projet : identité, état utile, démarrage et liens vers les owners. Il ne devient pas une copie complète des règles ou de l'architecture.
`RULES.md` est l'entrée normative locale et renvoie vers les owners détaillés sous `docs/rules/`.
`ROADMAP.md` décrit les objectifs et horizons produits réellement engagés. Il ne sert ni de journal quotidien ni de catalogue exhaustif des prereleases. Une version future n'y est pas réservée sans mission réelle.
`CHANGELOG.md` synthétise les changements utiles aux jalons de release. Les fixes et essais alpha internes ne sont pas transformés en catalogue exhaustif lorsque leur détail appartient déjà aux deltas/histories.
`docs/000-README.md` indexe la documentation durable et fournit le chemin de lecture principal.
## Familles documentaires
Knowledge distingue :
```text
RULES / docs/rules contrat normatif local
docs/architecture architecture et décisions structurantes
docs/studies analyse avant décision ou réconciliation
docs/plans pilotage vivant d'une release multi-tranches
docs/validation matrices, critères et contrats de preuve
docs/templates patterns locaux réutilisables
prompts handoff versionné d'ouverture d'une release
deltas contrat d'une tranche à appliquer
history résultat réellement observé d'une tranche
```
Un delta/history ne remplace pas la documentation durable. Une décision structurante acquise finit chez son owner durable lorsqu'elle doit gouverner la suite.
## Documents vivants et historiques
`RULES.md`, `docs/rules/`, l'architecture, la roadmap et un plan actif sont des documents vivants : ils évoluent lorsque leur contrat actuel change.
`deltas/`, `history/` et les prompts de releases passées sont historiques après commit. Ils ne sont pas réécrits uniquement pour se conformer à une nouvelle convention apparue plus tard.
Une étude terminée peut rester historique tout en étant référencée depuis la décision durable qu'elle a permis d'établir.
## Plans
Un plan actif contient au minimum, lorsque pertinent : statut/sources, mission, état acquis/questions ouvertes, scope, hors-scope, stratégie de validation, trajectoire prévisionnelle, déclencheurs de REPLAN, clôture/transition et revue d'horizon.
Les phases prévisionnelles se trouvent sous `## Trajectoire prévisionnelle` et utilisent des headings `###`.
Le plan est mis à jour lorsqu'une hypothèse de pilotage devient fausse, pas pour recopier chaque sortie de commande. Les preuves détaillées appartiennent aux histories.
## Revue d'horizon
Lorsqu'une release approche de sa stabilisation et que la suite n'est pas déjà décidée, une revue d'horizon explicite détermine s'il faut engager une prochaine mission, maintenir les domaines futurs non numérotés ou reclasser un `DEFER`.
La revue n'invente pas un numéro de version uniquement pour assurer la continuité documentaire.
## Prompts de nouvelle session
Un prompt normal Knowledge repart de la stable Knowledge, de son rapport post-tag lorsqu'il existe, puis du prompt versionné local. Il vérifie les artefacts Knowledge locaux avant de préparer la tranche suivante.
Il MUST NOT demander de rechercher ou charger PGR ou un autre référentiel externe, sauf lorsque cette release contient explicitement une réévaluation/adoption de ce référentiel.
Le pattern local est [`../templates/001-NEW_SESSION_PROMPT.md`](../templates/001-NEW_SESSION_PROMPT.md).
## Templates
Les templates locaux sont des patterns adaptables, pas des documents normatifs à recopier aveuglément. L'owner normatif reste la règle locale correspondante ; un template sert à réduire les omissions lors de la création d'un nouvel artefact.
## Liens, tables et audits
Les liens Markdown locaux doivent pointer vers des cibles existantes. Les tables source doivent rester syntaxiquement cohérentes. Les arbres générés (`.git`, `node_modules`, `target`, `builds`) n'appartiennent pas au corpus documentaire gouverné.
Les audits Markdown locaux sont read-only :
```text
scripts/audit_markdown_headers.py
scripts/audit_markdown_links.py
scripts/audit_markdown_tables.py
```

View File

@@ -0,0 +1,103 @@
<!-- file: docs/rules/400-VALIDATION.md -->
<!-- version: 1 -->
# Validation locale Knowledge
## Principe
Une tranche sélectionne ses preuves à partir du scope modifié, des contrats potentiellement invalidés et du risque réel. La validation est proportionnée : elle ne rejoue pas mécaniquement toutes les commandes disponibles lorsque celles-ci n'apportent aucune preuve nouvelle.
La matrice canonique est [`../validation/001-VALIDATION_MATRIX.md`](../validation/001-VALIDATION_MATRIX.md).
## Statuts
Les statuts reconnus sont :
```text
PASS toutes les preuves requises ont réussi
FAIL au moins une preuve requise a échoué
PARTIAL seules certaines preuves requises ont été acquises
BLOCKED un prérequis externe empêche d'exécuter une preuve requise
```
Un statut incomplet ne devient jamais implicitement `PASS`.
## Autorité de la gate
La gate opérateur exécutée dans l'environnement autoritaire possède le statut de tranche. Une prévalidation par assistant, génération locale ou CI supplémentaire peut réduire le risque de livraison mais ne remplace pas cette gate.
Une commande qui échoue dans la gate reste un `FAIL` même si des tests exécutés ensuite passent. Les preuves positives sont conservées dans le diagnostic mais ne neutralisent pas l'échec requis.
## Catégories de preuve
Les gates peuvent combiner, selon le scope :
```text
FORMAT état produit par le formatter officiel
AUDIT contrat structurel read-only non possédé par l'outil officiel
CHECK compilation/typecheck/manifest sans production nécessaire d'artefact
LINT politique statique stricte
TEST comportement ciblé ou workspace
BUILD production d'un artefact réellement nécessaire
SMOKE preuve d'intégration/processus/frontière runtime
PACKAGE layout ou archive de livraison
PUBLISH tag/archive/remote effectivement publiés
```
Une catégorie n'est pas ajoutée pour remplir un quota ; elle doit protéger une propriété affectée par la tranche.
## Niveau de preuve
Une propriété est vérifiée au niveau le plus fiable et le moins redondant disponible :
```text
compilateur / langage
-> outil officiel ou linter
-> manifest / build system
-> audit structurel read-only
-> test comportemental
-> smoke d'intégration lorsque l'environnement le nécessite
```
Une règle qualitative qui exige du jugement humain reste une revue plutôt qu'une regex fragile créée uniquement pour automatiser.
## Tests
Les tests ciblés sont privilégiés pour le scope directement modifié. Les tests workspace sont utilisés lorsqu'un contrat transverse, un changement de structure ou une phase de consolidation peut invalider plusieurs composants.
Les tests unitaires doivent rester indépendants d'Internet et de services externes non contrôlés. Un test d'intégration réel peut utiliser des ressources locales isolées et temporaires lorsqu'il prouve une frontière que des fakes ne démontrent pas correctement.
Un test ne modifie pas l'API produit uniquement pour faciliter son accès à des détails internes.
## Audits
Les audits locaux sont read-only et monotâches autant que raisonnable. Ils contrôlent une propriété du dépôt que le compilateur, rustfmt, Clippy, Cargo, TypeScript, npm ou Vite ne possède pas déjà de manière fiable.
Un audit ne doit pas analyser les caches et dépendances générés comme s'ils faisaient partie du source gouverné. Les scripts Markdown locaux ignorent notamment `.git`, `node_modules`, `target` et `builds`.
Lorsqu'un audit lexical rencontre un cas que son modèle ne sait pas interpréter sans heuristique fragile, la propriété revient à l'outil officiel ou à une revue humaine plutôt qu'à un faux positif permanent.
## Ordre normal
Pour une tranche Rust transverse, la séquence habituelle est :
```text
format
-> audits structurels applicables
-> cargo check / metadata utile
-> clippy strict
-> tests ciblés
-> tests workspace si justifiés
-> smokes/builds/packages seulement si le scope les invalide
-> git diff --cached --check / status
```
Pour une tranche Web, les preuves npm/typecheck/build sont ajoutées lorsque `Web/` ou son contrat d'intégration est touché. Une tranche documentaire ou Rust sans diff Web ne rejoue pas automatiquement le frontend.
## Régression et dette externe
Un warning provenant d'une dépendance tierce n'est pas automatiquement un `FAIL` si la gate locale ne le traite pas comme tel et si l'outil termine avec succès. Il doit toutefois être reclassé si une mise à jour de toolchain le transforme en rupture réelle ou si la release cible exige zéro warning sur cette frontière.
## Traçabilité
Chaque delta liste sa gate exécutable et la matrice conserve le contrat durable. Le history enregistre les résultats réellement observés ; il ne résume pas une prévalidation comme si elle avait été exécutée par l'opérateur.

View File

@@ -0,0 +1,79 @@
<!-- file: docs/rules/510-RUST_CARGO.md -->
<!-- version: 1 -->
# Rust / Cargo local Knowledge
## Toolchain et workspace
Knowledge utilise Rust stable, édition 2024 et un workspace Cargo à train de release unique. `[workspace.package].version` suit `VERSION` et les crates membres héritent de la version commune.
Aucun `rust-toolchain.toml` n'est ajouté sans besoin réel de reproductibilité ou de compatibilité. Les artefacts Cargo sont dirigés hors de l'arborescence source par la configuration locale lorsque possible.
`Cargo.lock` est généré localement, ignoré et non versionné pour ce workspace. Cette politique ne s'applique pas au lockfile npm.
## Nomenclature et responsabilités
Les crates utilisent le préfixe `knowledge-`. Les suffixes portent un contrat :
```text
-api frontière passive de contrats réutilisables/remplaçables
-lib implémentation ou fonctionnalité réutilisable
-server launcher/processus mince
```
Une crate n'est pas créée par symétrie. Une `-api` ne contient ni runtime, ni logging imposé, ni implémentation de provider. Un launcher ne duplique pas une logique qui possède un owner bibliothèque commun.
## Façade crate-root
Pour toute crate bibliothèque Knowledge, `src/lib.rs` est une façade de crate. Il contient la documentation de crate, les déclarations de modules, les réexports publics/internes nécessaires et, lorsque pertinent, le rattachement conditionnel des tests.
Les `struct`, `enum`, `trait`, fonctions, implémentations et autres définitions de comportement appartiennent à des modules nommés selon leur responsabilité. Une petite crate n'est pas artificiellement éclatée en nombreux fichiers : un seul module de responsabilité peut suffire, mais les définitions ne s'accumulent pas dans `lib.rs`.
Les crates `-api` nomment leurs modules par le contrat réel (`reference`, `revision`, `snapshot`, `repository`, `signal`, etc.) plutôt que par un générique `api.rs` sans ownership.
Les consommateurs externes utilisent la façade `owner_crate::Item`. Les références intra-crate vers des items partagés passent par `crate::Item` afin de garder une identité stable indépendante du module propriétaire.
`scripts/audit_rust_crate_root_facades.py` contrôle que les crate-roots de bibliothèque restent des façades sans définitions top-level de production.
## Safety, erreurs et contrôle de flux
`unsafe` est interdit par défaut. Les lints workspace stricts restent autoritaires.
Le code de production ne doit pas utiliser `unwrap`, `expect`, `panic!` ou l'opérateur `?` lorsque les lints locaux les interdisent. Les erreurs récupérables sont propagées explicitement avec le type d'erreur possédé par la couche concernée.
Les retours explicites exigés par la politique Clippy locale sont conservés, y compris dans les closures lorsque le lint `implicit_return` s'applique.
## Imports, modules et réexports
Les `use` non exportés sont réservés aux imports réellement nécessaires, notamment les traits. Les modules de production précèdent les modules de tests conditionnels et suivent un ordre déterministe lorsqu'aucune sémantique ne l'interdit.
Les réexports crate-root restent groupés par visibilité. La façade publique doit être complète pour les items partagés et les modules propriétaires restent privés sauf besoin architectural explicite.
## Tests
Les tests unitaires résident sous `unit_tests/` à la racine de chaque crate et sont rattachés depuis le module source correspondant. Les tests d'intégration Cargo résident sous `tests/` et consomment l'API publique.
Les tests ne rendent pas l'API produit plus visible uniquement pour accéder à des détails internes.
## Formatage et audits
La séquence normale d'un changement Rust pertinent inclut :
```bash
cargo fmt --all
cargo fmt --all -- --check
python3 -B scripts/audit_rust_test_layout.py crates
python3 -B scripts/audit_rust_blank_lines.py crates
python3 -B scripts/audit_rust_item_spacing.py crates
python3 -B scripts/audit_rust_module_order.py crates
python3 -B scripts/audit_rust_trait_import_blocks.py crates
python3 -B scripts/audit_rust_reexport_blocks.py crates
python3 -B scripts/audit_rust_crate_root_facades.py crates
python3 -B scripts/audit_rust_export_completeness.py --root . --summary-only
cargo check --workspace
cargo clippy --workspace --all-targets --all-features -- -D warnings
```
Les tests ciblés sont sélectionnés selon le scope. `cargo test --workspace --all-targets --all-features` est utilisé pour les changements transverses et les phases de consolidation.
L'audit mécanique des blocs `const` n'est pas sélectionné globalement par Knowledge : l'ordre de constantes peut être sémantique. Il ne sera ajouté localement que si un besoin réel et un corpus approprié le justifient.

View File

@@ -0,0 +1,57 @@
<!-- file: docs/rules/530-WEB_FRONTEND.md -->
<!-- version: 1 -->
# Frontend Web local Knowledge
## Scope
Cet owner regroupe les contrats Web réellement utilisés par Knowledge : TypeScript, npm, Vite, Sass, Bootstrap et l'articulation entre le template statique de référence et le rendu runtime Maud.
Il remplace, pour le développement courant de Knowledge, la nécessité de relire plusieurs profils Web externes séparés.
## Package et dépendances
Le package de référence est `Web/knowledge-template-lab/` et utilise npm. `package.json` possède les scripts explicites `typecheck`, `dev`, `build` et `preview` nécessaires au workflow courant.
`package-lock.json` est versionné. `node_modules/`, caches Vite et sorties de build restent générés et hors Git.
Les versions de dépendances sont décidées dans le package Knowledge ; aucune version externe n'est adoptée automatiquement parce qu'un template ou référentiel plus récent existe.
## TypeScript
Le frontend utilise TypeScript strict. Le typecheck doit couvrir le code applicatif et la configuration Vite selon les `tsconfig` locaux.
Une dépendance de types n'est ajoutée que lorsqu'elle est réellement nécessaire à l'IDE, au compilateur ou au package consommé.
## Vite
`vite.config.ts` est le propriétaire de `root`, `base`, cache, dev server, preview, outputs et manifest. Les caches et builds sont dirigés vers les outputs Knowledge hors source.
Le build de production doit générer un manifest machine-readable et conserver l'entrée stable `src/main.ts`. Les noms d'assets hashés ne sont pas codés en dur dans le backend Rust.
## Sass et Bootstrap
Sass est la chaîne de styles sélectionnée et Bootstrap est un choix local Knowledge. Les warnings de dépréciation provenant d'une dépendance tierce sont suivis comme dette/compatibilité mais ne deviennent bloquants que si la gate locale l'exige ou s'ils annoncent une rupture effective de la toolchain retenue.
## Template statique et Maud
Le template sous `Web/knowledge-template-lab/` sert de harness de conception et de validation. Il ne constitue pas une seconde implémentation runtime.
Le markup de production est rendu par `knowledge-web-lib` avec Maud. L'adaptation depuis le template doit préserver les contrats utiles de structure, classes, attributs et assets.
En développement, `KNOWLEDGE_VITE_DEV_ORIGIN` fournit l'origin Vite. En production, `KNOWLEDGE_VITE_MANIFEST_PATH` désigne le manifest et `KNOWLEDGE_ASSET_BASE_PATH` peut remplacer le préfixe public.
## Validation
Lorsqu'un changement touche le package Web ou son contrat d'intégration, la preuve normale est :
```bash
(
cd Web/knowledge-template-lab
npm ci
npm run typecheck
npm run build
)
```
Les smokes Actix/Maud pertinents sont ajoutés lorsqu'un changement touche réellement le runtime ou la résolution d'assets. Une tranche exclusivement documentaire ou Rust sans diff Web ne rejoue pas automatiquement le build frontend si aucune preuve n'est invalidée.

View File

@@ -0,0 +1,26 @@
<!-- file: docs/templates/001-NEW_SESSION_PROMPT.md -->
<!-- version: 1 -->
# Pattern local — prompt de nouvelle session
## Usage
Ce pattern prépare le court message opérateur remis après une stable Knowledge publiée. Le prompt détaillé reste un fichier versionné sous `prompts/`.
Une session normale Knowledge ne consulte pas PGR. Une mention PGR n'apparaît que lorsque la release cible contient explicitement une réévaluation/adoption PGR.
## Forme normale
Lorsque le rapport post-tag de la baseline est `PASS` :
```text
Partir de l'archive sasedev-knowledge-vX.Y.Z.zip téléchargée depuis le tag Gitea vX.Y.Z et du rapport post-tag sasedev-knowledge-X.Y.Z-publish.001-report.md. Lire et exécuter prompts/NNN-<NEXT_RELEASE>_START_PROMPT.md. Vérifier intégralement l'archive Knowledge, les règles locales, la gouvernance, l'architecture, la structure documentaire, les deltas/histories, les décisions différées et la cohérence globale avant de préparer <NEXT_RELEASE>-alpha.1.
```
`X.Y.Z` désigne la stable autoritaire de départ et `<NEXT_RELEASE>` la release suivante réellement décidée ; ces deux valeurs ne sont pas supposées identiques.
Les noms et versions sont remplacés uniquement par des valeurs établies. Si le rapport post-tag n'existe pas ou n'est pas `PASS`, il n'est pas présenté comme preuve.
## Réévaluation externe explicite
Si et seulement si le plan de la release contient une adoption externe, le prompt peut demander de fournir en plus l'archive/rapport exacts du référentiel concerné. Cette exception doit être visible dans le scope du prompt ; elle ne devient jamais le comportement par défaut des sessions suivantes.

33
docs/templates/002-RELEASE_PLAN.md vendored Normal file
View File

@@ -0,0 +1,33 @@
<!-- file: docs/templates/002-RELEASE_PLAN.md -->
<!-- version: 1 -->
# Pattern local — plan de release
## Contrat minimal
Un plan multi-tranches Knowledge utilise normalement :
```text
## Statut et sources
## Mission
## État acquis et questions ouvertes
## Scope
## Hors scope
## Stratégie de validation
## Trajectoire prévisionnelle
### alpha.N — ...
### beta.N — ...
### rc.N — ...
### rel.N — ...
## Déclencheurs de REPLAN
## Clôture et transition
## Revue d'horizon
```
Le nombre de tranches n'est pas fixé. Les phases annoncées restent sous `## Trajectoire prévisionnelle` avec un heading `###`.
## Règles
Le plan pilote le travail restant ; il n'est pas un journal de commandes. Les preuves détaillées vivent dans `history/` et les règles durables vivent chez leur owner local.
Un REPLAN met à jour la trajectoire et les responsabilités devenues fausses. Aucune version postérieure n'est réservée uniquement pour remplir la roadmap.

29
docs/templates/003-OPERATOR_HANDOFF.md vendored Normal file
View File

@@ -0,0 +1,29 @@
<!-- file: docs/templates/003-OPERATOR_HANDOFF.md -->
<!-- version: 1 -->
# Pattern local — handoff opérateur
## Après un history de prerelease
Lorsque `origin/master` est établi :
```bash
git add -A
git diff --cached --check
git status --short
git commit -m "<VERSION_DE_LA_TRANCHE>"
git push origin master
git status --short
```
Si le delta suivant est livré dans la même réponse, son application vient seulement après ce bloc.
## Après un FAIL suivi d'un fix
Le history `FAIL` est appliqué et committé avec l'identité de la tranche en échec avant d'appliquer `.fix.N`. Il n'est jamais remplacé ou fusionné avec le futur history `PASS`.
## Première fermeture stable
La première tranche `rel.N[/fix.M]` qui obtient le `PASS` stable est committée avec le message produit `X.Y.Z`, puis le tag `vX.Y.Z` est créé/poussé selon la politique locale et vérifié avant le rapport post-tag.
Les commandes exactes de tag/publication sont fournies avec les valeurs réellement établies au moment de la clôture.

View File

@@ -0,0 +1,37 @@
<!-- file: docs/templates/004-RUST_LIBRARY_CRATE.md -->
<!-- version: 1 -->
# Pattern local — crate bibliothèque Rust
## But
Ce pattern illustre la structure minimale attendue d'une crate bibliothèque Knowledge. Il ne crée pas une crate par anticipation et ne remplace pas [`../rules/510-RUST_CARGO.md`](../rules/510-RUST_CARGO.md).
## Façade
`src/lib.rs` reste une façade :
```rust
//! Documentation de crate.
mod responsibility;
/// Contrat public exposé par la crate.
pub use self::responsibility::PublicItem;
```
Les définitions résident dans le module propriétaire :
```rust
// file: crates/<crate>/src/responsibility.rs
// version: 1
/// Contrat public possédé par cette responsabilité.
pub struct PublicItem;
```
Pour plusieurs responsabilités distinctes, créer plusieurs modules nommés selon leur rôle réel. Ne pas créer un fichier `api.rs`, `common.rs` ou `utils.rs` uniquement pour déplacer du code sans clarifier l'ownership.
## Tests
Les tests unitaires vivent sous `unit_tests/` et sont rattachés au module source correspondant. Les tests d'intégration vivent sous `tests/` et consomment l'API publique.

View File

@@ -1,5 +1,5 @@
<!-- file: docs/validation/001-VALIDATION_MATRIX.md --> <!-- file: docs/validation/001-VALIDATION_MATRIX.md -->
<!-- version: 24 --> <!-- version: 25 -->
# Matrice de validation Knowledge # Matrice de validation Knowledge
@@ -658,3 +658,26 @@ Le fix ferme les défauts techniques d'`alpha.3` et enregistre le REPLAN sans é
- `git diff --cached --check` propre avant commit. - `git diff --cached --check` propre avant commit.
Le `PASS` de `alpha.3.fix.1` ferme `alpha.3` et autorise uniquement la préparation de `0.0.2-alpha.4`. Le `PASS` de `alpha.3.fix.1` ferme `alpha.3` et autorise uniquement la préparation de `0.0.2-alpha.4`.
## Gate de `0.0.2-alpha.4`
La tranche d'autonomie normative et de structure interne doit prouver :
- `VERSION = 0.0.2-alpha.4` et version workspace identique ;
- history `history/0.0.2/alpha.3.fix.1.md` présent avec statut `PASS` et committé avant application ;
- owners locaux `200`, `210`, `300`, `400`, `510` et `530-WEB_FRONTEND` présents, indexés et suffisamment complets pour retrouver localement lifecycle/versioning, fixes/REPLAN, delta/history/handoff, rôles documentaires et catégories de preuve ;
- mapping d'adoption `003-PGR_ADOPTION_MAP.md` présent, PGR `v0.1.3` seulement comme provenance et aucune consultation PGR automatique requise ;
- templates locaux de nouvelle session, release plan, handoff opérateur et crate bibliothèque présents ;
- audits Markdown headers/liens/tables possédés localement et propres ;
- audit `audit_rust_crate_root_facades.py` propre sur toutes les crates bibliothèque ;
- `knowledge-git-api/src/lib.rs` limité à documentation/module declarations/réexports/test attachment, avec définitions déplacées vers `reference`, `repository`, `revision`, `snapshot` ;
- `knowledge-sync-api/src/lib.rs` limité à façade, avec définitions déplacées vers `event_source` et `signal` ;
- API publique crate-root inchangée pour `GitReference`, `GitRevision`, `GitSnapshot`, `GitRepository`, `RepositorySyncCause`, `RepositorySyncSignal`, `RepositoryEventSource` ;
- `knowledge-domain-lib`, `knowledge-git-lib` et `knowledge-web-lib` déjà conformes à la façade crate-root sans refactor artificiel ;
- comportement Git `alpha.3` inchangé et tests réels toujours propres ;
- `cargo fmt --all -- --check`, audits Rust, `cargo metadata`, `cargo check`, Clippy strict, tests ciblés `knowledge-git-api`/`knowledge-sync-api`/`knowledge-git-lib` et tests workspace propres ;
- `Web/` sans diff et aucun `knowledge-app-lib`, adapter forge ou store PostgreSQL ajouté ;
- `Cargo.lock` ignoré/non suivi ;
- `git diff --cached --check` propre avant commit.
Le `PASS` d'`alpha.4` ferme l'adoption PGR `v0.1.3` comme migration ponctuelle et autorise uniquement la préparation de `0.0.2-alpha.5`.

144
history/0.0.2/alpha.4.md Normal file
View File

@@ -0,0 +1,144 @@
<!-- file: history/0.0.2/alpha.4.md -->
<!-- version: 1 -->
# History 0.0.2-alpha.4 — autonomie normative et façades de crates
## Statut
FAIL
La gate opérateur de `0.0.2-alpha.4` exécutée le `2026-09-28` valide l'autonomie documentaire, les audits locaux et la structure des façades, mais la tranche ne compile pas à cause de deux constructions de tuple structs privés depuis leurs réexports crate-root.
## Baseline opérateur
`alpha.3.fix.1` `PASS` a été historisé, committé et poussé avant application d'`alpha.4` :
```text
history/0.0.2/alpha.3.fix.1.md PASS
commit b9508b0
message 0.0.2-alpha.3.fix.1
branch master
push origin/master PASS
workspace après push propre
```
Le push observé a avancé `origin/master` de `721e8a6` à `b9508b0`.
## Version et autonomie normative
Les contrôles de version et de provenance passent :
```text
VERSION 0.0.2-alpha.4
Cargo workspace version 0.0.2-alpha.4
history alpha.3.fix.1 PASS
```
Les audits Markdown possédés localement passent :
```text
Markdown header audit: clean (80 file(s))
Markdown link audit: clean (71 local link(s), 80 file(s))
Markdown table audit: clean (4 table(s), 80 file(s))
```
L'audit d'autonomie/structure passe :
```text
Knowledge 0.0.2-alpha.4 autonomy/structure audit: clean
```
Les owners locaux `200`, `210`, `300`, `400`, `510` et `530-WEB_FRONTEND`, le mapping d'adoption, les templates locaux et les audits Markdown/Rust attendus sont présents. PGR `v0.1.3` reste une provenance d'adoption et aucune consultation PGR automatique n'est requise.
## Audits Rust et formatage
Les audits structurels passent :
```text
Rust test-layout audit: clean (8 crate(s))
Rust blank-line audit: clean (29 file(s))
Rust item-spacing audit: clean (29 file(s))
Rust module-order audit: clean (29 file(s))
Rust trait-import-block audit: clean (29 file(s))
Rust re-export-block audit: clean (29 file(s))
Rust crate-root facade audit: clean (5 crate root(s))
Rust export completeness audit: 0 candidate(s) across 8 package(s)
```
`cargo fmt --all -- --check` passe.
## Compilation et Clippy
`cargo check --workspace` échoue dans `knowledge-git-api` sur deux erreurs `E0423` :
```text
crates/knowledge-git-api/src/reference.rs:11
return crate::GitReference(value.to_owned());
crates/knowledge-git-api/src/revision.rs:11
return crate::GitRevision(value.to_owned());
```
Après déplacement des types dans leurs modules propriétaires, leurs champs tuple privés ne sont plus constructibles via le réexport crate-root. Les deux implémentations doivent construire leur propre type avec `Self(...)`.
Clippy strict échoue pour les mêmes deux erreurs de compilation. Aucun assouplissement de visibilité ou de lint n'est justifié.
## Tests
`knowledge-sync-api` compile et son test passe :
```text
cargo test -p knowledge-sync-api --all-targets --all-features
1 passed; 0 failed
```
Les suites `knowledge-git-api`, `knowledge-git-lib` et workspace sont bloquées par la compilation de `knowledge-git-api` et ne peuvent donc pas valider la tranche.
## Métadonnées et frontières
L'audit Cargo passe :
```text
Knowledge 0.0.2-alpha.4 Cargo metadata audit: clean
```
Les huit packages attendus sont présents. `Cargo.lock` est présent localement, ignoré et non suivi.
Les contrôles de frontière passent :
```text
Web/ sans diff
crates/knowledge-git-lib/src sans diff
crates/knowledge-app-lib absent
crates/knowledge-forge-gitea-lib absent
crates/knowledge-store-postgres-lib absent
history/0.0.2/alpha.4.md absent avant clôture
```
Le staging final est propre à la tranche et `git diff --cached --check` passe.
## Diagnostic
L'architecture `alpha.4` n'est pas remise en cause. Le défaut est local aux constructeurs des deux tuple structs après séparation de `lib.rs` en modules propriétaires.
Le correctif doit uniquement :
- construire `GitReference` avec `Self(value.to_owned())` dans son propre `impl` ;
- construire `GitRevision` avec `Self(value.to_owned())` dans son propre `impl` ;
- conserver l'API publique crate-root inchangée ;
- rejouer la gate complète `alpha.4` sans modifier les autres owners, templates, audits ou comportements Git/sync.
## Décision
`0.0.2-alpha.4` est `FAIL`.
La transition autorisée est :
```text
appliquer ce history
-> git add / diff --cached --check / status
-> commit exact "0.0.2-alpha.4"
-> push origin master
-> vérifier le workspace propre
-> appliquer seulement ensuite 0.0.2-alpha.4.fix.1
```

View File

@@ -0,0 +1,96 @@
#!/usr/bin/env python3
# file: scripts/audit_markdown_headers.py
# version: 1
"""Validate path and positive revision in selected Markdown file headers."""
from __future__ import annotations
import argparse
import pathlib
import re
import sys
_IGNORED_DIRECTORIES = frozenset({".git", ".idea", ".venv", "__pycache__", "dist", "node_modules", "target", "builds"})
_VERSION = re.compile(r"<!-- version: [1-9][0-9]* -->")
def _selected_files(raw_paths: list[str], root: pathlib.Path) -> tuple[list[pathlib.Path], list[str]]:
files: set[pathlib.Path] = set()
errors: list[str] = []
for raw_path in raw_paths:
path = pathlib.Path(raw_path)
if path.is_dir() or path.is_file():
if not path.resolve().is_relative_to(root):
errors.append(f"Markdown header audit: path outside project root: {path}")
continue
if path.is_dir():
candidates = (
candidate
for candidate in path.rglob("*.md")
if candidate.is_file() and not any(part in _IGNORED_DIRECTORIES for part in candidate.parts)
)
elif path.is_file() and path.suffix.lower() == ".md":
candidates = iter((path,))
else:
errors.append(f"Markdown header audit: unsupported or missing path: {path}")
continue
for candidate in candidates:
canonical = candidate.resolve()
if not canonical.is_relative_to(root):
errors.append(f"Markdown header audit: path outside project root: {candidate}")
else:
files.add(canonical)
return sorted(files), errors
def _audit_file(path: pathlib.Path, root: pathlib.Path) -> list[str]:
relative = path.relative_to(root).as_posix()
lines = path.read_text(encoding="utf-8").splitlines()
errors: list[str] = []
expected_file = f"<!-- file: {relative} -->"
if not lines or lines[0] != expected_file:
errors.append(f"{relative}:1: expected `{expected_file}`")
if len(lines) < 2 or _VERSION.fullmatch(lines[1]) is None:
errors.append(f"{relative}:2: expected positive `<!-- version: N -->`")
return errors
def main() -> int:
"""Run the read-only Markdown header audit from the project root."""
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("paths", nargs="+", help="Markdown files or directories to audit")
args = parser.parse_args()
root = pathlib.Path.cwd().resolve()
files, selection_errors = _selected_files(args.paths, root)
if selection_errors or not files:
for error in selection_errors or ["Markdown header audit: no Markdown files selected"]:
print(error, file=sys.stderr)
return 2
errors: list[str] = []
for path in files:
try:
errors.extend(_audit_file(path, root))
except (OSError, UnicodeError) as error:
print(f"Markdown header audit: cannot read {path}: {error}", file=sys.stderr)
return 2
for error in errors:
print(error, file=sys.stderr)
if errors:
print(f"Markdown header audit: {len(errors)} error(s) across {len(files)} file(s)", file=sys.stderr)
return 1
print(f"Markdown header audit: clean ({len(files)} file(s))")
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -0,0 +1,131 @@
#!/usr/bin/env python3
# file: scripts/audit_markdown_links.py
# version: 1
"""Validate that local inline Markdown link targets exist."""
from __future__ import annotations
import argparse
import pathlib
import re
import sys
import urllib.parse
_IGNORED_DIRECTORIES = frozenset({".git", ".idea", ".venv", "__pycache__", "dist", "node_modules", "target", "builds"})
_INLINE_LINK = re.compile(r"(?<!!)\[[^\]]+\]\(([^)]+)\)")
def _selected_files(raw_paths: list[str]) -> tuple[list[pathlib.Path], list[str]]:
files: list[pathlib.Path] = []
errors: list[str] = []
for raw_path in raw_paths:
path = pathlib.Path(raw_path)
if path.is_dir():
files.extend(
candidate
for candidate in path.rglob("*.md")
if candidate.is_file() and not any(part in _IGNORED_DIRECTORIES for part in candidate.parts)
)
elif path.is_file() and path.suffix.lower() == ".md":
files.append(path)
else:
errors.append(f"Markdown link audit: unsupported or missing path: {path}")
return sorted(set(files)), errors
def _destination(raw_destination: str) -> str:
destination = raw_destination.strip()
if destination.startswith("<"):
closing = destination.find(">")
return destination[1:closing] if closing > 0 else destination
return destination.split(maxsplit=1)[0] if destination else ""
def _local_target(destination: str) -> str | None:
if not destination or destination.startswith("#") or destination.startswith("//"):
return None
parsed = urllib.parse.urlsplit(destination)
if parsed.scheme or parsed.netloc:
return None
target = urllib.parse.unquote(parsed.path)
return target or None
def _audit_file(path: pathlib.Path) -> tuple[int, list[str]]:
errors: list[str] = []
checked = 0
fence: str | None = None
for line_number, line in enumerate(path.read_text(encoding="utf-8").splitlines(), start=1):
stripped = line.lstrip()
if stripped.startswith("```") or stripped.startswith("~~~"):
marker = stripped[:3]
if fence is None:
fence = marker
elif fence == marker:
fence = None
continue
if fence is not None:
continue
for match in _INLINE_LINK.finditer(line):
destination = _destination(match.group(1))
target = _local_target(destination)
if target is None:
continue
checked += 1
if target.startswith("/"):
candidate = pathlib.Path.cwd() / target.lstrip("/")
else:
candidate = path.parent / target
if not candidate.exists():
errors.append(f"{path}:{line_number}: missing local Markdown target: {destination}")
return checked, errors
def main() -> int:
"""Run the read-only local Markdown link audit."""
parser = argparse.ArgumentParser()
parser.add_argument("paths", nargs="+", help="Markdown files or directories to audit")
arguments = parser.parse_args()
files, selection_errors = _selected_files(arguments.paths)
if selection_errors:
for error in selection_errors:
print(error, file=sys.stderr)
return 2
if not files:
print("Markdown link audit: no Markdown files selected", file=sys.stderr)
return 2
link_count = 0
errors: list[str] = []
for path in files:
current_count, current_errors = _audit_file(path)
link_count += current_count
errors.extend(current_errors)
if errors:
for error in errors:
print(error, file=sys.stderr)
print(f"Markdown link audit: {len(errors)} error(s) across {len(files)} file(s)", file=sys.stderr)
return 1
print(f"Markdown link audit: clean ({link_count} local link(s), {len(files)} file(s))")
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -0,0 +1,216 @@
#!/usr/bin/env python3
# file: scripts/audit_markdown_tables.py
# version: 2
"""Validate source formatting of Markdown tables in explicitly selected paths."""
from __future__ import annotations
import argparse
import pathlib
import re
import sys
_SEPARATOR = re.compile(r"^:?-{3,}:?$")
_IGNORED_DIRECTORIES = frozenset({".git", ".idea", ".venv", "__pycache__", "dist", "node_modules", "target", "builds"})
_MARKDOWN_FENCE_LANGUAGES = frozenset({"markdown", "md"})
def _selected_files(raw_paths: list[str]) -> tuple[list[pathlib.Path], list[str]]:
files: list[pathlib.Path] = []
errors: list[str] = []
for raw_path in raw_paths:
path = pathlib.Path(raw_path)
if path.is_dir():
files.extend(
candidate
for candidate in path.rglob("*.md")
if candidate.is_file() and not any(part in _IGNORED_DIRECTORIES for part in candidate.parts)
)
elif path.is_file() and path.suffix.lower() == ".md":
files.append(path)
else:
errors.append(f"Markdown table audit: unsupported or missing path: {path}")
return sorted(set(files)), errors
def _is_row(line: str) -> bool:
return line.startswith("|") and line.endswith("|")
def _cells(line: str) -> list[str]:
return line.split("|")[1:-1]
def _separator_marker(cell: str) -> str | None:
marker = cell.strip()
return marker if _SEPARATOR.fullmatch(marker) is not None else None
def _is_separator_row(line: str) -> bool:
if not _is_row(line):
return False
cells = _cells(line)
return bool(cells) and all(_separator_marker(cell) is not None for cell in cells)
def _alignment(marker: str) -> str:
if marker.startswith(":") and marker.endswith(":"):
return "center"
if marker.endswith(":"):
return "right"
return "left"
def _padding(cell: str) -> tuple[int, int]:
return len(cell) - len(cell.lstrip(" ")), len(cell) - len(cell.rstrip(" "))
def _validate_table(path: pathlib.Path, start_line: int, rows: list[str]) -> list[str]:
errors: list[str] = []
if any("\\|" in row for row in rows):
errors.append(f"{path}:{start_line}: escaped pipe is forbidden inside a table cell")
parsed = [_cells(row) for row in rows]
column_count = len(parsed[0])
for offset, row in enumerate(parsed):
if len(row) != column_count:
errors.append(f"{path}:{start_line + offset}: table row has {len(row)} columns; expected {column_count}")
return errors
for column in range(column_count):
raw_cells = [row[column] for row in parsed]
widths = [len(cell) for cell in raw_cells]
expected_width = widths[0]
if any(width != expected_width for width in widths):
errors.append(f"{path}:{start_line}: column {column + 1} is not vertically aligned; raw widths are {widths}")
continue
marker = _separator_marker(raw_cells[1])
if marker is None:
errors.append(f"{path}:{start_line + 1}: separator for column {column + 1} is malformed")
continue
content_cells = [cell for index, cell in enumerate(raw_cells) if index != 1]
longest_content = max(len(cell.strip()) for cell in content_cells)
required_width = max(longest_content + 2, 3 + marker.count(":"))
if expected_width != required_width:
errors.append(
f"{path}:{start_line}: column {column + 1} width is {expected_width}; expected {required_width}"
)
continue
alignment = _alignment(marker)
for cell in content_cells:
content_width = len(cell.strip())
left, right = _padding(cell)
expected_padding = expected_width - content_width
if content_width + left + right != len(cell) or left < 1 or right < 1:
errors.append(f"{path}:{start_line}: column {column + 1} must use spaces only for outer padding")
break
if alignment == "left" and (left != 1 or right != expected_padding - 1):
errors.append(f"{path}:{start_line}: column {column + 1} must be source-aligned to the left")
break
if alignment == "right" and (right != 1 or left != expected_padding - 1):
errors.append(f"{path}:{start_line}: column {column + 1} must be source-aligned to the right")
break
if alignment == "center" and abs(left - right) > 1:
errors.append(f"{path}:{start_line}: column {column + 1} must be source-aligned to the center")
break
if len(raw_cells[1]) != expected_width or _SEPARATOR.fullmatch(raw_cells[1]) is None:
errors.append(f"{path}:{start_line + 1}: separator for column {column + 1} must fill the column width")
return errors
def _fence_language(stripped: str) -> str | None:
info = stripped[3:].strip()
if not info:
return None
return info.split(None, 1)[0].lower()
def _audit_file(path: pathlib.Path) -> tuple[int, list[str]]:
lines = path.read_text(encoding="utf-8").splitlines()
errors: list[str] = []
tables = 0
fence: str | None = None
audit_fenced_markdown = False
index = 0
while index < len(lines):
stripped = lines[index].lstrip()
if stripped.startswith("```") or stripped.startswith("~~~"):
marker = stripped[:3]
if fence is None:
fence = marker
audit_fenced_markdown = _fence_language(stripped) in _MARKDOWN_FENCE_LANGUAGES
elif fence == marker:
fence = None
audit_fenced_markdown = False
index += 1
continue
if fence is not None and not audit_fenced_markdown:
index += 1
continue
if index + 1 < len(lines) and _is_row(lines[index]) and _is_separator_row(lines[index + 1]):
start = index
rows = [lines[index], lines[index + 1]]
index += 2
while index < len(lines) and _is_row(lines[index]):
rows.append(lines[index])
index += 1
tables += 1
errors.extend(_validate_table(path, start + 1, rows))
continue
index += 1
return tables, errors
def main() -> int:
"""Run the read-only Markdown table audit."""
parser = argparse.ArgumentParser()
parser.add_argument("paths", nargs="+", help="Markdown files or directories to audit")
arguments = parser.parse_args()
files, selection_errors = _selected_files(arguments.paths)
if selection_errors:
for error in selection_errors:
print(error, file=sys.stderr)
return 2
if not files:
print("Markdown table audit: no Markdown files selected", file=sys.stderr)
return 2
table_count = 0
errors: list[str] = []
for path in files:
current_count, current_errors = _audit_file(path)
table_count += current_count
errors.extend(current_errors)
if errors:
for error in errors:
print(error, file=sys.stderr)
print(f"Markdown table audit: {len(errors)} error(s) across {len(files)} file(s)", file=sys.stderr)
return 1
print(f"Markdown table audit: clean ({table_count} table(s), {len(files)} file(s))")
return 0
if __name__ == "__main__":
raise SystemExit(main())

View File

@@ -0,0 +1,78 @@
#!/usr/bin/env python3
# file: scripts/audit_rust_crate_root_facades.py
# version: 1
"""Audit Rust library crate roots so `src/lib.rs` remains a facade."""
from __future__ import annotations
import argparse
import pathlib
import re
import sys
from _rust_audit_common import line_depths, mask_source
_ITEM = re.compile(
r"^\s*(?:(?:pub(?:\([^)]*\))?)\s+)?"
r"(?:(?:async|const|unsafe)\s+)*(?:extern\s+\"[^\"]+\"\s+)?"
r"(?:fn|struct|enum|union|trait|impl|type|const|static|macro_rules!)\b"
)
def _selected_lib_roots(raw_paths: list[str]) -> tuple[list[pathlib.Path], list[str]]:
roots: set[pathlib.Path] = set()
errors: list[str] = []
for raw_path in raw_paths:
path = pathlib.Path(raw_path)
if path.is_dir():
roots.update(candidate for candidate in path.rglob("src/lib.rs") if candidate.is_file())
elif path.is_file() and path.as_posix().endswith("src/lib.rs"):
roots.add(path)
else:
errors.append(f"unsupported or missing library-root path: {path}")
return sorted(roots), errors
def _audit_file(path: pathlib.Path) -> list[str]:
text = path.read_text(encoding="utf-8")
masked, _ = mask_source(text)
lines = masked.splitlines()
depths = line_depths(masked)
errors: list[str] = []
for index, line in enumerate(lines):
if depths[index] != 0:
continue
if _ITEM.match(line) is not None:
errors.append(f"{path}:{index + 1}: crate root must remain a facade; move this item to a responsibility module")
return errors
def main() -> int:
"""Run the read-only Knowledge library crate-root facade audit."""
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument("paths", nargs="+", help="Crate roots or directories containing Rust library crates")
arguments = parser.parse_args()
files, errors = _selected_lib_roots(arguments.paths)
if errors or not files:
for error in errors or ["no Rust library crate roots selected"]:
print(f"Rust crate-root facade audit: {error}", file=sys.stderr)
return 2
for path in files:
try:
errors.extend(_audit_file(path))
except (OSError, UnicodeError) as error:
print(f"Rust crate-root facade audit: cannot read {path}: {error}", file=sys.stderr)
return 2
for error in errors:
print(error, file=sys.stderr)
if errors:
print(f"Rust crate-root facade audit: {len(errors)} error(s) across {len(files)} crate root(s)", file=sys.stderr)
return 1
print(f"Rust crate-root facade audit: clean ({len(files)} crate root(s))")
return 0
if __name__ == "__main__":
raise SystemExit(main())