From b76889582cb1bf1a032f6ae2351cf4eb464281ae Mon Sep 17 00:00:00 2001 From: TheFlow Date: Sun, 22 Feb 2026 18:48:48 +1300 Subject: [PATCH] fix(docs): require document_type and audience before publishing MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Documents could be set to visibility: 'public' without document_type, audience, or status fields — either via bulk migration scripts or the upload-document.js script. This allowed internal session logs to appear in the public docs UI. Safeguards added: - Document.publish() now rejects if document_type or audience is missing - Document.publish() now sets status: 'current' automatically - upload-document.js requires --type and --category flags (was optional) - upload-document.js sets status: 'current' and document_type on insert Also archived 2 internal Phase 5 PoC session documents that were incorrectly public, and set status: 'current' on 4 legitimate public documents that were missing it. Co-Authored-By: Claude Opus 4.6 --- scripts/upload-document.js | 23 ++++++++++++++++++++++- src/models/Document.model.js | 18 ++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/scripts/upload-document.js b/scripts/upload-document.js index dc8e812b..b995e334 100644 --- a/scripts/upload-document.js +++ b/scripts/upload-document.js @@ -41,8 +41,10 @@ if (args.length === 0 || args[0] === '--help' || args[0] === '-h') { Usage: node scripts/upload-document.js [options] Options: - --category Category: getting-started, technical-reference, research-theory, + --category REQUIRED. Category: getting-started, technical-reference, research-theory, advanced-topics, case-studies, business-leadership + --type REQUIRED. Document type: working-paper, case-study, technical-report, + guide, reference, brief --audience Audience: general, researcher, implementer, leader, advocate, developer --title Override document title (extracted from H1 if not provided) --author <author> Document author (default: Agentic Governance Research Team) @@ -67,12 +69,14 @@ Examples: # Upload research paper node scripts/upload-document.js docs/research/my-paper.md \\ --category research-theory \\ + --type working-paper \\ --audience researcher \\ --tags "ai-safety,governance,research" # Upload technical guide (no PDF) node scripts/upload-document.js docs/guides/setup.md \\ --category getting-started \\ + --type guide \\ --audience developer \\ --no-pdf @@ -96,6 +100,7 @@ if (!mdFilePath) { const options = { category: null, audience: 'general', + document_type: null, title: null, author: 'Agentic Governance Research Team', tags: [], @@ -115,6 +120,9 @@ for (let i = 1; i < args.length; i++) { case '--audience': options.audience = args[++i]; break; + case '--type': + options.document_type = args[++i]; + break; case '--title': options.title = args[++i]; break; @@ -481,6 +489,17 @@ async function uploadDocument() { try { console.log('\n=== Tractatus Document Upload ===\n'); + // SECURITY: Require --category and --type for public documents + const validTypes = ['working-paper', 'case-study', 'technical-report', 'guide', 'reference', 'brief']; + if (!options.category) { + console.error('❌ Error: --category is required. Available: getting-started, resources, research-theory, technical-reference, advanced-topics, business-leadership'); + process.exit(1); + } + if (!options.document_type || !validTypes.includes(options.document_type)) { + console.error(`❌ Error: --type is required. Available: ${validTypes.join(', ')}`); + process.exit(1); + } + // Verify markdown file exists const mdPath = path.resolve(mdFilePath); try { @@ -559,7 +578,9 @@ async function uploadDocument() { quadrant: null, persistence: 'HIGH', audience: options.audience, + document_type: options.document_type, visibility: 'public', + status: 'current', category: options.category, licence: options.licence, order: options.order, diff --git a/src/models/Document.model.js b/src/models/Document.model.js index d1e36416..dfabffd2 100644 --- a/src/models/Document.model.js +++ b/src/models/Document.model.js @@ -214,6 +214,23 @@ class Document { return { success: false, message: 'Document must have content before publishing' }; } + // SECURITY: Require document_type for public docs + const docType = doc.document_type; + if (!docType) { + return { + success: false, + message: 'Document must have a document_type before publishing. Set document_type to one of: working-paper, case-study, technical-report, guide, reference, brief' + }; + } + + // SECURITY: Require audience for public docs + if (!doc.audience) { + return { + success: false, + message: 'Document must have an audience before publishing. Set audience to one of: researcher, implementer, leader, general' + }; + } + // SECURITY: Require valid category for public docs const category = options.category || doc.category; if (!category || category === 'none') { @@ -241,6 +258,7 @@ class Document { { $set: { visibility: 'public', + status: 'current', category, order: options.order !== undefined ? options.order : doc.order, workflow_status: 'published',