From 248c5558606bdc5a5591a94ccdaae46fa9815ab0 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 17 Aug 2026 21:35:31 +0900 Subject: [PATCH 1/7] feat(method): refuse prompt boilerplate as unique content Instruction and prompt boilerplate stays explicit method structure (ADR 0004 and 0012). It is not unique latent content and is not erased by a stopword list. Recovery is the computed share of prompt kinds that match known truth versus collapsing every token to unique content. --- ARCHITECTURE.md | 1 + CHANGELOG.md | 1 + Cargo.lock | 4 + Cargo.toml | 2 + README.md | 3 +- crates/prompt_source/Cargo.toml | 17 +++ crates/prompt_source/src/error.rs | 53 +++++++ crates/prompt_source/src/kind.rs | 132 ++++++++++++++++++ crates/prompt_source/src/lib.rs | 22 +++ crates/prompt_source/tests/crate_contract.rs | 7 + .../tests/prompt_source_contract.rs | 67 +++++++++ docs/TRACEABILITY.md | 2 +- .../0004-shared-multilingual-latent-space.md | 2 +- ...ational-shared-latent-topic-measurement.md | 2 +- docs/adr/README.md | 4 +- docs/research/prompt-source-identity.md | 31 ++++ docs/research/standards-and-literature.md | 4 +- docs/validation/temporal-event-foundation.md | 1 + scripts/check_workspace_contract.py | 1 + 19 files changed, 349 insertions(+), 7 deletions(-) create mode 100644 crates/prompt_source/Cargo.toml create mode 100644 crates/prompt_source/src/error.rs create mode 100644 crates/prompt_source/src/kind.rs create mode 100644 crates/prompt_source/src/lib.rs create mode 100644 crates/prompt_source/tests/crate_contract.rs create mode 100644 crates/prompt_source/tests/prompt_source_contract.rs create mode 100644 docs/research/prompt-source-identity.md diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index ffe514db..e365c4c7 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -61,6 +61,7 @@ boundaries above remain the target modular MSA architecture. | `tepp_simulation` | known-truth temporal/event data generation | | `validation_core` | RMSE, bias, coverage, graph, and Monte Carlo metrics | | `tepp_api` | versioned DTO, schema, and export contracts | +| `prompt_source` | prompt boilerplate is not unique latent content and not stopword deletion | No crate exposes placeholder production behavior in Task 1. This prevents an empty façade from becoming a de facto public API before its invariants and tests diff --git a/CHANGELOG.md b/CHANGELOG.md index 3fe6d08d..70f6e478 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to TEPP are documented here. The format follows Keep a Chang ### Added +- `prompt_source` identity gate: instruction and prompt boilerplate is not unique latent content and is not erased by a stopword list; recovered prompt kinds match known truth at a higher computed rate than collapsing every token to unique content (ADR 0004/0012). - `tepp_api` purpose-bound provider-payload minimization: time-bounded `PurposeGrant` evaluation, fail-closed expired/not-yet-valid/inverted/cross-tenant/impossible-calendar denial, semantic UTC calendar validation, refusal to copy identity mappings into model-provider payloads or ordinary logs, preservation of opaque analytical identifiers and membership roles (no blanket PII mask), a separately authorized scientific re-identification path, and an internally bound FIPS 180-4 SHA-256 audit digest appended through `ReidentificationAuditSink` before disclosure. - `persistence_postgres` retention/deletion/legal-hold (migration `0007`): policy rows, legal holds that block completed deletion, evidence tombstones without raw-source restore, analysis exclusion only for `logical_revocation`/`identity_tombstone` (not `cache_export_removal`), and deletion requests bound to the cited retention policy's tenant/class/purpose. - `persistence_postgres` backup/restore integrity: restored snapshots stay unusable until tenant, canonical `SHA-256`, knowledge-cutoff eligibility, temporal window order, and append-only triggers revalidate; SQL probes raise `restore integrity failed` (ADR 0013). diff --git a/Cargo.lock b/Cargo.lock index 616bfd78..eb8060e5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -856,6 +856,10 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prompt_source" +version = "0.1.0" + [[package]] name = "quote" version = "1.0.47" diff --git a/Cargo.toml b/Cargo.toml index 92565940..1a7cd1bc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,6 +11,7 @@ members = [ "crates/tepp_simulation", "crates/validation_core", "crates/tepp_api", + "crates/prompt_source", ] default-members = [ "crates/evidence_core", @@ -23,6 +24,7 @@ default-members = [ "crates/tepp_simulation", "crates/validation_core", "crates/tepp_api", + "crates/prompt_source", ] [workspace.package] diff --git a/README.md b/README.md index ae74015d..67f75a1c 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@ implemented in Rust. ## Current implementation state This branch establishes the Task 1 Rust workspace and quality-gate foundation. -The ten bounded crates compile independently but intentionally expose no +The eleven bounded crates compile independently but intentionally expose no placeholder production APIs. Domain behavior begins in Task 2 with immutable evidence identifiers and source records. @@ -22,6 +22,7 @@ crates/corpus_split crates/tepp_simulation crates/validation_core crates/tepp_api +crates/prompt_source ``` ## Local verification diff --git a/crates/prompt_source/Cargo.toml b/crates/prompt_source/Cargo.toml new file mode 100644 index 00000000..9a48d6d0 --- /dev/null +++ b/crates/prompt_source/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "prompt_source" +description = "Prompt boilerplate is not unique content and not stopword deletion." +version.workspace = true +edition.workspace = true +rust-version.workspace = true +license.workspace = true +authors.workspace = true +repository.workspace = true +homepage.workspace = true +readme.workspace = true +keywords.workspace = true +categories.workspace = true +publish = false + +[lints] +workspace = true diff --git a/crates/prompt_source/src/error.rs b/crates/prompt_source/src/error.rs new file mode 100644 index 00000000..678cbbd1 --- /dev/null +++ b/crates/prompt_source/src/error.rs @@ -0,0 +1,53 @@ +//! Fail-closed prompt-source errors. + +use std::fmt; + +/// A fail-closed prompt-source error. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +#[non_exhaustive] +pub enum PromptSourceError { + /// Prompt boilerplate was treated as unique latent content. + PromptIsNotUniqueContent, + /// Prompt boilerplate was treated as stopword deletion. + PromptIsNotStopwordDeletion, + /// A recovery slice was empty or length-mismatched. + InvalidPromptPayload, +} + +impl fmt::Display for PromptSourceError { + fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + let message = match self { + Self::PromptIsNotUniqueContent => "prompt boilerplate is not unique latent content", + Self::PromptIsNotStopwordDeletion => "prompt boilerplate is not stopword deletion", + Self::InvalidPromptPayload => "invalid prompt-source payload", + }; + formatter.write_str(message) + } +} + +impl std::error::Error for PromptSourceError {} + +#[cfg(test)] +mod tests { + use super::PromptSourceError; + + #[test] + fn error_messages_are_stable() { + for (error, message) in [ + ( + PromptSourceError::PromptIsNotUniqueContent, + "prompt boilerplate is not unique latent content", + ), + ( + PromptSourceError::PromptIsNotStopwordDeletion, + "prompt boilerplate is not stopword deletion", + ), + ( + PromptSourceError::InvalidPromptPayload, + "invalid prompt-source payload", + ), + ] { + assert_eq!(error.to_string(), message); + } + } +} diff --git a/crates/prompt_source/src/kind.rs b/crates/prompt_source/src/kind.rs new file mode 100644 index 00000000..5bd9ba76 --- /dev/null +++ b/crates/prompt_source/src/kind.rs @@ -0,0 +1,132 @@ +//! Prompt boilerplate versus unique latent content. + +use crate::PromptSourceError; + +/// Closed vocabulary of prompt-related token treatments. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum PromptKind { + /// Instruction or prompt boilerplate, not unique document meaning. + PromptBoilerplate, + /// Token treatment reserved for unique latent content. + UniqueContent, +} + +impl PromptKind { + /// Return the stable wire kind name. + #[must_use] + pub const fn wire_name(self) -> &'static str { + match self { + Self::PromptBoilerplate => "prompt_boilerplate", + Self::UniqueContent => "unique_content", + } + } + + /// Parse a stable wire kind name. + /// + /// # Errors + /// + /// Returns [`PromptSourceError::InvalidPromptPayload`] for unrecognized + /// names. + pub fn from_wire_name(name: &str) -> Result { + match name { + "prompt_boilerplate" => Ok(Self::PromptBoilerplate), + "unique_content" => Ok(Self::UniqueContent), + _ => Err(PromptSourceError::InvalidPromptPayload), + } + } +} + +/// Refuse to treat prompt boilerplate as unique latent content. +/// +/// # Errors +/// +/// Returns [`PromptSourceError::PromptIsNotUniqueContent`] when `kind` is +/// [`PromptKind::PromptBoilerplate`]. +pub fn refuse_prompt_as_unique_content(kind: PromptKind) -> Result<(), PromptSourceError> { + match kind { + PromptKind::PromptBoilerplate => Err(PromptSourceError::PromptIsNotUniqueContent), + PromptKind::UniqueContent => Ok(()), + } +} + +/// Refuse to treat prompt boilerplate as stopword deletion. +/// +/// # Errors +/// +/// Returns [`PromptSourceError::PromptIsNotStopwordDeletion`] when `kind` is +/// [`PromptKind::PromptBoilerplate`]. +pub fn refuse_prompt_as_stopword_deletion(kind: PromptKind) -> Result<(), PromptSourceError> { + match kind { + PromptKind::PromptBoilerplate => Err(PromptSourceError::PromptIsNotStopwordDeletion), + PromptKind::UniqueContent => Ok(()), + } +} + +/// Fraction of recovered prompt kinds that match known truth. +/// +/// # Errors +/// +/// Returns [`PromptSourceError::InvalidPromptPayload`] when either slice is +/// empty or the lengths differ. +pub fn identity_recovery_rate( + truth: &[PromptKind], + decided: &[PromptKind], +) -> Result { + if truth.is_empty() || truth.len() != decided.len() { + return Err(PromptSourceError::InvalidPromptPayload); + } + let mut matches = 0_u32; + for (truth_kind, decided_kind) in truth.iter().zip(decided) { + if truth_kind == decided_kind { + matches += 1; + } + } + Ok(f64::from(matches) / truth.len() as f64) +} + +#[cfg(test)] +mod tests { + use super::{ + identity_recovery_rate, refuse_prompt_as_stopword_deletion, + refuse_prompt_as_unique_content, PromptKind, + }; + use crate::PromptSourceError; + + #[test] + fn local_branches_cover_kinds_payloads_and_wire_names() { + assert_eq!( + refuse_prompt_as_unique_content(PromptKind::PromptBoilerplate), + Err(PromptSourceError::PromptIsNotUniqueContent) + ); + assert_eq!( + refuse_prompt_as_stopword_deletion(PromptKind::PromptBoilerplate), + Err(PromptSourceError::PromptIsNotStopwordDeletion) + ); + refuse_prompt_as_unique_content(PromptKind::UniqueContent).expect("unique"); + refuse_prompt_as_stopword_deletion(PromptKind::UniqueContent).expect("unique"); + for kind in [PromptKind::PromptBoilerplate, PromptKind::UniqueContent] { + assert_eq!( + PromptKind::from_wire_name(kind.wire_name()).expect("round-trip"), + kind + ); + } + assert_eq!( + PromptKind::from_wire_name("template"), + Err(PromptSourceError::InvalidPromptPayload) + ); + let matched = identity_recovery_rate( + &[PromptKind::PromptBoilerplate], + &[PromptKind::PromptBoilerplate], + ) + .expect("rate"); + assert!((matched - 1.0).abs() < f64::EPSILON); + assert_eq!( + identity_recovery_rate(&[], &[]), + Err(PromptSourceError::InvalidPromptPayload) + ); + assert_eq!( + identity_recovery_rate(&[PromptKind::PromptBoilerplate], &[]), + Err(PromptSourceError::InvalidPromptPayload) + ); + } +} diff --git a/crates/prompt_source/src/lib.rs b/crates/prompt_source/src/lib.rs new file mode 100644 index 00000000..f3e070f2 --- /dev/null +++ b/crates/prompt_source/src/lib.rs @@ -0,0 +1,22 @@ +#![forbid(unsafe_code)] +#![deny(missing_docs)] +#![allow(clippy::cast_precision_loss)] +//! Prompt boilerplate is not unique latent content. +//! +//! Instruction and prompt text stays explicit method structure. It is not +//! unique document meaning and is not erased by a stopword list +//! (ADR 0004/0012). + +mod error; +mod kind; + +/// Fail-closed prompt-source errors. +pub use error::PromptSourceError; +/// Fraction of recovered prompt kinds that match known truth. +pub use kind::identity_recovery_rate; +/// Refuse to treat prompt boilerplate as stopword deletion. +pub use kind::refuse_prompt_as_stopword_deletion; +/// Refuse to treat prompt boilerplate as unique latent content. +pub use kind::refuse_prompt_as_unique_content; +/// Closed vocabulary of prompt-related token treatments. +pub use kind::PromptKind; diff --git a/crates/prompt_source/tests/crate_contract.rs b/crates/prompt_source/tests/crate_contract.rs new file mode 100644 index 00000000..7f82bf4d --- /dev/null +++ b/crates/prompt_source/tests/crate_contract.rs @@ -0,0 +1,7 @@ +//! Integration contract for the `prompt_source` package identity. + +#[test] +fn package_identity_is_stable() { + let observed = std::hint::black_box(env!("CARGO_PKG_NAME")); + assert_eq!(observed, "prompt_source"); +} diff --git a/crates/prompt_source/tests/prompt_source_contract.rs b/crates/prompt_source/tests/prompt_source_contract.rs new file mode 100644 index 00000000..bce40e3e --- /dev/null +++ b/crates/prompt_source/tests/prompt_source_contract.rs @@ -0,0 +1,67 @@ +//! Prompt boilerplate is not unique content and not stopword deletion. + +use prompt_source::{ + identity_recovery_rate, refuse_prompt_as_stopword_deletion, refuse_prompt_as_unique_content, + PromptKind, PromptSourceError, +}; + +#[test] +fn prompt_boilerplate_cannot_become_unique_content_or_stopword_deletion() { + assert_eq!( + refuse_prompt_as_unique_content(PromptKind::PromptBoilerplate), + Err(PromptSourceError::PromptIsNotUniqueContent) + ); + assert_eq!( + refuse_prompt_as_stopword_deletion(PromptKind::PromptBoilerplate), + Err(PromptSourceError::PromptIsNotStopwordDeletion) + ); + refuse_prompt_as_unique_content(PromptKind::UniqueContent).expect("unique"); + refuse_prompt_as_stopword_deletion(PromptKind::UniqueContent).expect("unique"); +} + +#[test] +fn recovered_kinds_match_known_truth_better_than_a_unique_content_collapse() { + let truth = [ + PromptKind::PromptBoilerplate, + PromptKind::UniqueContent, + PromptKind::PromptBoilerplate, + ]; + let recovered = truth; + let collapsed = [ + PromptKind::UniqueContent, + PromptKind::UniqueContent, + PromptKind::UniqueContent, + ]; + let recovered_rate = identity_recovery_rate(&truth, &recovered).expect("recovered"); + let collapsed_rate = identity_recovery_rate(&truth, &collapsed).expect("collapsed"); + let expected = { + let mut matches = 0_u32; + for (truth_kind, decided_kind) in truth.iter().zip(recovered.iter()) { + if truth_kind == decided_kind { + matches += 1; + } + } + f64::from(matches) / f64::from(u32::try_from(truth.len()).expect("len")) + }; + assert!((recovered_rate - expected).abs() < f64::EPSILON); + assert!(recovered_rate > collapsed_rate); +} + +#[test] +fn empty_or_mismatched_kind_payloads_fail_closed() { + assert_eq!( + identity_recovery_rate(&[], &[]), + Err(PromptSourceError::InvalidPromptPayload) + ); + assert_eq!( + identity_recovery_rate(&[PromptKind::PromptBoilerplate], &[]), + Err(PromptSourceError::InvalidPromptPayload) + ); + assert_eq!( + identity_recovery_rate( + &[PromptKind::PromptBoilerplate, PromptKind::UniqueContent], + &[PromptKind::PromptBoilerplate] + ), + Err(PromptSourceError::InvalidPromptPayload) + ); +} diff --git a/docs/TRACEABILITY.md b/docs/TRACEABILITY.md index dfcdd9e8..8ea301c2 100644 --- a/docs/TRACEABILITY.md +++ b/docs/TRACEABILITY.md @@ -25,7 +25,7 @@ The full APA 7th standards/literature register remains `docs/research/standards- | TRSL-TM temporal/relational topic posterior and backend compatibility | ADR 0012; ADR 0004 | future `topic_measurement` | accepted-target | | global P0 topic identity with activity/dormancy/reactivation | ADR 0012 | future topic lineage/activity state | accepted-target | | no default stopword deletion / no TF-IDF-BM25 inferential weighting | ADR 0004/0012; PRD/TRD | future semantic/method-source model | accepted-target | -| report template/section/copied/style/modality method effects | ADR 0004/0012; PRD/TRD | simulation truth factors implemented; estimator-side method model remains future | partial | +| report template/section/copied/style/modality method effects | ADR 0004/0012; PRD/TRD | simulation truth factors implemented; `prompt_source` prompt-versus-unique-content identity on the active PR; estimator-side method model remains future | partial | | candidate K statistical/Pareto gates + blinded LLM review | ADR 0012; research | future `model_selection` | accepted-target | | compositional topic correlation / stable clustering | ADR 0005/0012; research | future `network_analysis` | accepted-target | | posterior ESEM / longitudinal invariance / DSEM | ADR 0005 | future `psychometric_core` | accepted-target | diff --git a/docs/adr/0004-shared-multilingual-latent-space.md b/docs/adr/0004-shared-multilingual-latent-space.md index c8da25b5..2ca03cbc 100644 --- a/docs/adr/0004-shared-multilingual-latent-space.md +++ b/docs/adr/0004-shared-multilingual-latent-space.md @@ -1,7 +1,7 @@ # ADR 0004 — Shared multilingual latent semantic space **Decision status:** Accepted -**Implementation maturity:** accepted-target +**Implementation maturity:** accepted-target — prompt-versus-unique-content identity in `prompt_source` on the active PR; shared-space estimators remain accepted-target **Date:** 2026-08-05 **Supersedes:** None. ADR 0012 governs the complete topic-estimator/backend/global-topic contract built on this multilingual measurement decision. diff --git a/docs/adr/0012-temporal-relational-shared-latent-topic-measurement.md b/docs/adr/0012-temporal-relational-shared-latent-topic-measurement.md index c3d5085f..671140a3 100644 --- a/docs/adr/0012-temporal-relational-shared-latent-topic-measurement.md +++ b/docs/adr/0012-temporal-relational-shared-latent-topic-measurement.md @@ -1,7 +1,7 @@ # ADR 0012 — Temporal Relational Shared-Latent Topic Measurement **Decision status:** Accepted -**Implementation maturity:** accepted-target +**Implementation maturity:** accepted-target — prompt-versus-unique-content identity in `prompt_source` on the active PR; estimator-side method model remains accepted-target **Date:** 2026-08-12 **Supersedes:** None; refines ADR 0004 and ADR 0005 without replacing their multilingual and psychometric authorities. diff --git a/docs/adr/README.md b/docs/adr/README.md index f16c2345..54913cba 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -9,7 +9,7 @@ Read [`ADR_POLICY.md`](ADR_POLICY.md) first. **Decision status and implementatio | [0001](0001-rust-first-modular-msa.md) | Rust-first numerical core and CPU `f64` reference | Accepted | partial | ADR 0011 owns cross-service/MSA authority; 0001 retains numerical/backend authority. | | [0002](0002-six-clock-temporal-semantics.md) | Six-clock temporal semantics and fail-closed historical leakage prevention | Accepted | active-PR | Unmerged PR #8 is the canonical Task 3 replacement implementing typed clocks/intervals against the current protected-main lineage; conflicted PR #5 is superseded lineage. Later graph/split enforcement remains target work. | | [0003](0003-relational-event-multiple-membership.md) | Relational event ontology and time-varying cross-classified multiple membership | Accepted | partial | Weighted time-varying membership network/roles are active-PR (PR #12); full multilevel estimators, graph ontology, and persistence remain accepted-target. ADR 0016 owns event-intelligence tasks. | -| [0004](0004-shared-multilingual-latent-space.md) | One shared multilingual latent space with explicit invariance status | Accepted | accepted-target | ADR 0012 owns the full topic-estimator/backend/global-topic contract. | +| [0004](0004-shared-multilingual-latent-space.md) | One shared multilingual latent space with explicit invariance status | Accepted | accepted-target | Prompt-versus-unique-content identity is `prompt_source` on the active PR; ADR 0012 owns the full topic-estimator contract. | | [0005](0005-posterior-esem-dsem.md) | Posterior-aware ESEM/DSEM and valid compositional coordinates | Accepted | accepted-target | Downstream psychometric authority; upstream topic/network model is clarified by ADR 0012. | | [0006](0006-vram-gpu-nvidia-orchestration.md) | VRAM-adaptive GPU compute and model-credential boundary | Accepted | accepted-target | LLM orchestration policy superseded by ADR 0010; autonomous development authority governed by ADR 0015. | | [0007](0007-rust-workspace-quality-gates.md) | Explicit Rust workspace, pinned toolchains, and exact quality gates | Accepted | implemented-main | ADR 0014 governs scientific/product claim promotion beyond repository-quality tooling. | @@ -17,7 +17,7 @@ Read [`ADR_POLICY.md`](ADR_POLICY.md) first. **Decision status and implementatio | [0009](0009-purpose-bound-pii-governance.md) | Purpose-bound PII governance without blanket masking | Accepted | partial | Persistence retention/deletion/legal-hold (`0007`) implemented-main; provider-payload minimization and elevated re-identification are on the active PR; deployment evidence remains accepted-target. | | [0010](0010-adaptive-llm-orchestration.md) | Adaptive LLM orchestration and test-time compute | Accepted | accepted-target | Owns direct/verify/committee/conductor selection, budget, role/topology, and ablation policy. | | [0011](0011-standalone-modular-msa-boundary.md) | Standalone operation and modular CWL MSA boundary | Accepted | partial | Owns cross-service persistence/credential/API authority; no direct cross-service application-table coupling. | -| [0012](0012-temporal-relational-shared-latent-topic-measurement.md) | Temporal Relational Shared-Latent Topic Measurement (TRSL-TM) | Accepted | accepted-target | Owns topic backend compatibility, global topic identity, method effects, K/model-selection prerequisites, and compositional topic coordinates. | +| [0012](0012-temporal-relational-shared-latent-topic-measurement.md) | Temporal Relational Shared-Latent Topic Measurement (TRSL-TM) | Accepted | accepted-target | Prompt-versus-unique-content identity is `prompt_source` on the active PR; estimator-side method model, backend, and K gates remain accepted-target. | | [0013](0013-bitemporal-persistence-reproducibility-and-split-authority.md) | Bitemporal persistence, reproducibility manifests, and relation-aware split authority | Accepted | partial | Owns PostgreSQL adapter semantics, immutable run/split manifests, leakage-safe partitions, and recovery identity; optional `live-sqlx` `PgPool`, live PG CI, tenant RLS, and `0006` membership implemented-main; `0007` retention/deletion/legal-hold on the active PR; remaining physical ERD/backup accepted-target. | | [0014](0014-scientific-claim-promotion-and-release-evidence.md) | Scientific claim promotion and release evidence authority | Accepted | partial | Separates design, implementation, scientific/product claim, and release authority; repository SBOM/provenance generator implemented, full release bundle remaining. | | [0015](0015-autonomous-development-review-and-merge-authority.md) | Autonomous development, review, and merge authority separation | Accepted | active-PR | Separates model proposal, deterministic verification, publication, independent review, and merge/release authority. | diff --git a/docs/research/prompt-source-identity.md b/docs/research/prompt-source-identity.md new file mode 100644 index 00000000..f35acb2b --- /dev/null +++ b/docs/research/prompt-source-identity.md @@ -0,0 +1,31 @@ +# Prompt boilerplate is not unique content (doctoring) + +## Scope + +`prompt_source` keeps instruction and prompt boilerplate out of unique +latent content and out of global stopword deletion. Recovery is the +computed share of recovered kinds that match known truth. + +This slice does not persist method sources, allocate migration `0008`, +or replace `method_effects`, `section_source`, `style_source`, +`copied_text`, `modality_source`, `corpus_background`, or +`stopword_deletion`. + +## Authority + +### Normative TEPP contract + +- `docs/adr/0004-shared-multilingual-latent-space.md` and + `docs/adr/0012-temporal-relational-shared-latent-topic-measurement.md` + — method and template sources are modeled explicitly and are not + inferential topic weights or stopword deletions. + +### Supporting literature + +Liu et al. (2023) treat prompting as a method condition that shapes +emissions. Prompt text is not the document's unique latent meaning. + +Liu, P., Yuan, W., Fu, J., Jiang, Z., Hayashi, H., & Neubig, G. (2023). +Pre-train, prompt, and predict: A systematic survey of prompting methods +in natural language processing. *ACM Computing Surveys, 55*(9), Article +195. https://doi.org/10.1145/3560815 diff --git a/docs/research/standards-and-literature.md b/docs/research/standards-and-literature.md index 6e0438fe..e8911e14 100644 --- a/docs/research/standards-and-literature.md +++ b/docs/research/standards-and-literature.md @@ -32,7 +32,9 @@ Bianchi, F., Terragni, S., Hovy, D., Nozza, D., & Fersini, E. (2021). Cross-ling Nguyen, T. P., Minh, N. V., Nguyen, T., Van, L. N., Nguyen, D. A., Sang, D. V., & Le, T. (2025). XTRA: Cross-lingual topic modeling with topic and representation alignments. In *Findings of the Association for Computational Linguistics: EMNLP 2025*. Association for Computational Linguistics. -TEPP retains a logistic-normal CPU reference while allowing adapter backends that satisfy shared-latent, posterior, temporal, relational, and measurement-invariance contracts. +Liu, P., Yuan, W., Fu, J., Jiang, Z., Hayashi, H., & Neubig, G. (2023). Pre-train, prompt, and predict: A systematic survey of prompting methods in natural language processing. *ACM Computing Surveys, 55*(9), Article 195. https://doi.org/10.1145/3560815 + +TEPP retains a logistic-normal CPU reference while allowing adapter backends that satisfy shared-latent, posterior, temporal, relational, and measurement-invariance contracts. Instruction and prompt boilerplate is modeled as explicit method structure, not unique latent content and not a stopword deletion (Liu et al., 2023). ## Topic-model evaluation and LLM judges diff --git a/docs/validation/temporal-event-foundation.md b/docs/validation/temporal-event-foundation.md index 7c50db23..7560c166 100644 --- a/docs/validation/temporal-event-foundation.md +++ b/docs/validation/temporal-event-foundation.md @@ -23,6 +23,7 @@ This report tracks exact-head scientific and engineering evidence required befor | Truth corpora / manifests | `tepp_simulation` | implemented-main | — | deterministic generator tests | Task 10 / PR #18 | | Recovery metrics | `validation_core` | implemented-main | — | RMSE/bias/coverage/MC gates | Task 11 / PR #19 | | Versioned API/export contracts | `tepp_api` | implemented-main | naruon HTTP interchange | unknown-field/version/limit + naruon HTTPS interchange tests | Task 12 / PR #21; live HTTP service remaining | +| Prompt-versus-unique-content identity | `prompt_source` | accepted-target | active PR | refuse prompt-as-unique/stopword + recovery vs unique-content collapse | ADR 0004/0012 | | Purpose-bound provider payloads | `tepp_api` | active-PR | provider-payload minimization | expired/not-yet-valid/inverted/cross-tenant/impossible-calendar grant, mapping refusal, audited elevated re-id replay | ADR 0009; `docs/research/provider-payload-minimization.md` | | CWL modular connectors | `docs/connectors/*` | implemented-main | — | contract docs + examples | PR #22; live HTTP ports remaining | | Release SBOM/provenance generator | `scripts/release_evidence.py` | partial | — | generate+validate in CI | Task 13 partial / PR #28 | diff --git a/scripts/check_workspace_contract.py b/scripts/check_workspace_contract.py index c7b1ecf5..3b810361 100644 --- a/scripts/check_workspace_contract.py +++ b/scripts/check_workspace_contract.py @@ -23,6 +23,7 @@ "tepp_simulation", "validation_core", "tepp_api", + "prompt_source", ) REQUIRED_CI_SNIPPETS: tuple[str, ...] = ( From 5319e0ca0baa581fb7890b51e38e638aae4dc69b Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 02:52:13 +0900 Subject: [PATCH 2/7] fix(prompt-source): apply repository rustfmt --- crates/prompt_source/src/kind.rs | 4 ++-- crates/prompt_source/src/lib.rs | 4 ++-- crates/prompt_source/tests/prompt_source_contract.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crates/prompt_source/src/kind.rs b/crates/prompt_source/src/kind.rs index 5bd9ba76..ad3d09d7 100644 --- a/crates/prompt_source/src/kind.rs +++ b/crates/prompt_source/src/kind.rs @@ -87,8 +87,8 @@ pub fn identity_recovery_rate( #[cfg(test)] mod tests { use super::{ - identity_recovery_rate, refuse_prompt_as_stopword_deletion, - refuse_prompt_as_unique_content, PromptKind, + PromptKind, identity_recovery_rate, refuse_prompt_as_stopword_deletion, + refuse_prompt_as_unique_content, }; use crate::PromptSourceError; diff --git a/crates/prompt_source/src/lib.rs b/crates/prompt_source/src/lib.rs index f3e070f2..8f8893f4 100644 --- a/crates/prompt_source/src/lib.rs +++ b/crates/prompt_source/src/lib.rs @@ -12,11 +12,11 @@ mod kind; /// Fail-closed prompt-source errors. pub use error::PromptSourceError; +/// Closed vocabulary of prompt-related token treatments. +pub use kind::PromptKind; /// Fraction of recovered prompt kinds that match known truth. pub use kind::identity_recovery_rate; /// Refuse to treat prompt boilerplate as stopword deletion. pub use kind::refuse_prompt_as_stopword_deletion; /// Refuse to treat prompt boilerplate as unique latent content. pub use kind::refuse_prompt_as_unique_content; -/// Closed vocabulary of prompt-related token treatments. -pub use kind::PromptKind; diff --git a/crates/prompt_source/tests/prompt_source_contract.rs b/crates/prompt_source/tests/prompt_source_contract.rs index bce40e3e..966976ec 100644 --- a/crates/prompt_source/tests/prompt_source_contract.rs +++ b/crates/prompt_source/tests/prompt_source_contract.rs @@ -1,8 +1,8 @@ //! Prompt boilerplate is not unique content and not stopword deletion. use prompt_source::{ - identity_recovery_rate, refuse_prompt_as_stopword_deletion, refuse_prompt_as_unique_content, - PromptKind, PromptSourceError, + PromptKind, PromptSourceError, identity_recovery_rate, refuse_prompt_as_stopword_deletion, + refuse_prompt_as_unique_content, }; #[test] From c5fb37d9855a0df97bee899e5c31a8e3d2bc9801 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 05:07:44 +0900 Subject: [PATCH 3/7] test(quality): derive docstring crate count from workspace contract --- tests/quality/test_check_docstrings.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/quality/test_check_docstrings.py b/tests/quality/test_check_docstrings.py index 2c11f7a5..da59f799 100644 --- a/tests/quality/test_check_docstrings.py +++ b/tests/quality/test_check_docstrings.py @@ -11,6 +11,7 @@ from unittest import mock from scripts import check_docstrings as docstrings +from scripts import check_workspace_contract as workspace_contract REPOSITORY_ROOT = Path(__file__).resolve().parents[2] @@ -24,7 +25,7 @@ def test_live_repository_is_documented(self) -> None: sources = docstrings.rust_sources(REPOSITORY_ROOT) crate_roots = sorted(REPOSITORY_ROOT.glob("crates/*/src/lib.rs")) - self.assertEqual(len(crate_roots), 10) + self.assertEqual(len(crate_roots), len(workspace_contract.EXPECTED_CRATES)) self.assertTrue(set(crate_roots).issubset(sources)) self.assertGreaterEqual(len(sources), len(crate_roots)) self.assertEqual(docstrings.validate_repository(REPOSITORY_ROOT), []) From 9409d83d29e7fca707e5833ae025550f9d09a65f Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 05:37:35 +0900 Subject: [PATCH 4/7] docs: remove duplicate provider payload ledger row --- docs/validation/temporal-event-foundation.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/validation/temporal-event-foundation.md b/docs/validation/temporal-event-foundation.md index 471eb315..80dadcad 100644 --- a/docs/validation/temporal-event-foundation.md +++ b/docs/validation/temporal-event-foundation.md @@ -24,7 +24,6 @@ This report tracks exact-head scientific and engineering evidence required befor | Recovery metrics | `validation_core` | implemented-main | — | RMSE/bias/coverage/MC gates | Task 11 / PR #19 | | Versioned API/export contracts | `tepp_api` | implemented-main | naruon HTTP interchange | unknown-field/version/limit + naruon HTTPS interchange tests | Task 12 / PR #21; live HTTP service remaining | | Prompt-versus-unique-content identity | `prompt_source` | accepted-target | active PR | refuse prompt-as-unique/stopword + recovery vs unique-content collapse | ADR 0004/0012 | -| Purpose-bound provider payloads | `tepp_api` | active-PR | provider-payload minimization | expired/not-yet-valid/inverted/cross-tenant/impossible-calendar grant, mapping refusal, audited elevated re-id replay | ADR 0009; `docs/research/provider-payload-minimization.md` | | Purpose-bound provider payloads | `tepp_api` | implemented-main | provider-payload minimization | expired/not-yet-valid/inverted/cross-tenant/impossible-calendar grant, mapping refusal, audited elevated re-id replay | ADR 0009; `docs/research/provider-payload-minimization.md` | | Adaptive orchestration router | `tepp_api` | accepted-target | active PR | mode selection, document-control denial, ablation, credential-free bind | ADR 0010; `docs/research/adaptive-orchestration-router.md` | | CWL modular connectors | `docs/connectors/*` | implemented-main | — | contract docs + examples | PR #22; live HTTP ports remaining | From a67d90381d62ccb2a094fca2f722e729761cbd53 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 06:27:37 +0900 Subject: [PATCH 5/7] docs(prompt): bound identity claim to repository policy --- CHANGELOG.md | 2 +- docs/research/prompt-source-identity.md | 7 +++++-- docs/research/standards-and-literature.md | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6f2c00c6..3240d3fc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ All notable changes to TEPP are documented here. The format follows Keep a Chang ### Added -- `prompt_source` identity gate: instruction and prompt boilerplate is not unique latent content and is not erased by a stopword list; recovered prompt kinds match known truth at a higher computed rate than collapsing every token to unique content (ADR 0004/0012). +- `prompt_source` identity gate: instruction and prompt boilerplate is not unique latent content and is not erased by a stopword list; on the mixed known-truth fixture, recovered prompt kinds match known truth at a higher computed rate than collapsing every token to unique content (ADR 0004/0012). - `tepp_api` adaptive orchestration router (ADR 0010): versioned `direct`/`verify`/`committee`/`conductor`/`abstain` selection from CPU `f64` risk, ambiguity, evidence, and token-budget inputs; recorded stages, recursion, decomposition, access lists, and role-specific reasoning effort; fail-closed document-controlled policy/access/credentials; LLM plans remain proposals under deterministic statistical authority; comparable-budget ablation requires a direct baseline; credential-free contextual-orchestrator binding. Live NIM HTTP remains accepted-target. - `tepp_api` purpose-bound provider-payload minimization: time-bounded `PurposeGrant` evaluation, fail-closed expired/not-yet-valid/inverted/cross-tenant/impossible-calendar denial, semantic UTC calendar validation, refusal to copy identity mappings into model-provider payloads or ordinary logs, preservation of opaque analytical identifiers and membership roles (no blanket PII mask), a separately authorized scientific re-identification path, and an internally bound FIPS 180-4 SHA-256 audit digest appended through `ReidentificationAuditSink` before disclosure. - `persistence_postgres` backup/restore integrity: restored snapshots stay unusable until tenant, canonical `SHA-256`, knowledge-cutoff eligibility, temporal window order, and append-only triggers revalidate; SQL probes raise `restore integrity failed` (ADR 0013). diff --git a/docs/research/prompt-source-identity.md b/docs/research/prompt-source-identity.md index f35acb2b..fe329fc6 100644 --- a/docs/research/prompt-source-identity.md +++ b/docs/research/prompt-source-identity.md @@ -22,8 +22,11 @@ or replace `method_effects`, `section_source`, `style_source`, ### Supporting literature -Liu et al. (2023) treat prompting as a method condition that shapes -emissions. Prompt text is not the document's unique latent meaning. +Liu et al. (2023) is retained as a secondary survey of prompting methods and +is not used as evidence for the repository's latent-content classification. +The statement that prompt boilerplate is not unique latent content is a +normative TEPP measurement contract derived from ADR 0004 and ADR 0012, not a +universal empirical claim about every prompt or corpus. Liu, P., Yuan, W., Fu, J., Jiang, Z., Hayashi, H., & Neubig, G. (2023). Pre-train, prompt, and predict: A systematic survey of prompting methods diff --git a/docs/research/standards-and-literature.md b/docs/research/standards-and-literature.md index a5ff2048..e1612e5a 100644 --- a/docs/research/standards-and-literature.md +++ b/docs/research/standards-and-literature.md @@ -34,7 +34,7 @@ Nguyen, T. P., Minh, N. V., Nguyen, T., Van, L. N., Nguyen, D. A., Sang, D. V., Liu, P., Yuan, W., Fu, J., Jiang, Z., Hayashi, H., & Neubig, G. (2023). Pre-train, prompt, and predict: A systematic survey of prompting methods in natural language processing. *ACM Computing Surveys, 55*(9), Article 195. https://doi.org/10.1145/3560815 -TEPP retains a logistic-normal CPU reference while allowing adapter backends that satisfy shared-latent, posterior, temporal, relational, and measurement-invariance contracts. Instruction and prompt boilerplate is modeled as explicit method structure, not unique latent content and not a stopword deletion (Liu et al., 2023). +TEPP retains a logistic-normal CPU reference while allowing adapter backends that satisfy shared-latent, posterior, temporal, relational, and measurement-invariance contracts. As a normative ADR 0004/0012 contract, instruction and prompt boilerplate is modeled as explicit method structure, not unique latent content and not a stopword deletion. Liu et al. (2023) remains secondary background on prompting methods, not empirical support for that repository-specific classification. ## Topic-model evaluation and LLM judges From 70a6c6608e39df757417b2674f0acf27aa09b612 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Fri, 21 Aug 2026 11:04:04 +0900 Subject: [PATCH 6/7] docs: narrow prompt identity evidence claims --- CHANGELOG.md | 2 +- docs/research/prompt-source-identity.md | 29 +++++++++++++++-------- docs/research/standards-and-literature.md | 6 ++++- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9c10a794..3c3be4ca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,7 +6,7 @@ All notable changes to TEPP are documented here. The format follows Keep a Chang ### Added -- `prompt_source` identity gate: instruction and prompt boilerplate is not unique latent content and is not erased by a stopword list; on the mixed known-truth fixture, recovered prompt kinds match known truth at a higher computed rate than collapsing every token to unique content (ADR 0004/0012). +- `prompt_source` identity gate: instruction and prompt boilerplate is not unique latent content and is not erased by a stopword list; `identity_recovery_rate` reports exact kind matches, with a contract test comparing correct recovery with an all-unique collapse on a mixed known-truth fixture (ADR 0004/0012). - `tepp_api` naruon live loopback HTTP/1.1 listener: `serve_one` installs a read/write deadline, requires a loopback `Host`, refuses `Transfer-Encoding` and NIM/proxy credential headers, parses `knowledge_cutoff` as RFC 3339 and refuses a future cutoff, keys analysis-run idempotency by tenant plus key, and proves both analysis-run and export POSTs over a real `TcpStream`. Not a production TLS/`$PORT` service (ADR 0011). - `tepp_api` adaptive orchestration router (ADR 0010): versioned `direct`/`verify`/`committee`/`conductor`/`abstain` selection from CPU `f64` risk, ambiguity, evidence, and token-budget inputs; recorded stages, recursion, decomposition, access lists, and role-specific reasoning effort; fail-closed document-controlled policy/access/credentials; LLM plans remain proposals under deterministic statistical authority; comparable-budget ablation requires a direct baseline; credential-free contextual-orchestrator binding. Live NIM HTTP remains accepted-target. - `tepp_api` purpose-bound provider-payload minimization: time-bounded `PurposeGrant` evaluation, fail-closed expired/not-yet-valid/inverted/cross-tenant/impossible-calendar denial, semantic UTC calendar validation, refusal to copy identity mappings into model-provider payloads or ordinary logs, preservation of opaque analytical identifiers and membership roles (no blanket PII mask), a separately authorized scientific re-identification path, and an internally bound FIPS 180-4 SHA-256 audit digest appended through `ReidentificationAuditSink` before disclosure. diff --git a/docs/research/prompt-source-identity.md b/docs/research/prompt-source-identity.md index fe329fc6..884ca696 100644 --- a/docs/research/prompt-source-identity.md +++ b/docs/research/prompt-source-identity.md @@ -22,13 +22,22 @@ or replace `method_effects`, `section_source`, `style_source`, ### Supporting literature -Liu et al. (2023) is retained as a secondary survey of prompting methods and -is not used as evidence for the repository's latent-content classification. -The statement that prompt boilerplate is not unique latent content is a -normative TEPP measurement contract derived from ADR 0004 and ADR 0012, not a -universal empirical claim about every prompt or corpus. - -Liu, P., Yuan, W., Fu, J., Jiang, Z., Hayashi, H., & Neubig, G. (2023). -Pre-train, prompt, and predict: A systematic survey of prompting methods -in natural language processing. *ACM Computing Surveys, 55*(9), Article -195. https://doi.org/10.1145/3560815 +Brown et al. (2020) provide primary evidence that textual prompts and +demonstrations condition language-model task behavior, while Reynolds and +McDonell (2021) study prompt programming as a method for directing model +behavior. Neither study defines TEPP's latent-content labels. The statement +that prompt boilerplate is not unique latent content is therefore a normative +TEPP measurement contract derived from ADR 0004 and ADR 0012, not a universal +empirical claim about every prompt or corpus. + +Brown, T. B., Mann, B., Ryder, N., Subbiah, M., Kaplan, J. D., Dhariwal, P., +Neelakantan, A., Shyam, P., Sastry, G., Askell, A., Agarwal, S., Herbert-Voss, +A., Krueger, G., Henighan, T., Child, R., Ramesh, A., Ziegler, D., Wu, J., +Winter, C., … Amodei, D. (2020). Language models are few-shot learners. +*Advances in Neural Information Processing Systems, 33*, 1877–1901. +https://papers.neurips.cc/paper/2020/hash/1457c0d6bfcb4967418bfb8ac142f64a-Abstract.html + +Reynolds, L., & McDonell, K. (2021). Prompt programming for large language +models: Beyond the few-shot paradigm. In *Extended abstracts of the 2021 CHI +conference on human factors in computing systems*. Association for Computing +Machinery. https://doi.org/10.1145/3411763.3451760 diff --git a/docs/research/standards-and-literature.md b/docs/research/standards-and-literature.md index a14dc6f7..d32a3ad1 100644 --- a/docs/research/standards-and-literature.md +++ b/docs/research/standards-and-literature.md @@ -32,9 +32,13 @@ Bianchi, F., Terragni, S., Hovy, D., Nozza, D., & Fersini, E. (2021). Cross-ling Nguyen, T. P., Minh, N. V., Nguyen, T., Van, L. N., Nguyen, D. A., Sang, D. V., & Le, T. (2025). XTRA: Cross-lingual topic modeling with topic and representation alignments. In *Findings of the Association for Computational Linguistics: EMNLP 2025*. Association for Computational Linguistics. +Brown, T. B., Mann, B., Ryder, N., Subbiah, M., Kaplan, J. D., Dhariwal, P., Neelakantan, A., Shyam, P., Sastry, G., Askell, A., Agarwal, S., Herbert-Voss, A., Krueger, G., Henighan, T., Child, R., Ramesh, A., Ziegler, D., Wu, J., Winter, C., … Amodei, D. (2020). Language models are few-shot learners. *Advances in Neural Information Processing Systems, 33*, 1877–1901. https://papers.neurips.cc/paper/2020/hash/1457c0d6bfcb4967418bfb8ac142f64a-Abstract.html + +Reynolds, L., & McDonell, K. (2021). Prompt programming for large language models: Beyond the few-shot paradigm. In *Extended abstracts of the 2021 CHI conference on human factors in computing systems*. Association for Computing Machinery. https://doi.org/10.1145/3411763.3451760 + Liu, P., Yuan, W., Fu, J., Jiang, Z., Hayashi, H., & Neubig, G. (2023). Pre-train, prompt, and predict: A systematic survey of prompting methods in natural language processing. *ACM Computing Surveys, 55*(9), Article 195. https://doi.org/10.1145/3560815 -TEPP retains a logistic-normal CPU reference while allowing adapter backends that satisfy shared-latent, posterior, temporal, relational, and measurement-invariance contracts. As a normative ADR 0004/0012 contract, instruction and prompt boilerplate is modeled as explicit method structure, not unique latent content and not a stopword deletion. Liu et al. (2023) remains secondary background on prompting methods, not empirical support for that repository-specific classification. +TEPP retains a logistic-normal CPU reference while allowing adapter backends that satisfy shared-latent, posterior, temporal, relational, and measurement-invariance contracts. Brown et al. (2020) and Reynolds and McDonell (2021) provide primary research context for prompts as task-conditioning and prompt-programming mechanisms; they do not define TEPP's latent-content labels. As a normative ADR 0004/0012 contract, instruction and prompt boilerplate is therefore modeled as explicit method structure, not unique latent content and not a stopword deletion. Liu et al. (2023) is secondary survey background only and is not evidence for that repository-specific classification. ## Topic-model evaluation and LLM judges From c1bd092d1319728c9dbdf4be744eb0e795d98207 Mon Sep 17 00:00:00 2001 From: Seongho Bae Date: Mon, 24 Aug 2026 18:50:43 +0900 Subject: [PATCH 7/7] chore: regenerate Cargo.lock after main merge --- Cargo.lock | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index fcd7b90e..656738e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1101,6 +1101,10 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "prompt_source" +version = "0.1.0" + [[package]] name = "provider_receipt" version = "0.1.0"