diff --git a/.agents/skills/codex-token-saving/SKILL.md b/.agents/skills/codex-token-saving/SKILL.md new file mode 100644 index 0000000..d04ff4d --- /dev/null +++ b/.agents/skills/codex-token-saving/SKILL.md @@ -0,0 +1,44 @@ +# Skill: Codex Token-Saving Workflow + +## Purpose +Reduce context waste and avoid repo-drift during Codex Desktop work. + +## Use this skill when +- Starting a new Codex Desktop session. +- Working under token limits. +- Deep-diving a large repo. + +## Operating mode +- Do not scan the entire repo blindly. +- Start with local instructions and manifests. +- Use targeted `rg` searches. +- Read only files relevant to the current phase. +- Produce compact summaries. +- Avoid rereading large files. +- Batch validation after coherent edits. + +## Standard phase pattern +1. Bootstrap workspace. +2. Read instructions. +3. Build compact repo map. +4. Identify smallest safe change. +5. Ask for approval if in plan mode. +6. Implement focused change. +7. Validate. +8. Report exact files and command results. + +## Useful search terms for CompText +- `canonical_json` +- `sha256_hex` +- `package` +- `artifact` +- `manifest` +- `goal` +- `policy` +- `review` +- `provider` +- `boundary` +- `handoff` +- `roundtrip` +- `SPARK` +- `claim` diff --git a/.agents/skills/comptext-governance/SKILL.md b/.agents/skills/comptext-governance/SKILL.md new file mode 100644 index 0000000..13328e4 --- /dev/null +++ b/.agents/skills/comptext-governance/SKILL.md @@ -0,0 +1,57 @@ +# Skill: CompText Governance + +## Purpose +Preserve the CompText product contract during any code, UI, CLI, documentation, or artifact work. + +## Use this skill when +- Working on CompText Gateway, comptext-cli, comptext-sparkctl, Context Governor, or related docs. +- Changing pipeline, provider, review, artifact, or safety logic. +- Preparing material for reviewers, SPARK, public sector, or enterprise stakeholders. + +## Product contract +CompText is a deterministic Context Pack / proposal-gated evidence workflow. + +Core line: +Models are providers. Context is the product. + +Canonical pipeline: +Source / GitHub URL → Goal → Inspect → Context Pack → Policy Gate → Provider Boundary → Untrusted Proposal → Human Review → Artifacts + +## Required boundaries +- Provider output is untrusted until reviewed. +- Proposals are never auto-applied. +- Policy Gate decides whether provider calls are allowed. +- Human Review is the approval boundary. +- Artifacts preserve the evidence trail. +- GitHub/source repos remain read-only unless explicitly approved. + +## Allowed claims +- deterministic context infrastructure +- bounded inspection +- proposal-gated workflow +- review boundary +- evidence trail +- provider-agnostic boundary +- artifact manifest +- local integrity anchor if actually implemented +- SHA-256 hash of canonical JSON if actually computed + +## Blocked claims +- production-ready +- certified +- EU AI Act compliant +- legally compliant +- forensic proof or forensic certainty +- solved hallucinations +- guaranteed correctness +- guaranteed replay validity for arbitrary inputs +- autonomous enterprise agent +- autonomous approval +- universal AI memory + +## Checklist before final answer +- Did the change preserve Goal → Context Pack → Policy Gate → Review → Artifacts? +- Is provider output clearly untrusted? +- Are claims bounded and review-safe? +- Are artifacts/data honest and not faked? +- Are source repos/GitHub writes blocked unless explicitly approved? diff --git a/.agents/skills/reviewer-final-report/SKILL.md b/.agents/skills/reviewer-final-report/SKILL.md new file mode 100644 index 0000000..9953cd1 --- /dev/null +++ b/.agents/skills/reviewer-final-report/SKILL.md @@ -0,0 +1,27 @@ +# Skill: Reviewer Final Report + +## Purpose +Ensure every Codex Desktop run ends with an auditable, reviewer-grade report. + +## Required final report sections +1. Working folder path. +2. Repository root path. +3. Instructions/skills read. +4. MCP/connectors/plugins used or skipped. +5. Git remote status showing push disabled. +6. Files changed. +7. Artifact contract improvements. +8. Goal support improvements. +9. Policy/review/provider-boundary improvements. +10. SPARK alignment improvements. +11. Validation commands and exact results. +12. Remaining risks. +13. Final ZIP path if created. +14. Next safe action. + +## Reporting rules +- Do not hide failed commands. +- Distinguish implemented vs documented vs future work. +- Do not inflate claims. +- Mention any assumptions. +- Keep the final report compact but complete. diff --git a/.agents/skills/rust-canonical-artifacts/SKILL.md b/.agents/skills/rust-canonical-artifacts/SKILL.md new file mode 100644 index 0000000..54da212 --- /dev/null +++ b/.agents/skills/rust-canonical-artifacts/SKILL.md @@ -0,0 +1,36 @@ +# Skill: Rust Canonical Artifacts + +## Purpose +Keep Rust artifact packaging deterministic, testable, and honest. + +## Use this skill when +- Editing Rust package/codec/serialization code. +- Working on `canonical_json`, `sha256_hex`, manifests, or roundtrip tests. + +## Determinism rules +- Canonical serialization must be stable across runs. +- Avoid map iteration order unless explicitly sorted/canonicalized. +- Avoid nondeterministic timestamps in hash inputs unless intentionally part of the schema and tested. +- Avoid platform-specific path separators inside canonical hashes unless normalized. +- Hash only canonical bytes/string, not pretty-printed or debug output. + +## Hash rules +- Never display `sha256` unless actually computed. +- Never call a placeholder hash an integrity anchor. +- If a hash is optional, represent missing hash explicitly. +- If docs mention SHA-256, say “over canonical JSON” only when implemented. + +## Rust quality rules +- Prefer typed structs/enums over loose strings for contract-critical fields. +- Use serde derives consistently. +- Keep backwards compatibility if an existing package format exists. +- Add tests before broad refactors. +- Keep changes small. + +## Validation +Prefer: +- `cargo fmt --check` +- `cargo test` +- `cargo clippy --all-targets --all-features -- -D warnings` + +If clippy fails on pre-existing warnings, report honestly and fix only safe issues. diff --git a/.agents/skills/security-readonly-boundaries/SKILL.md b/.agents/skills/security-readonly-boundaries/SKILL.md new file mode 100644 index 0000000..e9522c1 --- /dev/null +++ b/.agents/skills/security-readonly-boundaries/SKILL.md @@ -0,0 +1,42 @@ +# Skill: Security and Read-Only Boundaries + +## Purpose +Prevent unsafe actions while working with Codex Desktop, GitHub, MCP/connectors, and local repositories. + +## Use this skill when +- GitHub plugin is enabled. +- Codex Security plugin is enabled. +- Any MCP/connector is available. +- Working on CompText source repos or hackathon deliverables. + +## Hard restrictions +- Do not push. +- Do not deploy. +- Do not create PRs. +- Do not create issues. +- Do not create remote branches. +- Do not create tokens. +- Do not write secrets. +- Do not paste secrets into code, docs, prompts, or tests. +- Do not install unofficial Codex UI/Android/remote-control packages. + +## Git safety +After cloning, run: +`git remote set-url --push origin DISABLED` + +Then show: +`git remote -v` + +Treat GitHub as read-only even if credentials allow writes. + +## MCP / connector rules +- Use MCP/connectors only for read-only context unless explicitly approved. +- Prefer local cloned files as source of truth. +- Do not use connectors to mutate GitHub or deployments. +- Do not rely on hidden external state for deterministic validation. + +## Network/tooling caution +- Do not add provider calls for sparkctl. +- Do not add shell execution features to the product. +- Do not add arbitrary filesystem readers. +- Do not expose private provider keys to frontend/runtime output. diff --git a/.agents/skills/spark-hackathon-alignment/SKILL.md b/.agents/skills/spark-hackathon-alignment/SKILL.md new file mode 100644 index 0000000..a27a7ed --- /dev/null +++ b/.agents/skills/spark-hackathon-alignment/SKILL.md @@ -0,0 +1,35 @@ +# Skill: SPARK Hackathon Alignment + +## Purpose +Align CompText work with SPARK / Safe & Stable positioning without overclaiming. + +## Use this skill when +- Preparing hackathon material. +- Writing README, demo, pitch, or docs for SPARK. +- Adding evidence/review functionality. + +## Positioning +SPARK stands for “Schnellere Planung und Realisierung durch KI”. +CompText should be positioned as the review, policy, and evidence boundary for AI-assisted workflows. + +## Good framing +- Safe and stable AI workflows need reviewable context, provider boundaries, and evidence artifacts. +- CompText does not replace human review; it preserves a reviewable trail. +- sparkctl packages the artifact/evidence layer. +- Provider output is an untrusted proposal until reviewed. + +## Avoid +- automated approval +- legal review replacement +- compliance certification +- production-ready government deployment claims +- forensic proof +- live public-sector data processing claims + +## Demo object +Prefer a concrete “SPARK Evidence Packet v1” over vague dashboard features. + +Minimum demo story: +1. Goal: Assess a module/workflow for safe and stable use. +2. Policy Gate: ALLOW / REVIEW_NEEDED / BLOCK with reasons. +3. Evidence Packet: preserves goal, context, proposal, review, claim hygiene, and manifest. diff --git a/.agents/skills/sparkctl-evidence-packet/SKILL.md b/.agents/skills/sparkctl-evidence-packet/SKILL.md new file mode 100644 index 0000000..8686661 --- /dev/null +++ b/.agents/skills/sparkctl-evidence-packet/SKILL.md @@ -0,0 +1,63 @@ +# Skill: sparkctl Evidence Packet + +## Purpose +Guide `comptext-sparkctl` work toward a SPARK Evidence Packet v1: a deterministic, reviewable artifact package for CompText. + +## Use this skill when +- Working in `ProfRandom92/comptext-sparkctl`. +- Modifying artifact/package/codec/manifest/roundtrip code. +- Preparing SPARK Safe & Stable hackathon material. + +## Target artifact +SPARK Evidence Packet v1 should contain, as data fields or manifest sections: +- `schema_version` +- `package_id` or `local_id` +- `goal` +- `source_summary` +- `context_pack_ref` or `context_pack_summary` +- `policy_result` +- `provider_boundary_status` +- `untrusted_proposal` +- `human_review_decision` +- `claim_hygiene` +- `artifact_manifest` +- `canonical_hash` only if computed from canonical JSON +- `warnings` / `limitations` + +## Enums +Policy Gate result: +- `ALLOW` +- `REVIEW_NEEDED` +- `BLOCK` + +Provider Boundary status: +- `DEMO` +- `UNAVAILABLE` +- `AVAILABLE` +- `BLOCKED_BY_POLICY` + +Human Review decision: +- `PASS` +- `NOTES` +- `BLOCKED` + +## Rules +- Goal informs packaging and review criteria. +- Goal never bypasses Policy Gate. +- Goal never authorizes auto-apply. +- Provider output is untrusted until reviewed. +- Human Review is the approval boundary. +- Artifacts preserve the evidence trail. +- Do not fake hashes. +- If a hash is shown, compute it from canonical JSON. + +## Tests to prefer +- canonical JSON deterministic output +- SHA-256 stable for known canonical input +- package roundtrip verify +- goal included in manifest +- policy result included +- provider boundary status included +- review decision included +- claim hygiene included +- SPARK Evidence Packet demo validates diff --git a/AGENTS.md b/AGENTS.md index 71f7251..6d10cf3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,15 +1,34 @@ -# Agent Instruction Manual — Antigravity × CompText v7 +# CompText Agent Rules -Welcome, Agent. You are pair programming inside the isolated SPARK Hackathon sandbox. +This repository is part of CompText. -> [!IMPORTANT] -> **First Step:** You MUST read [.agent/skills/00_project_system.md](file:///.agent/skills/00_project_system.md) before performing any file reads, writes, edits, or terminal command executions. +CompText is a deterministic Context Pack / proposal-gated evidence workflow, not a generic AI dashboard, not an agent memory product, and not an autonomous deployment agent. -## Protocol Highlights +Core line: +Models are providers. Context is the product. -1. **Read Guidelines First:** Open [.agent/skills/00_project_system.md](file:///.agent/skills/00_project_system.md) and choose the specific specialized skill matching your target task. -2. **Keep Changes Scoped:** Work only within the allowed write paths for the current approved phase. Never modify existing Python core, benchmarks, reports, or the original repository `README.md`. -3. **Phase-Gate Compliance:** Follow the `Implementation -> Audit -> Snapshot` loop. Do NOT advance to a new phase without explicit user approval. -4. **Cargo Restrictions:** You have permission to run `cargo fmt`, `cargo check`, `cargo test`, `cargo clippy`, and `cargo run` inside `agy7rust/` only. Active entry points: `sparkctl` (legacy compatibility checks) and `agy-ct` (production workflow orchestrator writing to untracked `reports/latest.json`). -5. **No Network or Git Remotes:** Web/network calls, git remote modifications, git fetch, git pull, or git push are strictly forbidden unless explicitly approved. -6. **Structured Output:** All step results must be reported using the structured phase block format. +Pipeline: +Source / GitHub URL → Goal → Inspect → Context Pack → Policy Gate → Provider Boundary → Untrusted Proposal → Human Review → Artifacts + +Hard rules: +- Treat GitHub as read-only unless the human explicitly asks otherwise. +- Do not push, deploy, create PRs, create issues, or create remote branches. +- Do not expose secrets. +- Do not fake hashes. +- Do not claim production-ready, EU AI Act compliance, legal certification, forensic proof, guaranteed correctness, or autonomous approval. +- Provider output is untrusted until reviewed. +- Proposals are never auto-applied. +- Human review is the approval boundary. +- Artifacts preserve the evidence trail. +- Keep changes scoped and reviewable. +- Do not modify root `README.md` unless the human explicitly approves it. +- Do not commit `reports/latest.json`. +- Do not commit `reports/performance_baseline.json` when it is only validation churn. +- Run cargo commands only inside `agy7rust/` unless the human explicitly approves otherwise. + +Before editing: +1. Read AGENTS.md. +2. Read `.agents/skills/**/SKILL.md` relevant to the task. +3. If `.agent/skills/00_project_system.md` exists, read it too. +4. Build a compact repo map. +5. Stop for approval if the user asked for plan mode. diff --git a/agy7rust/src/bin/sparkctl.rs b/agy7rust/src/bin/sparkctl.rs index 2a378c6..a76aa3d 100644 --- a/agy7rust/src/bin/sparkctl.rs +++ b/agy7rust/src/bin/sparkctl.rs @@ -22,6 +22,16 @@ enum Commands { ContextAll, #[command(about = "Run complete end-to-end demo pipeline (compress, build, render, validate)")] SparkDemo, + #[command(about = "Write a deterministic SPARK Evidence Packet v1 demo envelope")] + SparkEvidenceDemo { + #[arg(short = 'o', long = "output")] + output: String, + }, + #[command(about = "Validate a SPARK Evidence Packet v1 envelope")] + SparkEvidenceValidate { + #[arg(short = 'i', long = "input")] + input: String, + }, #[command(about = "Verify local repository handoff readiness")] HandoffCheck, } @@ -42,6 +52,12 @@ fn main() -> Result<()> { Commands::SparkDemo => { sparkctl::spark_demo::run_spark_demo()?; } + Commands::SparkEvidenceDemo { output } => { + sparkctl::spark_evidence::run_spark_evidence_demo(output)?; + } + Commands::SparkEvidenceValidate { input } => { + sparkctl::spark_evidence::run_spark_evidence_validate(input)?; + } Commands::HandoffCheck => { sparkctl::handoff_check::run_handoff_check()?; } diff --git a/agy7rust/src/codec/package.rs b/agy7rust/src/codec/package.rs index 4a5b1a1..584c4e8 100644 --- a/agy7rust/src/codec/package.rs +++ b/agy7rust/src/codec/package.rs @@ -1,6 +1,81 @@ use crate::codec::hash::sha256_hex; +use serde::{Deserialize, Serialize}; use serde_json; +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub enum PolicyResult { + #[serde(rename = "ALLOW")] + ALLOW, + #[serde(rename = "REVIEW_NEEDED")] + ReviewNeeded, + #[serde(rename = "BLOCK")] + BLOCK, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub enum ProviderBoundaryStatus { + #[serde(rename = "DEMO")] + DEMO, + #[serde(rename = "UNAVAILABLE")] + UNAVAILABLE, + #[serde(rename = "AVAILABLE")] + AVAILABLE, + #[serde(rename = "BLOCKED_BY_POLICY")] + BlockedByPolicy, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub enum HumanReviewDecision { + #[serde(rename = "PASS")] + PASS, + #[serde(rename = "NOTES")] + NOTES, + #[serde(rename = "BLOCKED")] + BLOCKED, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[serde(deny_unknown_fields)] +pub struct ClaimHygiene { + pub allowed_claims: Vec, + pub blocked_claims: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[serde(deny_unknown_fields)] +pub struct ArtifactManifestEntry { + pub path: String, + pub role: String, + pub sha256: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[serde(deny_unknown_fields)] +pub struct SparkEvidencePacketPreimage { + pub schema_version: String, + pub local_id: String, + pub goal: String, + pub source_summary: String, + pub context_pack_summary: String, + pub policy_result: PolicyResult, + pub provider_boundary_status: ProviderBoundaryStatus, + pub untrusted_proposal: String, + pub human_review_decision: HumanReviewDecision, + pub claim_hygiene: ClaimHygiene, + pub artifact_manifest: Vec, + pub warnings: Vec, + pub limitations: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +#[serde(deny_unknown_fields)] +pub struct SparkEvidencePacketEnvelope { + #[serde(flatten)] + pub preimage: SparkEvidencePacketPreimage, + pub canonical_json: String, + pub canonical_hash: String, +} + pub fn sort_json_value(value: &serde_json::Value) -> serde_json::Value { match value { serde_json::Value::Object(map) => { @@ -27,6 +102,93 @@ pub fn canonical_json(value: &serde_json::Value) -> String { serde_json::to_string(&sorted).unwrap_or_default() } +pub fn build_spark_evidence_packet_envelope( + preimage: SparkEvidencePacketPreimage, +) -> anyhow::Result { + validate_spark_evidence_preimage(&preimage)?; + let preimage_value = serde_json::to_value(&preimage)?; + let canonical = canonical_json(&preimage_value); + let canonical_hash = sha256_hex(&canonical); + + Ok(SparkEvidencePacketEnvelope { + preimage, + canonical_json: canonical, + canonical_hash, + }) +} + +pub fn validate_spark_evidence_packet_envelope( + envelope: &SparkEvidencePacketEnvelope, +) -> anyhow::Result<()> { + validate_spark_evidence_preimage(&envelope.preimage)?; + let preimage_value = serde_json::to_value(&envelope.preimage)?; + let calculated_canonical_json = canonical_json(&preimage_value); + if envelope.canonical_json != calculated_canonical_json { + return Err(anyhow::anyhow!("canonical_json mismatch")); + } + + let calculated_hash = sha256_hex(&envelope.canonical_json); + if envelope.canonical_hash != calculated_hash { + return Err(anyhow::anyhow!("canonical_hash mismatch")); + } + + Ok(()) +} + +pub fn validate_spark_evidence_packet_value(value: &serde_json::Value) -> anyhow::Result<()> { + let envelope: SparkEvidencePacketEnvelope = serde_json::from_value(value.clone())?; + validate_spark_evidence_packet_envelope(&envelope) +} + +fn validate_spark_evidence_preimage(preimage: &SparkEvidencePacketPreimage) -> anyhow::Result<()> { + require_non_empty("schema_version", &preimage.schema_version)?; + if preimage.schema_version != "SPARK-EVIDENCE-PACKET-V1" { + return Err(anyhow::anyhow!( + "schema_version mismatch: expected SPARK-EVIDENCE-PACKET-V1" + )); + } + require_non_empty("local_id", &preimage.local_id)?; + require_non_empty("goal", &preimage.goal)?; + require_non_empty("source_summary", &preimage.source_summary)?; + require_non_empty("context_pack_summary", &preimage.context_pack_summary)?; + require_non_empty("untrusted_proposal", &preimage.untrusted_proposal)?; + + require_non_empty_list( + "missing or empty claim in claim_hygiene.allowed_claims", + &preimage.claim_hygiene.allowed_claims, + )?; + require_non_empty_list( + "missing or empty claim in claim_hygiene.blocked_claims", + &preimage.claim_hygiene.blocked_claims, + )?; + if preimage.artifact_manifest.is_empty() { + return Err(anyhow::anyhow!("missing artifact_manifest")); + } + require_non_empty_list("missing or empty warning", &preimage.warnings)?; + require_non_empty_list("missing or empty limitation", &preimage.limitations)?; + + for entry in &preimage.artifact_manifest { + require_non_empty("artifact_manifest.path", &entry.path)?; + require_non_empty("artifact_manifest.role", &entry.role)?; + } + + Ok(()) +} + +fn require_non_empty(label: &str, value: &str) -> anyhow::Result<()> { + if value.trim().is_empty() { + return Err(anyhow::anyhow!("missing {}", label)); + } + Ok(()) +} + +fn require_non_empty_list(label: &str, values: &[String]) -> anyhow::Result<()> { + if values.is_empty() || values.iter().any(|value| value.trim().is_empty()) { + return Err(anyhow::anyhow!(label.to_string())); + } + Ok(()) +} + pub fn collect_field_paths(value: &serde_json::Value) -> Vec { let mut paths = Vec::new(); collect_paths_recursive(value, "$", &mut paths); diff --git a/agy7rust/src/lib.rs b/agy7rust/src/lib.rs index dac7607..5a6e975 100644 --- a/agy7rust/src/lib.rs +++ b/agy7rust/src/lib.rs @@ -7,7 +7,10 @@ pub mod error; pub use codec::hash::sha256_hex; pub use codec::package::{ - build_package_from_value, canonical_json, collect_field_paths, extract_commitment_tokens, - get_value_by_path, replay_package_value, sort_json_value, validate_schema, - verify_package_value, + build_package_from_value, build_spark_evidence_packet_envelope, canonical_json, + collect_field_paths, extract_commitment_tokens, get_value_by_path, replay_package_value, + sort_json_value, validate_schema, validate_spark_evidence_packet_envelope, + validate_spark_evidence_packet_value, verify_package_value, ArtifactManifestEntry, + ClaimHygiene, HumanReviewDecision, PolicyResult, ProviderBoundaryStatus, + SparkEvidencePacketEnvelope, SparkEvidencePacketPreimage, }; diff --git a/agy7rust/src/sparkctl/mod.rs b/agy7rust/src/sparkctl/mod.rs index d861532..221c0b3 100644 --- a/agy7rust/src/sparkctl/mod.rs +++ b/agy7rust/src/sparkctl/mod.rs @@ -4,3 +4,5 @@ pub mod doctor; pub mod handoff_check; pub mod rust_validate; pub mod spark_demo; +#[allow(dead_code)] +pub mod spark_evidence; diff --git a/agy7rust/src/sparkctl/spark_evidence.rs b/agy7rust/src/sparkctl/spark_evidence.rs new file mode 100644 index 0000000..51fa3d1 --- /dev/null +++ b/agy7rust/src/sparkctl/spark_evidence.rs @@ -0,0 +1,114 @@ +use agy7rust::codec::hash::sha256_hex; +use agy7rust::codec::package::{ + build_spark_evidence_packet_envelope, canonical_json, validate_spark_evidence_packet_value, + ArtifactManifestEntry, ClaimHygiene, HumanReviewDecision, PolicyResult, ProviderBoundaryStatus, + SparkEvidencePacketPreimage, +}; +use anyhow::{Context, Result}; +use std::fs; +use std::path::{Path, PathBuf}; + +pub fn run_spark_evidence_demo(output_path: &str) -> Result<()> { + let manifest = build_artifact_manifest(&[ + ( + "../examples/spark/extraction.json", + "source_summary_fixture", + ), + ("../artifacts/spark/extraction.spkg", "context_package"), + ("../artifacts/spark/context.json", "context_pack_summary"), + ("../artifacts/spark/context_render.txt", "review_render"), + ])?; + + let preimage = SparkEvidencePacketPreimage { + schema_version: "SPARK-EVIDENCE-PACKET-V1".to_string(), + local_id: "spark-evidence-demo-v1".to_string(), + goal: "Prepare a reviewable SPARK Evidence Packet v1 for safe and stable AI-assisted workflow review.".to_string(), + source_summary: "Synthetic SPARK-style local fixture for administrative planning workflow review.".to_string(), + context_pack_summary: "Local CompText context package and rendered context artifacts generated by sparkctl demo commands.".to_string(), + policy_result: PolicyResult::ReviewNeeded, + provider_boundary_status: ProviderBoundaryStatus::DEMO, + untrusted_proposal: "Demo proposal remains untrusted until a human reviewer records a decision.".to_string(), + human_review_decision: HumanReviewDecision::NOTES, + claim_hygiene: ClaimHygiene { + allowed_claims: vec![ + "deterministic canonical packaging".to_string(), + "bounded artifact manifest".to_string(), + "SHA-256 hash of canonical JSON when computed".to_string(), + "human review trail".to_string(), + "policy result record".to_string(), + ], + blocked_claims: vec![ + "production-ready".to_string(), + "EU AI Act compliant".to_string(), + "legally certified".to_string(), + "forensic proof".to_string(), + "guaranteed correctness".to_string(), + "autonomous approval".to_string(), + ], + }, + artifact_manifest: manifest, + warnings: vec![ + "Provider output is untrusted until human review.".to_string(), + "Goal does not bypass Policy Gate or Human Review.".to_string(), + ], + limitations: vec![ + "Prototype/demo workflow only.".to_string(), + "No provider calls are made by this packet generator.".to_string(), + "No compliance, legal, forensic, production, or certified-use claim is made.".to_string(), + ], + }; + + let envelope = build_spark_evidence_packet_envelope(preimage)?; + let output_value = serde_json::to_value(&envelope)?; + let output_json = canonical_json(&output_value); + + let output_path_buf = PathBuf::from(output_path); + if let Some(parent) = output_path_buf.parent() { + fs::create_dir_all(parent) + .with_context(|| format!("Failed to create directory: {:?}", parent))?; + } + + fs::write(&output_path_buf, output_json) + .with_context(|| format!("Failed to write evidence packet: {}", output_path))?; + + println!("spark-evidence-demo result: PASS"); + println!(" output: {}", output_path); + println!(" canonical_hash: {}", envelope.canonical_hash); + Ok(()) +} + +pub fn run_spark_evidence_validate(input_path: &str) -> Result<()> { + let content = fs::read_to_string(input_path) + .with_context(|| format!("Failed to read evidence packet: {}", input_path))?; + let value: serde_json::Value = serde_json::from_str(&content) + .with_context(|| format!("Failed to parse evidence packet JSON: {}", input_path))?; + + validate_spark_evidence_packet_value(&value)?; + + println!("spark-evidence-validate result: PASS"); + println!(" input: {}", input_path); + Ok(()) +} + +fn build_artifact_manifest(paths: &[(&str, &str)]) -> Result> { + paths + .iter() + .map(|(path, role)| { + Ok(ArtifactManifestEntry { + path: normalize_manifest_path(path), + role: (*role).to_string(), + sha256: Some(file_sha256(path)?), + }) + }) + .collect() +} + +fn file_sha256(path: &str) -> Result { + let bytes = fs::read(Path::new(path)) + .with_context(|| format!("Failed to read required demo artifact: {}", path))?; + Ok(sha256_hex(bytes)) +} + +fn normalize_manifest_path(path: &str) -> String { + path.replace('\\', "/") +} diff --git a/agy7rust/tests/spark_roundtrip.rs b/agy7rust/tests/spark_roundtrip.rs index ebfe9a9..f104877 100644 --- a/agy7rust/tests/spark_roundtrip.rs +++ b/agy7rust/tests/spark_roundtrip.rs @@ -1,7 +1,11 @@ use agy7rust::codec::package::{ - build_package_from_value, canonical_json, collect_field_paths, extract_commitment_tokens, - replay_package_value, verify_package_value, + build_package_from_value, build_spark_evidence_packet_envelope, canonical_json, + collect_field_paths, extract_commitment_tokens, replay_package_value, + validate_spark_evidence_packet_envelope, validate_spark_evidence_packet_value, + verify_package_value, ArtifactManifestEntry, ClaimHygiene, HumanReviewDecision, PolicyResult, + ProviderBoundaryStatus, SparkEvidencePacketPreimage, }; +use agy7rust::sha256_hex; use serde_json::json; #[test] @@ -21,6 +25,225 @@ fn test_canonical_json_sorting() { assert_eq!(canonical, r#"{"a":{"b":2,"c":3},"m":[4,5,6],"z":1}"#); } +#[test] +fn test_sha256_hex_known_input_is_stable() { + assert_eq!( + sha256_hex("abc"), + "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad" + ); +} + +#[test] +fn test_spark_evidence_packet_demo_shape_validates() { + let preimage = sample_spark_evidence_preimage(); + let envelope = + build_spark_evidence_packet_envelope(preimage).expect("evidence envelope should build"); + + assert_eq!( + envelope.preimage.goal, + "Review deterministic artifact packaging for SPARK Evidence Packet v1." + ); + assert_eq!(envelope.preimage.policy_result, PolicyResult::ReviewNeeded); + assert_eq!( + envelope.preimage.provider_boundary_status, + ProviderBoundaryStatus::DEMO + ); + assert_eq!( + envelope.preimage.human_review_decision, + HumanReviewDecision::NOTES + ); + assert!(!envelope.preimage.claim_hygiene.allowed_claims.is_empty()); + assert!(!envelope.preimage.claim_hygiene.blocked_claims.is_empty()); + assert!(!envelope.preimage.artifact_manifest.is_empty()); + assert!(!envelope.preimage.warnings.is_empty()); + assert!(!envelope.preimage.limitations.is_empty()); + + let preimage_value = serde_json::to_value(&envelope.preimage).unwrap(); + assert_eq!(envelope.canonical_json, canonical_json(&preimage_value)); + assert_eq!( + envelope.canonical_hash, + sha256_hex(&envelope.canonical_json) + ); + assert!(validate_spark_evidence_packet_envelope(&envelope).is_ok()); + + let envelope_value = serde_json::to_value(&envelope).unwrap(); + assert!(validate_spark_evidence_packet_value(&envelope_value).is_ok()); +} + +#[test] +fn test_spark_evidence_packet_rejects_changed_preimage_with_stale_canonical_json() { + let mut envelope = + build_spark_evidence_packet_envelope(sample_spark_evidence_preimage()).unwrap(); + envelope.preimage.goal = "Tampered goal".to_string(); + + let err = validate_spark_evidence_packet_envelope(&envelope) + .unwrap_err() + .to_string(); + assert_eq!(err, "canonical_json mismatch"); +} + +#[test] +fn test_spark_evidence_packet_rejects_changed_canonical_json_with_stale_hash() { + let mut envelope = + build_spark_evidence_packet_envelope(sample_spark_evidence_preimage()).unwrap(); + envelope.canonical_json = "{}".to_string(); + + let err = validate_spark_evidence_packet_envelope(&envelope) + .unwrap_err() + .to_string(); + assert_eq!(err, "canonical_json mismatch"); +} + +#[test] +fn test_spark_evidence_packet_rejects_changed_canonical_hash() { + let mut envelope = + build_spark_evidence_packet_envelope(sample_spark_evidence_preimage()).unwrap(); + envelope.canonical_hash = + "0000000000000000000000000000000000000000000000000000000000000000".to_string(); + + let err = validate_spark_evidence_packet_envelope(&envelope) + .unwrap_err() + .to_string(); + assert_eq!(err, "canonical_hash mismatch"); +} + +#[test] +fn test_spark_evidence_packet_rejects_missing_required_review_policy_goal_fields() { + let mut missing_goal = sample_spark_evidence_preimage(); + missing_goal.goal = " ".to_string(); + assert_eq!( + build_spark_evidence_packet_envelope(missing_goal) + .unwrap_err() + .to_string(), + "missing goal" + ); + + let mut missing_review = sample_spark_evidence_preimage(); + missing_review.untrusted_proposal = "".to_string(); + assert_eq!( + build_spark_evidence_packet_envelope(missing_review) + .unwrap_err() + .to_string(), + "missing untrusted_proposal" + ); + + let mut missing_manifest = sample_spark_evidence_preimage(); + missing_manifest.artifact_manifest.clear(); + assert_eq!( + build_spark_evidence_packet_envelope(missing_manifest) + .unwrap_err() + .to_string(), + "missing artifact_manifest" + ); +} + +#[test] +fn test_spark_evidence_packet_rejects_unknown_envelope_field() { + let envelope = build_spark_evidence_packet_envelope(sample_spark_evidence_preimage()).unwrap(); + let mut envelope_value = serde_json::to_value(&envelope).unwrap(); + envelope_value["unexpected_envelope_field"] = json!("tamper"); + + let err = validate_spark_evidence_packet_value(&envelope_value) + .unwrap_err() + .to_string(); + assert!(err.contains("unknown field")); +} + +#[test] +fn test_spark_evidence_packet_rejects_unknown_preimage_field() { + let mut preimage_value = serde_json::to_value(sample_spark_evidence_preimage()).unwrap(); + preimage_value["unexpected_preimage_field"] = json!("tamper"); + + let err = serde_json::from_value::(preimage_value) + .unwrap_err() + .to_string(); + assert!(err.contains("unknown field")); +} + +#[test] +fn test_spark_evidence_packet_rejects_blank_allowed_claim() { + let mut preimage = sample_spark_evidence_preimage(); + preimage + .claim_hygiene + .allowed_claims + .push(" ".to_string()); + + let err = build_spark_evidence_packet_envelope(preimage) + .unwrap_err() + .to_string(); + assert_eq!( + err, + "missing or empty claim in claim_hygiene.allowed_claims" + ); +} + +#[test] +fn test_spark_evidence_packet_rejects_blank_blocked_claim() { + let mut preimage = sample_spark_evidence_preimage(); + preimage.claim_hygiene.blocked_claims.push("".to_string()); + + let err = build_spark_evidence_packet_envelope(preimage) + .unwrap_err() + .to_string(); + assert_eq!( + err, + "missing or empty claim in claim_hygiene.blocked_claims" + ); +} + +#[test] +fn test_spark_evidence_packet_rejects_blank_warning() { + let mut preimage = sample_spark_evidence_preimage(); + preimage.warnings.push("\t".to_string()); + + let err = build_spark_evidence_packet_envelope(preimage) + .unwrap_err() + .to_string(); + assert_eq!(err, "missing or empty warning"); +} + +#[test] +fn test_spark_evidence_packet_rejects_blank_limitation() { + let mut preimage = sample_spark_evidence_preimage(); + preimage.limitations.push("\n".to_string()); + + let err = build_spark_evidence_packet_envelope(preimage) + .unwrap_err() + .to_string(); + assert_eq!(err, "missing or empty limitation"); +} + +fn sample_spark_evidence_preimage() -> SparkEvidencePacketPreimage { + SparkEvidencePacketPreimage { + schema_version: "SPARK-EVIDENCE-PACKET-V1".to_string(), + local_id: "unit-test-packet".to_string(), + goal: "Review deterministic artifact packaging for SPARK Evidence Packet v1.".to_string(), + source_summary: "Synthetic local fixture summary.".to_string(), + context_pack_summary: "Context pack summary for deterministic review.".to_string(), + policy_result: PolicyResult::ReviewNeeded, + provider_boundary_status: ProviderBoundaryStatus::DEMO, + untrusted_proposal: "Untrusted proposal requires human review.".to_string(), + human_review_decision: HumanReviewDecision::NOTES, + claim_hygiene: ClaimHygiene { + allowed_claims: vec![ + "deterministic canonical packaging".to_string(), + "artifact manifest".to_string(), + ], + blocked_claims: vec![ + "production-ready".to_string(), + "guaranteed correctness".to_string(), + ], + }, + artifact_manifest: vec![ArtifactManifestEntry { + path: "artifacts/spark/evidence_packet_v1.json".to_string(), + role: "evidence_packet".to_string(), + sha256: None, + }], + warnings: vec!["Provider output is untrusted until reviewed.".to_string()], + limitations: vec!["No compliance or production claim is made.".to_string()], + } +} + #[test] fn test_field_paths_collection() { let original = json!({ @@ -1128,7 +1351,7 @@ fn test_context_validate_invalid_shape_fails() { fn test_sparkctl_doctor_execution() { use std::process::Command; let output = Command::new("cargo") - .args(&["run", "--bin", "sparkctl", "--", "doctor"]) + .args(["run", "--bin", "sparkctl", "--", "doctor"]) .output() .expect("failed to execute cargo run"); @@ -1143,7 +1366,7 @@ fn test_sparkctl_rust_validate_execution() { use std::process::Command; let output = Command::new("cargo") .env("SPARKCTL_IN_TEST", "1") - .args(&["run", "--bin", "sparkctl", "--", "rust-validate"]) + .args(["run", "--bin", "sparkctl", "--", "rust-validate"]) .output() .expect("failed to execute cargo run"); @@ -1157,7 +1380,7 @@ fn test_sparkctl_rust_validate_execution() { fn test_sparkctl_context_all_execution() { use std::process::Command; let output = Command::new("cargo") - .args(&["run", "--bin", "sparkctl", "--", "context-all"]) + .args(["run", "--bin", "sparkctl", "--", "context-all"]) .output() .expect("failed to execute cargo run"); @@ -1171,7 +1394,7 @@ fn test_sparkctl_context_all_execution() { fn test_sparkctl_spark_demo_execution() { use std::process::Command; let output = Command::new("cargo") - .args(&["run", "--bin", "sparkctl", "--", "spark-demo"]) + .args(["run", "--bin", "sparkctl", "--", "spark-demo"]) .output() .expect("failed to execute cargo run"); @@ -1185,7 +1408,7 @@ fn test_sparkctl_spark_demo_execution() { fn test_sparkctl_handoff_check_execution() { use std::process::Command; let output = Command::new("cargo") - .args(&["run", "--bin", "sparkctl", "--", "handoff-check"]) + .args(["run", "--bin", "sparkctl", "--", "handoff-check"]) .output() .expect("failed to execute cargo run"); diff --git a/artifacts/spark/evidence_packet_v1.json b/artifacts/spark/evidence_packet_v1.json new file mode 100644 index 0000000..af4ee4c --- /dev/null +++ b/artifacts/spark/evidence_packet_v1.json @@ -0,0 +1 @@ +{"artifact_manifest":[{"path":"../examples/spark/extraction.json","role":"source_summary_fixture","sha256":"c3eec26d5f8d385c40d3332d9a8cd561a8aca2623b8d098af952521c0f02a039"},{"path":"../artifacts/spark/extraction.spkg","role":"context_package","sha256":"ac3ac0f1e96cc3a208c6249d49efdfb21044d93a284597ba7ff527da6509bbeb"},{"path":"../artifacts/spark/context.json","role":"context_pack_summary","sha256":"4ea7fe65fdafb6972b9e759355f1d6de0268479fea510016dfa36bc73253defb"},{"path":"../artifacts/spark/context_render.txt","role":"review_render","sha256":"c3a41070a6f331a14960ea693e0ebf5c3ab47960ef752e0897e107209779c320"}],"canonical_hash":"2d344566cb434335fffb04fe9e7c98649fa2f1dd3413a0a3931b388d253e16b7","canonical_json":"{\"artifact_manifest\":[{\"path\":\"../examples/spark/extraction.json\",\"role\":\"source_summary_fixture\",\"sha256\":\"c3eec26d5f8d385c40d3332d9a8cd561a8aca2623b8d098af952521c0f02a039\"},{\"path\":\"../artifacts/spark/extraction.spkg\",\"role\":\"context_package\",\"sha256\":\"ac3ac0f1e96cc3a208c6249d49efdfb21044d93a284597ba7ff527da6509bbeb\"},{\"path\":\"../artifacts/spark/context.json\",\"role\":\"context_pack_summary\",\"sha256\":\"4ea7fe65fdafb6972b9e759355f1d6de0268479fea510016dfa36bc73253defb\"},{\"path\":\"../artifacts/spark/context_render.txt\",\"role\":\"review_render\",\"sha256\":\"c3a41070a6f331a14960ea693e0ebf5c3ab47960ef752e0897e107209779c320\"}],\"claim_hygiene\":{\"allowed_claims\":[\"deterministic canonical packaging\",\"bounded artifact manifest\",\"SHA-256 hash of canonical JSON when computed\",\"human review trail\",\"policy result record\"],\"blocked_claims\":[\"production-ready\",\"EU AI Act compliant\",\"legally certified\",\"forensic proof\",\"guaranteed correctness\",\"autonomous approval\"]},\"context_pack_summary\":\"Local CompText context package and rendered context artifacts generated by sparkctl demo commands.\",\"goal\":\"Prepare a reviewable SPARK Evidence Packet v1 for safe and stable AI-assisted workflow review.\",\"human_review_decision\":\"NOTES\",\"limitations\":[\"Prototype/demo workflow only.\",\"No provider calls are made by this packet generator.\",\"No compliance, legal, forensic, production, or certified-use claim is made.\"],\"local_id\":\"spark-evidence-demo-v1\",\"policy_result\":\"REVIEW_NEEDED\",\"provider_boundary_status\":\"DEMO\",\"schema_version\":\"SPARK-EVIDENCE-PACKET-V1\",\"source_summary\":\"Synthetic SPARK-style local fixture for administrative planning workflow review.\",\"untrusted_proposal\":\"Demo proposal remains untrusted until a human reviewer records a decision.\",\"warnings\":[\"Provider output is untrusted until human review.\",\"Goal does not bypass Policy Gate or Human Review.\"]}","claim_hygiene":{"allowed_claims":["deterministic canonical packaging","bounded artifact manifest","SHA-256 hash of canonical JSON when computed","human review trail","policy result record"],"blocked_claims":["production-ready","EU AI Act compliant","legally certified","forensic proof","guaranteed correctness","autonomous approval"]},"context_pack_summary":"Local CompText context package and rendered context artifacts generated by sparkctl demo commands.","goal":"Prepare a reviewable SPARK Evidence Packet v1 for safe and stable AI-assisted workflow review.","human_review_decision":"NOTES","limitations":["Prototype/demo workflow only.","No provider calls are made by this packet generator.","No compliance, legal, forensic, production, or certified-use claim is made."],"local_id":"spark-evidence-demo-v1","policy_result":"REVIEW_NEEDED","provider_boundary_status":"DEMO","schema_version":"SPARK-EVIDENCE-PACKET-V1","source_summary":"Synthetic SPARK-style local fixture for administrative planning workflow review.","untrusted_proposal":"Demo proposal remains untrusted until a human reviewer records a decision.","warnings":["Provider output is untrusted until human review.","Goal does not bypass Policy Gate or Human Review."]} \ No newline at end of file diff --git a/docs/ARTIFACT_CONTRACT.md b/docs/ARTIFACT_CONTRACT.md new file mode 100644 index 0000000..f881698 --- /dev/null +++ b/docs/ARTIFACT_CONTRACT.md @@ -0,0 +1,46 @@ +# Artifact Contract + +## SPARK Evidence Packet v1 Shape + +The packet is modeled as two layers: + +- `SparkEvidencePacketPreimage`: the review data that is canonicalized. +- `SparkEvidencePacketEnvelope`: the preimage plus derived `canonical_json` and `canonical_hash`. + +The preimage contains: + +- `schema_version` +- `local_id` +- `goal` +- `source_summary` +- `context_pack_summary` +- `policy_result` +- `provider_boundary_status` +- `untrusted_proposal` +- `human_review_decision` +- `claim_hygiene` +- `artifact_manifest` +- `warnings` +- `limitations` + +The envelope contains all preimage fields plus: + +- `canonical_json` +- `canonical_hash` + +## Canonicalization + +`canonical_json` is computed only from `SparkEvidencePacketPreimage`. It is not part of its own hash preimage. + +`canonical_hash` is computed only as `sha256_hex(canonical_json)`. + +## Validation + +Validation rejects: + +- changed preimage with stale `canonical_json` +- changed `canonical_json` +- changed `canonical_hash` +- missing required goal, review, policy, claim hygiene, warning, limitation, or artifact fields + +Existing `.spkg` package compatibility is preserved. The SPARK Evidence Packet v1 is a separate evidence envelope and does not alter the existing package verification contract. diff --git a/docs/CODEX_HANDOFF_SPARK_EVIDENCE_PACKET_V1.md b/docs/CODEX_HANDOFF_SPARK_EVIDENCE_PACKET_V1.md new file mode 100644 index 0000000..5e10ce9 --- /dev/null +++ b/docs/CODEX_HANDOFF_SPARK_EVIDENCE_PACKET_V1.md @@ -0,0 +1,108 @@ +# Codex Handoff: SPARK Evidence Packet v1 + +## 1. Current Workspace Paths + +- Working folder: `C:\Users\contr\Desktop\comptext-sparkctl-codex-work` +- Repo root: `C:\Users\contr\Desktop\comptext-sparkctl-codex-work\comptext-sparkctl` +- Rust crate root: `C:\Users\contr\Desktop\comptext-sparkctl-codex-work\comptext-sparkctl\agy7rust` +- Final ZIP path, if separately produced: `C:\Users\contr\Desktop\comptext-sparkctl-spark-ready.zip` + +## 2. Current Git / PR State + +- Branch: `spark-evidence-packet-v1` +- Commit: `081a2cbb526d580c1143235f9cbfb1f4cc0df4aa` +- PR: `#3` +- Status: pushed, PR open, not merged. +- Working tree was clean after push. +- Push URL status after review setup: `DISABLED`. + +## 3. Implemented Feature Summary + +- Added SPARK Evidence Packet v1 as a local deterministic evidence envelope. +- Added `SparkEvidencePacketPreimage` for hash input fields only. +- Added `SparkEvidencePacketEnvelope` containing the preimage plus derived `canonical_json` and `canonical_hash`. +- `canonical_json` is computed from preimage fields only. +- `canonical_hash = sha256_hex(canonical_json)`. +- Added `sparkctl spark-evidence-demo --output ../artifacts/spark/evidence_packet_v1.json`. +- Added `sparkctl spark-evidence-validate --input ../artifacts/spark/evidence_packet_v1.json`. +- Added tamper validation tests for stale preimage, stale canonical JSON, stale hash, and missing required fields. +- Added docs for SPARK alignment, artifact contract, safety/claims, implementation report, README update proposal, and this handoff. + +## 4. Intended PR Files + +- `AGENTS.md` +- `.agents/skills/**` +- `agy7rust/src/bin/sparkctl.rs` +- `agy7rust/src/codec/package.rs` +- `agy7rust/src/lib.rs` +- `agy7rust/src/sparkctl/mod.rs` +- `agy7rust/src/sparkctl/spark_evidence.rs` +- `agy7rust/tests/spark_roundtrip.rs` +- `artifacts/spark/evidence_packet_v1.json` +- `docs/SPARK_ALIGNMENT.md` +- `docs/ARTIFACT_CONTRACT.md` +- `docs/SAFETY_AND_CLAIMS.md` +- `docs/IMPLEMENTATION_REPORT.md` +- `docs/README_UPDATE_PROPOSAL.md` +- `docs/CODEX_HANDOFF_SPARK_EVIDENCE_PACKET_V1.md` + +## 5. Files That Must NOT Be Committed + +- `reports/latest.json` +- `reports/performance_baseline.json` if it is only validation churn +- `target/` +- `.env` +- caches +- secrets +- unrelated files + +## 6. Validation Results Achieved + +- `cargo fmt --all --check`: PASS +- `cargo test`: PASS +- `cargo clippy --all-targets --all-features -- -D warnings`: PASS +- `cargo run --bin sparkctl -- spark-evidence-validate --input ../artifacts/spark/evidence_packet_v1.json`: PASS +- Tamper tests: PASS + +## 7. Critical Invariants + +- Root `README.md` untouched. +- `canonical_json` is derived only from preimage fields. +- `canonical_hash` is computed only from `canonical_json`. +- No timestamp, random value, environment value, local absolute path, or machine-specific value is included in the canonical hash input. +- Provider output remains untrusted. +- Policy Gate remains before provider proposal. +- Human Review remains the approval boundary. +- Goal never bypasses Policy Gate, Provider Boundary, or Human Review. +- No provider calls were added. +- No compliance, legal, forensic, official SPARK compatibility, autonomous approval, or production readiness claims were added. + +## 8. Current Next Step + +Review PR `#3`, wait for GitHub CI/check status if configured, and keep any follow-up changes small and review-gated. + +## 9. Historical Pre-Commit Handoff Snapshot + +This section preserves the original pre-commit handoff state for audit context only. It is not the current branch state. + +- Current branch at that time: `main` +- Latest local commit at that time: `c2f41e3` +- Push URL status at that time: `DISABLED` +- `git status --short` summary at handoff creation: + +```text + M AGENTS.md + M agy7rust/src/bin/sparkctl.rs + M agy7rust/src/codec/package.rs + M agy7rust/src/lib.rs + M agy7rust/src/sparkctl/mod.rs + M agy7rust/tests/spark_roundtrip.rs + M reports/performance_baseline.json +?? .agents/ +?? agy7rust/src/sparkctl/spark_evidence.rs +?? artifacts/spark/evidence_packet_v1.json +?? docs/ +?? reports/latest.json +``` + +At that historical point, no local implementation commit had been created yet. The recommended sequence then was to clean generated report churn, create `spark-evidence-packet-v1`, stage intended files only, commit with `feat(sparkctl): add SPARK Evidence Packet v1`, and avoid push without explicit approval. diff --git a/docs/IMPLEMENTATION_REPORT.md b/docs/IMPLEMENTATION_REPORT.md new file mode 100644 index 0000000..4ecf085 --- /dev/null +++ b/docs/IMPLEMENTATION_REPORT.md @@ -0,0 +1,45 @@ +# Implementation Report + +## Scope + +Implemented the SPARK Evidence Packet v1 as a local, deterministic evidence envelope for `sparkctl`. + +## Files Changed + +- `AGENTS.md` +- `.agents/skills/**/SKILL.md` +- `agy7rust/src/codec/package.rs` +- `agy7rust/src/lib.rs` +- `agy7rust/src/sparkctl/mod.rs` +- `agy7rust/src/sparkctl/spark_evidence.rs` +- `agy7rust/src/bin/sparkctl.rs` +- `agy7rust/tests/spark_roundtrip.rs` +- `docs/SPARK_ALIGNMENT.md` +- `docs/ARTIFACT_CONTRACT.md` +- `docs/SAFETY_AND_CLAIMS.md` +- `docs/README_UPDATE_PROPOSAL.md` +- `docs/IMPLEMENTATION_REPORT.md` + +## Artifact Contract Improvements + +- Added typed policy, provider-boundary, and human-review enums. +- Added a preimage/envelope packet model. +- Derived `canonical_json` only from the packet preimage. +- Derived `canonical_hash` only from `sha256_hex(canonical_json)`. +- Preserved the existing `.spkg` package format. + +## Validation + +- `cargo fmt --all --check`: PASS +- `cargo test`: PASS + - `benchmark_action_cli`: 1 passed + - `spark_roundtrip`: 38 passed +- `cargo clippy --all-targets --all-features -- -D warnings`: PASS +- `cargo run --bin sparkctl -- spark-evidence-demo --output ../artifacts/spark/evidence_packet_v1.json`: PASS +- `cargo run --bin sparkctl -- spark-evidence-validate --input ../artifacts/spark/evidence_packet_v1.json`: PASS + +## Risks + +- The evidence packet is a bounded prototype/demo artifact. +- It does not make provider calls or represent external review state. +- It makes no production, compliance, legal, forensic, certified-use, or guaranteed-correctness claim. diff --git a/docs/README_UPDATE_PROPOSAL.md b/docs/README_UPDATE_PROPOSAL.md new file mode 100644 index 0000000..b05eb17 --- /dev/null +++ b/docs/README_UPDATE_PROPOSAL.md @@ -0,0 +1,17 @@ +# README Update Proposal + +Root `README.md` was intentionally not modified. + +If a future README update is approved, add a short docs pointer rather than changing the existing product framing: + +```markdown +## SPARK Evidence Packet v1 + +This repository includes a local SPARK Evidence Packet v1 demo for reviewable CompText artifact packaging. See: + +- `docs/SPARK_ALIGNMENT.md` +- `docs/ARTIFACT_CONTRACT.md` +- `docs/SAFETY_AND_CLAIMS.md` +``` + +Keep the README wording bounded: do not claim production readiness, compliance certification, legal validation, forensic proof, guaranteed correctness, certified government use, or autonomous approval. diff --git a/docs/SAFETY_AND_CLAIMS.md b/docs/SAFETY_AND_CLAIMS.md new file mode 100644 index 0000000..7a76ed9 --- /dev/null +++ b/docs/SAFETY_AND_CLAIMS.md @@ -0,0 +1,38 @@ +# Safety And Claims + +## Preserved Invariants + +- Goal informs packaging and review criteria. +- Goal never bypasses the Policy Gate. +- Goal never authorizes auto-apply behavior. +- Provider output is untrusted until reviewed. +- Human Review is the approval boundary. +- Artifacts preserve the evidence trail. + +## Allowed Claims + +- deterministic canonical packaging +- bounded artifact manifest +- local integrity anchor when implemented +- SHA-256 hash of canonical JSON when actually computed +- human review trail +- policy result record +- provider-boundary record +- evidence packet for review +- prototype/demo workflow + +## Blocked Claims + +- production-ready +- EU AI Act compliant +- legally certified +- forensic proof +- guaranteed correctness +- guaranteed replay validity for arbitrary inputs +- certified government use +- autonomous approval +- replaces human review + +## Runtime Boundaries + +The evidence packet generator performs local file reads for manifest hashing only. It does not call providers, create tokens, deploy, push, create pull requests, create issues, create remote branches, or mutate GitHub. diff --git a/docs/SPARK_ALIGNMENT.md b/docs/SPARK_ALIGNMENT.md new file mode 100644 index 0000000..696b80d --- /dev/null +++ b/docs/SPARK_ALIGNMENT.md @@ -0,0 +1,30 @@ +# SPARK Alignment + +## Positioning + +SPARK stands for "Schnellere Planung und Realisierung durch KI". In this repository, `sparkctl` is treated as the local artifact and evidence-package layer for CompText-style review workflows. + +CompText is a deterministic Context Pack / proposal-gated evidence workflow: + +Source / GitHub URL -> Goal -> Inspect -> Context Pack -> Policy Gate -> Provider Boundary -> Untrusted Proposal -> Human Review -> Artifacts + +## SPARK Evidence Packet v1 + +The SPARK Evidence Packet v1 demo records a reviewable trail with: + +- a review goal +- source and context summaries +- policy result +- provider-boundary status +- untrusted proposal text +- human review decision +- claim hygiene +- artifact manifest +- canonical JSON derived from the packet preimage +- SHA-256 hash computed from that canonical JSON + +## Boundaries + +The packet does not replace human review. Provider output remains untrusted until reviewed, and the goal does not bypass the Policy Gate or authorize auto-apply behavior. + +The demo is local and bounded. It makes no provider calls and does not claim production readiness, compliance certification, legal validation, forensic proof, guaranteed correctness, or certified government use.