← back to Approval Command Center
ACC: dynamic file scan for new pending-approval items (was stale manifest-only)
4af2af79c4e76231de57a56bf386a4e08b9badf2 · 2026-08-11 04:09:58 -0700 · Steve Abrams
Files touched
M public/index.htmlM server.js
Diff
commit 4af2af79c4e76231de57a56bf386a4e08b9badf2
Author: Steve Abrams <steve@designerwallcoverings.com>
Date: Tue Aug 11 04:09:58 2026 -0700
ACC: dynamic file scan for new pending-approval items (was stale manifest-only)
---
public/index.html | 2 +-
server.js | 42 +++++++++++++++++++++++++++++++++++++++++-
2 files changed, 42 insertions(+), 2 deletions(-)
diff --git a/public/index.html b/public/index.html
index f1cec81..9dc02b7 100644
--- a/public/index.html
+++ b/public/index.html
@@ -3,7 +3,7 @@
<head>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
-<title>Approval Command Center — 109 gated drafts</title>
+<title>Approval Command Center</title>
<style>
:root{ --cols:3; --bg:#0f1115; --panel:#171a21; --line:#252a34; --ink:#e7ebf0; --dim:#98a2b3; --teal:#33c2b8; --gold:#d9b166; }
*{box-sizing:border-box}
diff --git a/server.js b/server.js
index 275b15f..ef8d73b 100644
--- a/server.js
+++ b/server.js
@@ -54,9 +54,49 @@ function severity(gate, reversible) {
}
// ---- data -------------------------------------------------------------------
+// Auto-classify a .md file that isn't in the manifest yet.
+function autoClassify(slug, body) {
+ const low = (body || '').toLowerCase();
+ // reversible heuristics
+ const reversible = /reversible|dry.?run|rollback|staged|undo|no.?prod.?write|read.?only/.test(low)
+ && !/irreversible|destructive|cannot.?undo|permanent/.test(low);
+ // gate heuristics
+ let gate = 'deploy / prod write';
+ if (/dns|domain|nameserver|cloudflare zone/.test(low)) gate = 'DNS / domain';
+ else if (/spend|budget|stripe|charge|payment|paid api/.test(low)) gate = 'spend';
+ else if (/send.*(email|sms|push|list)|mail.*(blast|send)/.test(low)) gate = 'send (comms-law — NEVER auto)';
+ else if (/dw_unified.*canonical|canonical.*dw_unified/.test(low)) gate = 'dw_unified canonical';
+ else if (/shopify|publish|live store|customer.?facing/.test(low)) gate = 'deploy / prod write';
+ // officer heuristic from slug/body
+ const officer = /commerce|shopify|gmc|merchant|catalog/.test(low) ? 'vp-dw-commerce'
+ : /marketing|instagram|tiktok|social|seo/.test(low) ? 'vp-dw-marketing'
+ : /engineer|code|build|deploy|server/.test(low) ? 'vp-engineering'
+ : 'unassigned';
+ // title: first H1 or first line
+ const h1 = (body || '').match(/^#\s+(.+)/m);
+ const title = h1 ? h1[1].replace(/\*+/g, '').trim() : slug;
+ return { slug, title, officer, state: 'PENDING', signoff: '—', dtd: '—', gate, reversible };
+}
+
function loadManifest() {
const m = JSON.parse(fs.readFileSync(MANIFEST, 'utf8'));
- return m.drafts.map((d) => {
+ const manifestSlugs = new Set(m.drafts.map((d) => d.slug));
+
+ // Dynamically detect files in pending-approval/ not yet in the manifest.
+ let extra = [];
+ try {
+ const files = fs.readdirSync(PENDING).filter((f) => f.endsWith('.md'));
+ for (const f of files) {
+ const slug = f.slice(0, -3); // strip .md
+ if (!manifestSlugs.has(slug)) {
+ let body = '';
+ try { body = fs.readFileSync(path.join(PENDING, f), 'utf8'); } catch (e) { /* ignore */ }
+ extra.push(autoClassify(slug, body));
+ }
+ }
+ } catch (e) { /* ignore */ }
+
+ return [...m.drafts, ...extra].map((d) => {
const item = { ...d };
// find the backing .md across queue folders (state may have changed)
const candidates = [
← 4781118 viewer: add reversible fast-track tray (Approve all N) + per
·
back to Approval Command Center
·
nav-agent: universal grid-controls drop-in on internal dashb a809adc →