Currently v1.0.60. ← Back to home
What's changed in the engine's user-visible output, in reverse chronological order. Pre-1.0 versioning convention:
0.x.0 — feature additions, output-shape changes0.x.Y — quality fixes, prompt refinements, copy updates1.0.0 — reserved for first paid Tier 1 customer signing a contractTwo independent external reviews of the same run reached the same verdict: the analysis was right but the reading order made practitioners dig for it. This release re-sequences both deliverables so the sharpest output is the first thing read. No analysis logic changed.
/analyze/simple and the
self-upload path call one shared field-builder — up to 5 topics across all six sources (Semantic
Scholar, arXiv, PubMed, OpenAlex, GitHub, Hugging Face). The upload path previously did a shallow
single-source search of at most 2 topics; it now matches manual depth by construction, so an
upload's Article + Technical Report carry the same field depth as a typed-topic run.qeb_encoding, cte_traversal, bridge_detection). Hypothesis IDs render as
Hypothesis N (not H01); contradiction rows read contradiction markers / contradiction
links (not C-lite / CONTRADICTS). Same data, readable copy.files list (was 3 named fields), files+topics
capped at 10.Both artifacts exposed the engine's internal pipeline (L1 → L2 → L3) as document structure — so mid-read a customer hit process narration ("What Changed (Layer 3: Autonomous Trajectory)," the Structural Deformation Manifest, "What Deepened From Your Layer 1") and reasonably wondered whether they were reading earlier-layer backstory instead of the deepest answer. Since runs are already single-pass full-depth, that layer-by-layer narration is the engine's bookkeeping, not the reader's decision. This release folds the depth in: the integrated full-depth read is the whole artifact; the layer information becomes provenance + inline durability, never a process section.
Article (report_generator.py):
- The mid-body "What Changed (Layer N)" section is removed from the findings flow. The deep-pass findings already live in their topical sections (the single-pass collapse computes every section on the final merged corpus), so nothing is lost.
- The Structural Deformation Manifest (what held / what the deepening exposed / what persisted) relocates to a new audit-appendix section, "Structural State of the Analysis," framed as provenance for the findings — same numbers, no mid-read interruption. (_structural_state_appendix)
- Per-finding durability stays inline (the "(persistent across layers)" gap tags).
Memo (decision_memo_synth.py): - The "What Deepened From Your Layer 1" section is gone, along with the "you already received a Layer 1 memo" framing (there is no separate earlier memo — it's one full-depth analysis). - The structural diff is reframed as robustness metadata: findings that held across the deepening read as high-confidence, findings that surfaced only on the deepest scan read as the newest/most time-sensitive — woven into the topical sections in a clause each, never as a process recap. Engine plumbing (counts of articles pulled, queries fired) is explicitly suppressed.
Article fold verified offline (section assembly + appendix relocation logic, zero API cost); the prose-level Memo fold manifests on the next generation.
External read of run 83a81d4c25e4 surfaced that the v1.0.35/v1.0.38 legibility passes ("findings lead, disclosure → appendix") had been applied to the Article generator only — decision_memo_synth.py (the Memo) never got the same treatment. This release finishes the pass and fixes five objective Article bugs found in the same read.
Memo legibility (decision_memo_synth.py) — the missing half: - Confidence floor surfaced up front. A one-line reading note now sits at the top of every memo (reads titles + abstracts, not full texts; findings are leads, strongest where signals converge). Previously the only statement of method limits was the Methods note at the very bottom, so a reader hit the ranked actions before knowing the conditions on them. Full Methods stays at the close. - "What Deepened from Layer 1" collapsed from 2–4 paragraphs of mechanism ("7 queries fired, 3 from prior-session memory…") to ONE decision-led paragraph; the how-the-engine-deepened plumbing is now at most a subordinate clause. - State-once-and-point anti-repetition rule promoted from the deepened-only preamble into the main system prompt: each load-bearing paper gets one canonical home (full argument once), referenced by short label everywhere else. Kills the "same three papers re-argued in nine framings" fatigue. "Untested Foundations" is now the designated canonical home.
Article bugs (report_generator.py + attribution.py + api.py):
- Patent footer drift — Article showed 10 patents + 5 apps, Memo showed 8 + 4. Canonical attribution.py updated to 10 + Cross-Engine Topological Dynamics (App. No. 64/061,710); all surfaces aligned.
- Mid-sentence truncation — the field briefing hit a 550-token cap and shipped a dangling clause ("…or whether it"). Raised to 800 + a sentence-boundary guard that trims any incomplete trailing sentence in every narrated section.
- # What's Missing markdown leak — a heading the model echoed into the "Why this matters" narration is now stripped.
- 10-vs-11 paper count — callout used the uncapped count while the list/synthesis used the top-10; capped to the shown set so every number agrees.
- Doubled "Untested Foundation" — a bold callout naming the pattern was immediately followed by an identical ### heading; redundant heading removed.
Pure-logic guards (truncation, markdown strip) unit-verified offline; the prose/structure changes manifest on the next generation.
Four sequencing/translation fixes from the external critique cycle. The principle: the engine already derives this — these changes surface what it found where a reader actually reads, without authoring conclusions the engine isn't entitled to make.
Refines how each generated hypothesis names its suggested approach, building on the domain-adaptive concept rules from v1.0.36. Two changes, both generic across every run (not tuned to any one corpus):
The engine's association-rule layer (which surfaces the load-bearing concept combinations a field's research shares) now adapts its vocabulary to each corpus. Previously it under-fired on technical/CS/engineering domains — the patterns and the method signal they feed into the generated hypotheses came back empty, and hypotheses fell back to a generic "mixed-methods" suggestion. The engine now surfaces the field's own concept relationships (e.g. policy ↔ reinforcement learning, cognitive architectures ↔ reasoning) regardless of domain, and the generated hypotheses name a specific, evidence-ranked approach instead of a generic placeholder. Diagnosed and fixed against a saved run (0 → ~80 informative concept rules); not a corpus-size effect.
Closes Revision Audit #19 (jargon QA) — and the detector immediately earned its keep by catching two genuine leaks, both now fixed at the root:
Event svw_005 / H04 identifiers, which the model then echoed into prose ("via hypothesis H04", "event svw_005"). The serializer now hands the model ordinals (Signal 1, Direction 1) — there's no internal ID to leak.scripts/check_artifacts.py). Plain-English prose and upper-case section headings don't false-positive.skip_reason; the boundary block already discloses honestly when no disputes were mapped.The Article was reading like a technical report — a structural inventory in the order the engine found things. It now opens the way the Patents Landscape does: orientation first, evidence second.
simple_ run-id prefix so downloaded artifacts no longer carry the word "simple." One memo per run under one canonical filename — which also fixes a download that 404'd because the only memo file was written with a _deep suffix the endpoints excluded.Borrows the legibility discipline of the systematic-review standard (PRISMA) without becoming a review tool — DCFN is the inverse instrument, but the discipline that makes review outputs trusted (show the narrowing, don't just state it) applies. Woven into the two artifacts, not bolted on as a third.
Closes the tail of the legibility work. (A standalone, partner-formatted provenance record remains a JDA-tier deliverable, specified at the DRA — not part of the standard artifact set.)
The biggest structural change to the run model. Z's principle: "the instrument fires at full depth by default, every time" — a shallow first pass you then pay to deepen is scaffolding, not design.
What changed for the user: clicking run now performs one single full-depth analysis — L1 baseline → L2 gap-research corpus expansion → L3 autonomous-trajectory exploration, internally, under one run id — and emits one Article + one Memo with the structural-deformation delta embedded as a section. There is no "Go Deeper" button, no "simple" vs "deep" split, no second artifact. The result is the engine's full current capability in a single pass.
Engine: new _run_full_depth_pipeline orchestrator chains the three stages as internal stages (reusing the existing gap-query / autonomous-query / search / diff primitives); intermediate stages run compute-only (emit_artifacts=False), only the final stage emits. A pre-emit hook attaches the L1→final diff before artifacts render — which also fixes a latent bug: in the old two-pass flow the diff was attached after the Article was generated, so the deep Article never actually showed its deformation manifest. It does now.
Removed (no dead code): the entire two-pass pathway — _run_layer2_pipeline, _run_layer3_pipeline, _run_deep_with_cleanup, the /deepen and Go-Deeper /checkout endpoints, the startup deep-run crash-recovery loop, and all the frontend Go-Deeper surface (button, goDeeper/triggerDeepen/pollForDeeper, the deep-reconnect IIFE — rewritten to a clean ?run= resume).
Naming: with one run per analysis the layer tag is gone — downloads are now {id} - {Article|Memo} - {domains}.{ext}.
Verified offline end-to-end (search + Claude mocked): all three stages execute, the manifest attaches, artifacts emit, status completes — no paid run fired.
Acts on the external DCFN Engine Critique (Gap Occupancy / Stack Leverage / Output Legibility, evaluated against v1.0.8 artifacts). The critique's own conclusion: "the next evolution is activation, not invention" — the engine computes more than the artifact shows, and the practitioner can't audit the gap between what it computes and what it reports. Seven changes close that gap. All verified offline against a saved run (no new corpus pulls).
Article
- Highest-Severity Gaps list. The "What's Missing" section printed only a gap count (e.g. "273 gaps"). It now leads with the top 5 gaps ranked by the engine's composite severity (impact + age + blockage), each with a plain-language "why it ranks." When the top gaps saturate the severity ceiling, the ordering falls to years-untested + blockage and the clustering is stated explicitly. The practitioner now sees which gaps are bottlenecks, not just how many exist.
- Mechanized "What the Engine Could Not See." Replaces the old static Limitations prose with a deterministic, run-flag-driven boundary block (epistemic_boundary.py): the contradiction-detection line flips on whether that pass actually ran it; full-text, patent-corpus, source-scope, and structure-not-quality boundaries are always present and complete. The disclosure is now an engine invariant, not something the writer might forget.
- Article→Memo cross-pointer. The Article names its companion Decision Memo (the action half) and frames itself as the structural-evidence half — phrased tier-accurately (the Memo is Tier 1).
Decision Memo
- Mechanized boundary section (shared). The "What the Engine Could Not See" section is no longer model-authored — it is appended deterministically from the same epistemic_boundary module, so both artifacts carry the identical, auditable boundary set. The model is told to skip it; a strip-and-append guard enforces it.
- IP-window urgency, quantified. Parallel-discovery signals carried qualitative timing ("the window is open now"). Each signal now computes an IP-window tier (TIGHT / NARROWING / OPEN / DIFFUSE) from the persisted convergence fields (independent-group count + convergence window) and the memo states timing grounded in that — no invented month counts.
- "What the Void Demands" — inward-edge section (new). The memo moves past whether to act to what a move must satisfy to occupy a gap: the outward edge (prior work a filling must move past), the inward edge (the structural tension a coherent filling must resolve), and the minimum-viable-thesis requirements — stated as requirements the gap imposes, not fabricated claims.
- Article→Memo correspondence (traceability). Every ranked action must trace to a specific finding in the engine data — a paper, convergence pair, or gap the Article surfaced — so each recommendation is auditable against its evidence.
Go Deeper - Structural Deformation Manifest. A Layer 2/3 deepening produced a replacement document; it now leads "What Changed" with a compact, classified delta — voids filled, residual voids exposed (an imperfect fill opens the next layer), persistent (structural) voids, topology consolidation/fragmentation, growth, and trajectory-confidence shift — computed from the existing structural diff. Framed in the layered-fill model.
Honesty note: where the critique pointed at patent mechanisms (cross-engine routing over a shared knowledge graph), this ships the honest single-session version (generated correspondence + manifest from real run data), not a simulated multi-engine exchange.
Ports the Patents output-honesty discipline that made it credible to external critics. #8 Overclaim reframe — the Decision Memo prompt framed SVW convergence as independent groups "landing on something true" / "emerging consensus." Reworded (section header + vocab map) to the honest read: the engine detects high textual/conceptual similarity with no citation link = a possible parallel-discovery signal worth following up, NOT confirmed truth. The prompt now explicitly forbids implying convergence confirms the claim. #9 Methods block — the website disclosed methodology but the downloaded .docx carried none; added attribution.write_docx_methods_block() with REAL params (Sentence-BERT all-MiniLM-L6-v2 384-dim; SBERT cosine thresholds 0.70 / 0.35-0.70 / 0.45 with TF-IDF fallbacks; titles+abstracts-only public-source corpus) sourced from concept_graph/qeb/config, not invented. #10 About-this-memo — write_docx_about_block() injects a "not scientific/investment/regulatory/legal advice, not expert-reviewed" callout into the memo body. Both render before the footer in decision_memo_synth. Verified: blocks render into a real .docx with the true model + thresholds present. (Deferred next pass: #11 CHANGELOG/PLATFORM split.)
Platform-layer change tracked here because Research has a single CHANGELOG (no separate PLATFORM_CHANGELOG). DCFN-Research now lives in its own GCP project (lef-ai-research) with its own Firestore (default), its own Secret Manager namespace, and a dedicated runtime service account. The cross-build leak surface that motivated the v0.5.14 private-beta email allowlist no longer exists.
What changed in code:
- attribution.BUILD_ID = "research" — single source of truth, read at runtime by auth_session._build_id().
- auth_session.sign_session() stamps a build claim into the HMAC payload; verify_session() rejects cookies whose stamp doesn't match this build (empty/legacy stamps still accepted for graceful migration).
- accounts.hash_password() / verify_password() now concatenate password with BCRYPT_PEPPER_RESEARCH (Secret Manager) before bcrypt. Verify falls back to plain-bcrypt when the env var is unset, so legacy rows keep working through the rollout.
- _is_email_allowed, _private_beta_active, _enforce_private_beta reduced to no-op stubs in api.py; DCFN_RESEARCH_ALLOWED_EMAILS is no longer read. Health-check informational block on the gate state removed.
- File headers in accounts.py and auth_session.py corrected: previously identified the module as DCFN-Patents (copy-paste artifact from when Research was forked).
What changed in infra (out-of-repo):
- lef-ai-research Firestore (us-east4, Native) created.
- Secrets duplicated into lef-ai-research Secret Manager: anthropic-api-key, stripe-secret-key, dcfn-session-secret (NEW value, distinct from prior lef-ai and from Patents), bcrypt-pepper-research (new), github-token, hf-token, dcfn-admin-key. Runtime SA dcfn-research-runner@lef-ai-research.iam.gserviceaccount.com granted secretmanager.secretAccessor on each + datastore.user on the project.
- Cloud Run service to be re-deployed into lef-ai-research with GOOGLE_CLOUD_PROJECT=lef-ai-research and the new secret bindings; DNS retargeting (research.livingedenframeworks.com → new service) is Z's manual step.
VERSION: 0.6.0-pre-i → 0.6.0-pre-j.
Engine-integrity audit (2026-05-07) flagged a HIGH finding: the landing
page, UI status messages ("Pulling papers from 6 sources…", "Pulling new
sources from 6 databases..."), and /privacy all promised six sources —
Semantic Scholar, arXiv, PubMed, OpenAlex, GitHub, Hugging Face — but
the customer-facing /analyze/simple path went through
_multi_source_search, which silently fanned out to only four. GitHub
and Hugging Face were excluded by an explicit comment on the grounds
that they return code / models, not papers, and needed specialized
queries.
Z's call: build the wiring properly rather than soften the copy.
ingestion_github.py and ingestion_huggingface.py already exposed
search_github_topic / search_huggingface_topic wrappers that map
repo + model / dataset records into the paper-shape the rest of the
pipeline expects (paperId, title, abstract, year,
citationCount, authors, references, citations, source_type),
with stars + downloads as citation proxies and README + model-card text
as abstracts. _multi_source_search now calls both, capped at 25
results each. Per-source failure isolation already covered the existing
four; the two new sources inherit the same try / log / continue pattern,
so a single source going down doesn't crash the run.
This same fan-out powers /analyze/simple (the customer-facing path),
the L2 deepening loop, and the L3 autonomous-ingestion loop. All three
call into _multi_source_search, so one change covers them all.
API-key handling: GITHUB_TOKEN and HF_TOKEN are optional. Both
modules degrade to unauthenticated public endpoints when the env vars
are missing — auth just buys rate-limit headroom.
Cross-build labeling standard signed off 2026-05-07. See
DCFN - Projects/NAMING_CONVENTION.md and Charter §5.
attribution.VERSION bumped 0.6.0-pre-d → 0.6.0-pre-e.report_generator.py: 5 ghost version = "0.3.0" / engine_version, "0.3.0"
fallbacks replaced with attribution.VERSION. import attribution added.
Self-naming inconsistency fixed: title page now reads
"Generated by DCFN-Research v{version}" (was: "the DCFN Engine"),
matching decision_memo_synth.py:752.report_generator.py:generate_article_docx() now routes through
attribution.write_docx_footer_block(doc, attribution.VERSION, ...) before
doc.save().publish.py:_markdown_to_docx() repeating page footer rewritten to carry
the full brand stack: NV License + Built-on line (4 patents) +
8 U.S. Patents Pending. End-of-doc routes through
attribution.write_docx_footer_block.publish.py:_drive_filename() produces the new grammar
{Type} L{layer} T{tier} {SOURCE} - Research - {Subject} - {short_id}.
SOURCE derived from the auto_ prefix on run_id (LOC vs PUB) — the
prefix is no longer stripped.publish.py:publish_bridge_digest + _publish_syntari_to_drive filenames
now follow the same grammar (Bridge Digest L3 T0 …,
Syntari Record L3 T0 …).Mirrors DCFN-Patents v0.13.78 pricing restructure. New section order: Across Every Tier (artifact identity cards) → Three tiers → Strategic Run / Engine Bridge. The 3 trust cards (corpus snapshot / 8 patent-pending / engine version) replaced with 3 artifact-identity cards: Research Article (Layer 1), Technical Report (Layer 1), R&D Intelligence Decision Memo (Layer 2). Section labels "Self-Serve & Subscription" and "Sales-Led Add-Ons" pulled. "What stays the same" H2 + section-lede pulled. Bottom Trust Strip removed (replaced by the top Across-Every-Tier section).
Captured as cross-build standard in DCFN-BUILD-CHARTER.md §5 (Page-shape standard → "Pricing-page section order").
attribution.py::VERSION bumped 0.6.0-pre-c → 0.6.0-pre-d.
Z walk-through 2026-05-07: when the user right-click → "Save as PDF" (or hits the Save-as-PDF button) on the Research result page, the browser captures everything visible — including the dark navy site footer with nav links, terms/privacy, version. That's the SaaS chrome around the engine output, not part of the artifact. The Patents output artifact, by contrast, ends in a clean centered attribution block (HR · "Generated by LEF/ DCFN - Patents · v… · LLC, DBA Co Creators" · "NV Business License #…" · Built-on line) — that's the artifact-style footer, no SaaS chrome.
This release brings Research's artifact flow to parity:
#tryResults. Centered; HR; "Generated by LEF/ DCFN - Research · v__VERSION__ · Living Eden Frameworks LLC, DBA Co Creators"; "NV Business License #NV20263528439"; the Built-on line listing the four directly-used patents + 8 U.S. Patents Pending. Mirrors attribution.write_html_footer_block from DCFN-Patents.@media print rule hides the SaaS chrome when the page is being printed/saved as PDF: nav, footer.site-footer, marketing sections, intake card, generating panel, action buttons (Download Decision Memo, Download Article, Save as PDF, Run Another, etc). Body background reset to white. #tryResults width-breakout reset to static so the saved page renders as a normal-flow document, not a viewport-width breakout.window.print()) and right-click → Save-as-PDF now produce the same output: NV License + brand block masthead + body content + canonical attribution block. Matches the Patents flow Z called out 2026-05-07.Captured as cross-build standard in DCFN-BUILD-CHARTER.md §5 (Page-shape standard → "Output artifact print mode").
attribution.py::VERSION bumped 0.6.0-pre-b → 0.6.0-pre-c.
Z walk-through 2026-05-07: Research L1 + L2 result pages were "embedded" — title strip + buttons clumped into a 700px column, reading as a small card stuck inside the intake section rather than a proper artifact-page header. Compare to Patents L1, where the header runs full viewport width with two-column title + brand block, and a generous body container (max 860px) with breathing room.
Rebuilt:
- Top thin strip (full width) — NV Business License #NV20263528439 · Built on the LEF Ai Engine · 8 U.S. Patents Pending (left-aligned, low-emphasis text). Was: missing the NV License # line entirely.
- Header (full width, two-column 1fr/1fr grid) — H1 + meta line (italicized, sources + snapshot) + date row on the left; LLC | DBA Co Creators + DCFN + URL on the right. Title is now H1 (not H2), display font, navy.
- Action row (full width inside header) — warning on the left, buttons on the right (Decision Memo / Article / Save as PDF). Border-top separator between brand block and action row, matching Patents.
- Body container — max-width: 860px centered with padding: 1.75rem 2rem 2rem for breathing room. Same content card inside.
- Width breakout — width: 100vw + position: relative + left: 50% + margin-left: -50vw lets #tryResults escape the parent intake section's 700px column without restructuring the section nesting.
- _populateArticleBanner() updated: date now goes to its own #articleDate row (matches Patents pattern), with a fallback to keep working if #articleDate isn't present.
Captured as cross-build standard in DCFN-BUILD-CHARTER.md §5 (Page-shape standard → "Result page artifact-header shape").
attribution.py::VERSION bumped 0.6.0-pre-a → 0.6.0-pre-b.
Z walk-through 2026-05-07: the L2/L3 "Go Deeper — Running" panel was a small dark embedded card on the result page (background #1a1a2e, gold accent), reading as a different visual language than the rest of the build and disconnected from the L1 generating page treatment. Rebuilt to match the L1 generating-page shape (centered ~640px card, navy heading, teal progress fill with shimmer animation, status text, warning subhead) plus a small layer badge so the L2 vs L3 distinction stays visible. Heading changed to "Going deeper into your analysis…".
Elapsed-time counter added to every generating surface across both builds:
- DCFN-Research L1 generating panel — new #elapsedText element in #tryStatus, ticked by setInterval from runAnalysis(), cleared on complete/failed.
- DCFN-Research L2/L3 deepen panel — uses the existing _deeperStartTime clock; rendered into the new card.
- DCFN-Patents L1 generating page (templates/generating.html) — new #elapsedText element under .status-text, ticker started at page load.
- DCFN-Patents L2 result page (templates/layer2_result.html) — #l2rElapsed span next to the "X of Y artifacts ready" label, ticker stopped on data.all_settled.
Captured as cross-build standards in DCFN-BUILD-CHARTER.md §5 (Page-shape standard → "Generating animation" + "Elapsed-time counter on every generating surface").
/download and /memo survive Cloud Run instance churnCloud Run is multi-instance and stateless. Pre-0.6.0, the pipeline worker wrote per-run artifacts (*_article.docx, *_technical.md, rd_intelligence_decision_memo.docx, articles.json) to local disk under data/reports/{run_id}/ on whichever Cloud Run instance ran the pipeline. A subsequent /download or /memo request that landed on a different instance hit report_dir.exists() == False and returned 404. The user paid for, or was owed, an artifact sitting on a sibling instance that may already have been recycled — same class of bug session_storage v0.5.28 closed for session state, but for paid deliverables.
This release introduces a ReportsStore abstraction, parallel to SessionStorage:
reports_storage.py (new) — abstract ReportsStorage base + LocalReportsStorage (current behavior, default) + GCSReportsStorage (Cloud Run prod) + init_reports_store() factory. Mirrors session_storage.py one-for-one: same shape, same envvar pattern, same Tier 2 fail-loud rule. Object layout: gs://{DCFN_REPORTS_BUCKET}/reports/{run_id}/{filename}.api.py — initializes _reports_store at module load. Pipeline post-batch (after generate_article + generate_technical_report + generate_rd_intelligence_memo for L1, after the deepened memo for L3) calls _reports_store.sync_run_dir_up(run_id, run_report_dir) to push the local-fs artifact dir into the backing store. Soft-fails so a sync hiccup doesn't fail the run.api.py artifact-serving routes — /analyze/simple/{run_id} (poll), /analyze/simple/{run_id}/download/memo, /analyze/simple/{run_id}/download, /reports/{run_id}/article, /reports/{run_id}/technical, and the /admin/republish/{run_id} diagnostic now read through _reports_store.read_artifact() / list_artifacts() / report_dir_exists(). FileResponse(path) swapped for Response(bytes) since the backend may return bytes that never touched local fs.api.py: _read_artifact_by_suffix() and _find_artifact_name_by_suffix(). Replace the prior report_dir.glob("*_decision_memo.docx")-style scans with backend-agnostic listing + suffix match.decision_memo_synth.generate_rd_intelligence_memo() and report_generator.generate_article_docx() still call doc.save(local_path) directly — least-invasive surface. The api-layer post-batch sync uploads what they wrote.init_reports_store() raises RuntimeError if DCFN_TIER=tier_2 and DCFN_REPORTS_BACKEND is anything other than gcs. Same rationale as session_storage v0.5.28: a customer-VPC deploy must keep paid artifact deliverables inside the customer's audit/retention boundary.data/reports/{run_id}.json (the run summary JSON sibling) is still local-fs-only — read by the rehydrate-on-startup loop and Layer 2/3 parent-load. That's the same class of multi-instance issue but a separate persistence concern; deferred to a follow-up. The _auto_publish call (Drive uploader) also reads from local fs — fine on the same-instance pipeline write path, but worth a follow-up audit.New env vars: DCFN_REPORTS_BACKEND (local default | gcs), DCFN_REPORTS_BUCKET, optional DCFN_REPORTS_SCRATCH. Bucket setup commands documented in reports_storage.py module docstring.
attribution.py::VERSION bumped 0.5.29 → 0.6.0-pre-a (suffix marks the artifact-persistence sweep as a pre-release; 0.6.0 proper lands once the top-level {run_id}.json and Drive-publisher reads are also routed through the abstraction).
ReportsStore parallel to SessionStorage. LocalReportsStorage keeps Render / local-Docker behavior; GCSReportsStorage makes paid deliverables instance-independent. Same Tier 2 fail-loud invariant on both.FileResponse(local_path) → Response(content=bytes, media_type=…, headers={"Content-Disposition": …}). The backend may return bytes that never touched local fs; FileResponse can't handle that.Z walk-through 2026-05-07: the loading-page H1 read "Your Article is generating…" — too shallow. Implies the build is an article-producer rather than a corpus-analysis engine. Aligned to the Patents framing — the engine's pass is named, not the artifact:
Captured as a cross-build standard in DCFN-BUILD-CHARTER.md §5 (Page-shape standard → "Generating-page voice"). Family rule: the H1 names the engine pass, not the artifact.
Second-pass Tier 2 hardening after v0.5.16's Path B Firestore fix. Closes four leak/noise/data-residency soft-spots flagged by the v0.5.15 telemetry audit (TIER2_TELEMETRY_AUDIT.md). None of these would crash a Tier 2 deploy; each one was a quiet path that could send tenant data the wrong direction.
_record_usage() (api.py) now no-ops loudly when DCFN_TIER=tier_2. The embedded Stripe account is LEF's Tier 0/1 billing surface; running Customer.search on a customer-VPC deploy would post tenant dcfn_key_hash values into LEF's Stripe metadata index./analyze/simple/{run_id}/checkout now returns 503 on Tier 2. Tier 2 customers handle Go Deeper billing through their contract; the embedded inline-price checkout is Tier 0/1 only. The /deepen route was already covered (Tier 2 hits the subscription-bypass branch).email_send.py redacts recipient address, subject, and the Resend HTTP error body when DCFN_TIER=tier_2. Resend echoes request bodies in error responses, so a 4xx on a corpus-derived send_sales_inquiry would dump PII into the customer's Cloud Logging. Generic exceptions log type only at Tier 2.init_session_store() (session_storage.py) now raises RuntimeError if DCFN_TIER=tier_2 and DCFN_SESSION_BACKEND is anything other than gcs. The previous default (local) would silently park session artifacts on the Cloud Run instance disk, outside the customer's audit/retention boundary._t2_scrub_query() helper in api.py. Wraps the user-input prints that funnel into Cloud Logging at Tier 2: ingestion search prints ([MULTI] Semantic Scholar, arXiv, PubMed, OpenAlex), simple-mode topic prints ([SIMPLE] Searching topic 1/2/3, Also searching), gap-quality / apriori query previews, and the rerank cluster-rep title swap. Tier 0/1 keeps the verbose form (logs are LEF-internal there)./deepen Tier 2 invariant — architectural fix, not a bandaid. Pre-0.5.28, Tier 2 was safe-by-side-effect on /deepen — it always tripped _is_subscription_user before reaching stripe.checkout.Session.retrieve. If tier_config.tier_2.include_go_deeper ever flipped, the silent guarantee disappeared. v0.5.28 lifts Tier 2 refusal to a first-class invariant at the top of the route: tier_config.is_tier_2() checked first, validated against the entitlement, and on success sets _tier_2_bypass=True so the route never reaches the Stripe branch. Any future Stripe-touching route ships with the same shape.attribution.py VERSION drift corrected. Pre-0.5.28, api.py owned its own VERSION literal and attribution.VERSION was stale at 0.5.1, contradicting attribution.py's docstring claim ("api.py reads VERSION from this module"). v0.5.28 aligns Research to the Patents pattern: attribution.py::VERSION = "0.5.28" is the single source of truth; api.py does from attribution import VERSION. Site footer + .docx footer + PDF footer all read from one place.is_tier_2() helper in tier_config.py is the canonical check; for modules that can't import tier_config without circulars (email_send.py), inline the env-var read.TIER2_TELEMETRY_AUDIT.md) is the substrate-universal scope check — every new DCFN-X build should ship a parallel audit before its first Tier 2 deploy.Z surfaced 2026-05-06 with side-by-side PDFs (Patents L1 top/mid/bottom + Research L1 results) and called for the Research result page to match Patents' document-shape layout. Plus he flagged confusion on the landing-page Tier 1 card — implicit framing made it sound like Memo was Layer 2 or 3 when it's actually Layer 1 (prescriptive).
#tryResults now mirrors Patents L1: top branded title strip with Built on the LEF Ai Engine attribution band → article title (#articleTitle) + meta line (#articleMeta: date · sources · snapshot) on the left + LEF/DCFN/research.livingedenframeworks.com brand on the right → second row with the ⚠ save-this-report warning + Save as PDF / Download Article / Download Decision Memo buttons → content card with the report body → bottom CTA strip with Continue to Go Deeper → (mirrors Patents Progress to Layer 2 →)._populateArticleBanner(data) helper — populates the title + meta from the run payload at every result-render site (initial completion, Stripe-redirect resume, dcfn_active_deep reconnect, pollForDeeper completion).reportContent injection paths — the title strip carries that warning now.#goDeeperPricingNote removed).#multiRunHint from results, moved to #multiRunHintIntake under the intake header — Z's earlier call: keep the hint visible at intake time, not after results render.api.VERSION bumped 0.5.26 → 0.5.27./changelog — wrap in shared nav + footer (was rendering bare)Z surfaced 2026-05-06: the changelog page was missing the shared header (nav) and footer. Patents /changelog extends base.html so it inherits both for free; Research /changelog was a standalone HTMLResponse from before the shared _render_nav / _render_footer helpers existed.
/changelog now wrapped via _auth_page(..., wide=True) — gets the same nav + footer treatment as /, /pricing, /terms, /privacy, /account./terms + /privacy formatting (Cinzel display h1 + uppercase teal sub + status line)..changelog-page styles scoped under .legal-page so the markdown rendering doesn't conflict with other legal pages.api.VERSION bumped 0.5.25 → 0.5.26./terms + /privacy rewrite — Patents formatting + comprehensive contentZ surfaced 2026-05-06: "the research terms does not match the patent terms. im almost afraid to look elsewhere." The v0.5.20 versions of both pages were 3-clause stubs styled with random inline CSS. Patents has full 13-section ToS + multi-section Privacy with consistent legal-page formatting.
.hero + .legal-page CSS to _AUTH_CSS (mirrors DCFN-Patents site.css rhythm — centered Cinzel display h1 + uppercase teal sub + last-updated line, then 1.3rem navy h2 sections, 0.98rem body, proper list indentation, legal-contact box, legal-crosslink at bottom)./terms rewritten to match Patents structure: 13 numbered sections covering what DCFN-Research is, who can use it, three-tier model, refunds, IP ownership + engine-improvement license, Section 6 Tier 2 isolation + FDA 21 CFR Part 11 posture (new — substrate-specific to Research-side), not-professional-advice clause, acceptable use, availability, liability cap, governing law, changes, contact./privacy rewritten to match Patents structure: 8 numbered sections covering what we store, what we don't, substrate-evolution feedback boundary, cookies, third-party processing (Anthropic / scientific data sources / Resend), user rights, changes, contact.api.VERSION bumped 0.5.24 → 0.5.25.Standardize what: text size, spacing, structural composition (hero block → numbered h2 sections → legal-contact box → legal-crosslink), and the section shape (what topics each build's ToS + Privacy must cover).
Do NOT standardize: font type, color palette, or any other per-build brand-identity choice. Each DCFN-X build keeps its own visual identity. The shared scaffolding is layout and rhythm, not visual treatment.
.hero block + .legal-page section pattern, h2 sizing (1.3rem) + spacing (2.2rem top), body 0.98rem + 1.65 line-height, list indentation, legal-contact box + legal-crosslink cross-reference./terms + /privacy shell fix — wide column (mirror v0.5.23 /account)Same bug as v0.5.23 but on the legal pages. Z surfaced 2026-05-06: "this issue is over all the research build." Document-style pages (terms, privacy) were being rendered inside the centered max-width 480px intake-card shell — content read as a tiny crammed block in the middle of the page instead of flowing as a document.
/terms calls _auth_page(..., wide=True) — flows in 720px main column./privacy calls _auth_page(..., wide=True) — same.api.VERSION bumped 0.5.23 → 0.5.24.intake-card. Card-shape genuinely helps focus the input./account shell fix — break out of intake-card (was clumped to 480px square)Z surfaced 2026-05-06: the v0.5.21 /account redesign updated the inner content correctly (no pill, no extra buttons, Discovery Run CTA, FIRM MEMBERSHIP panel) but was still rendered inside the intake-card shell — a centered max-width 480px container designed for sign-up / sign-in forms. Result: account-page content "clumped up into a small square in the middle of the page" with massive empty margins.
_auth_page() now accepts a wide=True kwarg that swaps the intake-card shell for a wider 720px centered section (mirrors Patents base.html main-column flow)./account calls _auth_page(..., wide=True) — content now flows in the wider column matching Patents' /account layout (PDF screenshot).intake-card — those genuinely benefit from the centered-form treatment.api.VERSION bumped 0.5.22 → 0.5.23.intake-card shell.Your Article is generating…)Z surfaced two screenshots side-by-side. Research's generating UI was a tiny gear + small "Searching..." text — minimal vertical footprint, footer sat way too high on the page. Patents' generating UI is a centered Cinzel display heading with breathing room. Cross-build standard.
#tryStatus redesigned to match Patents .status-card shape: max-width 640px, centered, 4rem top margin, 2.5rem 2rem padding, generous vertical breathing room.statusIcon (the small gear emoji). All three references guarded with if (el) checks for safety.api.VERSION bumped 0.5.21 → 0.5.22..status-card pattern from Patents' site.css (centered, max-width 640px, Cinzel display heading + warning line + thicker progress bar + rotating status text below)./account redesign — mirror Patents layout (no pills, no filled colors except run button)Z's walk surfaced multiple issues on the Research /account page (especially for added firm-pool members): tier-pill the user disliked, redundant "Pricing" + "Back to engine" buttons, no "Start a Discovery run" CTA, no FIRM MEMBERSHIP panel for firm-pool members. Z's standing principle: pills + filled colors are reserved for run buttons and pricing-page buttons, NOT for tier badges or auxiliary nav.
TIER N pill. Plan now renders as plain text "Tier 1 · Pro Subscription" / "Tier 1 · Firm Pool member" etc.Log out is now a plain text link, not a filled button.Start a Discovery run → button — matches Patents' Start a portfolio run → placement and styling. Centered, generous gap above and below.edit toggle (mirrors Patents v0.13.19 pattern). New POST /account/display-name route.signed in as <email> sub-line under the display-name h2 (was a kv row).api.VERSION bumped 0.5.20 → 0.5.21.Account label / display-name h2 with edit / signed in as <email> / plan label / centered run button / FIRM MEMBERSHIP panel (if firm-pool) / plain Log out link. Standard for all DCFN-X builds.Z's walk surfaced the broken /terms link (returned raw JSON) + missing Privacy link + duplicated copyright text in the footer.
© 2026 Living Eden Frameworks LLC · DBA Co Creators (was Living Eden Frameworks LLC · DBA Co Creators — missing the ©).© 2026 Living Eden Frameworks LLC text. Now just Terms · Privacy · v{VERSION} →.Privacy link added to the footer (was missing entirely)./terms returns HTML now (browser-facing Terms of Service page, mirrors the auth-page shell). The previous JSON shape moved to /api/terms for any external API client still expecting it./privacy route added — sister to /terms. Covers what we store, the Tier 1/2 isolation guarantee, substrate-evolution feedback boundary, cookies, contact./admin/smoke updated to expect /privacy in the route registration check.api.VERSION bumped 0.5.19 → 0.5.20.Four changes Z surfaced as substrate-universal standards. Mirrored on Patents in v0.13.66.
License DCFN → is now a plain link (no border). Was a .nav-cta button-style; cleaner as inline text./contact-sales with multi-select inquiry checkboxes. Was: each ?inquiry=tier_2 etc. landed on a separate-feeling page with a single inquiry label. Now: ONE form with checkboxes for Tier 2, Strategic Run, Engine Bridge, Licensing, etc. User can select / deselect freely; pre-checked when arriving via /pricing CTA. Selected topics flow into the email body as a bulleted list under "Topics selected:" so sales sees the full set.api.VERSION bumped 0.5.18 → 0.5.19.All four changes apply substrate-universally. Future DCFN-X builds inherit these patterns via the BuildMe template: - Nav-cta border off (default to plain link) - Pricing subtitle = sample-output bridge, not tier-restating prose - Multi-select unified contact-sales - No "Licensing Guide Bridge" section on /pricing (the guide is already public; gatekeeping it via /contact-sales is anti-pattern)
Z walked the signed-in landing page and surfaced four cuts on noisy / redundant copy.
#intakeIntro hidden for signed-in users. "TRY IT" section-label + "What connections do you want to find?" h2 + lede paragraph all gone for authenticated users — they're already on the engine page using it. Anonymous tier_0 visitors still see the intro as part of the marketing flow.#signed-in-welcome. The "Welcome back, {name}" h1 is enough; the explainer was redundant for returning subscribers.Tier 2 secondary cleanup is now v0.5.19 (was v0.5.17 → v0.5.18 → now v0.5.19 after this slot ate the version).
Z surfaced 2026-05-06 with a screenshot: when a signed-in user runs an analysis and results render, the page still showed the "SIGNED IN / Welcome back" banner + "TRY IT / What connections..." section header + lede paragraph stacked above the result card. Same root cause Patents already fixed: the form-hide was per-element (#tryForm only), so the section preamble + welcome banner stayed visible above the result.
#intakeIntro div — section-label, h2, and lede paragraph now share a single container the JS can toggle._hideIntakePreamble() / _showIntakePreamble() helpers — called everywhere #tryForm toggles. Hides BOTH the intake intro AND the signed-in welcome banner during runs / results display. Reset path restores both.api.VERSION bumped 0.5.16 → 0.5.17.(NOTE: previous "v0.5.17 secondary cleanup" Tier 2 work is now renumbered to v0.5.18.)
Closes the three "must-fix" findings from the v0.5.15 Tier 2 telemetry audit. Tier 2 deployments (single-tenant customer VPC, $185K/yr) ship with architectural telemetry isolation — not policy promises. Pharma/biotech procurement compliance (FDA 21 CFR Part 11) accepts structural isolation; they will not accept a pinky-swear policy.
tier_config.is_tier_2() helper added — substrate-universal. Reads DCFN_TIER env var, returns True iff equals tier_2. Used everywhere the codebase needs to gate telemetry paths.accounts._client() now validates GOOGLE_CLOUD_PROJECT is set at Tier 2. Fails loud at first call with an explicit RuntimeError if missing — no silent fallback to LEF's default ADC project. Customer must point at their own GCP project on the Tier 2 Docker image. This is what makes user-attributed audit trails per FDA 21 CFR Part 11 work without telemetry leak: Firestore queries run, but they hit the customer's database, not LEF's.publish.auto_publish() defaults to disabled at Tier 2. Customer can opt in by setting DCFN_TIER_2_PUBLISH_DRIVE=1 AND providing their own GDRIVE_REPORTS_FOLDER_ID etc. — folder IDs then point at customer's Drive, not LEF's.startup_event no longer attempts Drive sync when DCFN_TIER=tier_2. Local-only calibration state./admin/smoke Tier 2 self-check now verifies BOTH (1) required env vars are set (GOOGLE_CLOUD_PROJECT) AND (2) forbidden LEF telemetry env vars are NOT set, with DCFN_TIER_2_PUBLISH_DRIVE=1 correctly skipping the GDRIVE_* checks when customer has opted in to customer-side Drive publish.api.VERSION bumped 0.5.15 → 0.5.16.is_tier_2() is substrate-universal — Patents will mirror in v0.13.65. Future DCFN-X builds inherit the helper from the BuildMe template + the Path B Firestore pattern.Closes the BuildMe §5.9 failure mode — deploys looking clean to me but Z walking them and finding a broken route or stale UI. Pre-deploy parse-checks catch syntax errors; this catches runtime + config drift.
GET /admin/smoke — admin-key-gated. Returns JSON with: VERSION + revision identifiers, route-registration sanity, subsystem availability flags (accounts, Stripe), required env-var presence (ANTHROPIC_API_KEY, DCFN_SESSION_SECRET), private-beta gate state, tier-resolution sanity, Firestore client init probe, and a Tier 2 self-check that fires only when DCFN_TIER=tier_2 (verifies forbidden LEF telemetry env vars are not set).x-admin-key header or ?admin_key= query param matching DCFN_ADMIN_KEY. Returns 503 if env unset, 403 if mismatch.summary.ok boolean. CI / manual deploy verification can grep "ok": true.api.VERSION bumped 0.5.14 → 0.5.15./admin/smoke so the operator-side verification loop is in place from day one, not retrofit after the first BuildMe §5.9 incident.Pre-launch lockdown: when DCFN_RESEARCH_ALLOWED_EMAILS env var is set, anonymous Tier 0 free runs are blocked and signed-in users whose email is not on the allowlist are blocked. Same posture Patents has shipped since v0.13.29.
_enforce_private_beta(request) route guard added on /analyze/simple, /analyze/simple/upload, /analyze/simple/{run_id}/checkout, and /analyze/simple/{run_id}/deepen. Anonymous = blocked. Signed-in non-allowlisted = blocked. Signed-in allowlisted = pass through./. Same UX as Patents.api.VERSION bumped 0.5.13 → 0.5.14.Z walked v0.5.12 and surfaced five user-broken behaviors. All five fixed in this push.
/checkout always created a $15 Stripe session even for tier_1+ users whose subscription bundles Go Deeper. v0.5.6 had left a "next phase" comment for this; the auth flow that phase was waiting for shipped in v0.5.11. Now: /checkout returns {auto_deepen: true} for tier_1+ users; frontend honors that by calling /deepen directly without the Stripe round-trip. /deepen payment gate also adds a parallel subscription bypass as defense in depth.auth_session.py's dev-fallback secret regenerates every Cloud Run revision, so all session cookies invalidate on each deploy. Fix is operational — bound DCFN_SESSION_SECRET to the existing dcfn-session-secret Secret Manager entry on both dcfn-research and dcfn-patents Cloud Run services. Sessions now persist across deploys. (Latent bug on Patents too — bound there as well.)/, and saw Tab B's running deep analysis because dcfn_active_deep lived in localStorage (origin-wide). Switched to sessionStorage (per-tab) so each tab tracks only its own active deep run. The cross-tab override of window._currentRunId is now scoped correctly.window.DCFN_TIER: Tier 0 sees the upgrade hint, Tier 1 sees "Article + Decision Memo + Go Deeper bundled," Tier 2 sees "unlimited at maximum corpus depth."api.VERSION bumped 0.5.12 → 0.5.13.DCFN_SESSION_SECRET to a Secret Manager entry, not rely on the in-process dev fallback. Sibling to BuildMe §5.12 (env-var propagation).sessionStorage, not localStorage. The "survive a refresh" intent is a sessionStorage use case; localStorage's cross-tab leakage is a feature only when state is genuinely user-wide (preferences, theme, etc.).Z walked the v0.5.11 surface and surfaced the visual delta: Research had per-page nav blocks (different on /, /pricing, the auth pages), a footer that varied between pages, sign-in pages that didn't match Patents' intake-wrap styling, and bottom-of-landing tier cards that still read "Free 5/month" + "$15 per run" — pre-flip framing that contradicted the v0.5.10 pricing page.
_render_nav / _render_footer). Single source of truth for the header (brand · "by Living Eden Frameworks LLC" | Sign in or display name → /account · Pricing · License DCFN →) and the footer (tagline, LLC + DBA, Terms · v0.5.12 → · "Built on the LEF Ai Engine — …" patent attribution). Mirrors Patents' base.html composition; injected as inline-HTML helpers because Research hasn't moved to a templates/ tree yet (separate phase)./signup, /login, /account, /forgot, /reset, /contact-sales now render inside the shared nav + intake-wrap + shared footer composition. Patents-style section-label ("Account access") + Cinzel-display heading + teal CTA button, replacing the v0.5.11 standalone-card shell./, the marketing sections (hero, data sources, "What You Get" tier cards) hide via body[data-signed-in="1"] and a "Welcome back, {name}" banner appears above the engine intake. Mirrors Patents' is_active_run pattern from index.html — "Back to engine" lands on a clean engine-only view, not the full marketing page./analyze/simple/upload) was correct, the label was borrowed from Patents (where users upload provisional drafts to refine). Research users upload source papers/PDFs to enrich the analyzed corpus — that's what the relabel says now.api.VERSION bumped 0.5.11 → 0.5.12.Research now ships the same account/auth flow Patents has been running on since v0.11.0 — Firestore-backed signup, JWT session cookie, password reset via Resend, and a /contact-sales handler for Tier 2 / Strategic Run / Engine Bridge / institutional licensing inquiries. This closes the gap between the v0.5.10 pricing page (which already linked to /signup, /login, /contact-sales) and the actual routes — those links pointed at ghost endpoints until now.
GET/POST /signup, GET/POST /login, POST /logout, GET /account, GET/POST /forgot, GET/POST /reset, GET/POST /contact-sales. All inline-HTML responses (matching Research's existing template-less rendering pattern); a separate phase will extract these to a templates/ tree._resolve_user_tier). Replaces the env-only tier_config.resolve_tier() for the user-facing paths: /, /download/memo, /checkout, /deepen. Resolution order — active subscription / firm membership → JWT cookie tier → env-var fallback. Background pipelines now accept an optional user_tier kwarg captured at request time, so a Tier 1 user kicking off /analyze/simple actually generates the Decision Memo even when DCFN_TIER is unset on the Cloud Run service.email_send.py). Welcome email on signup, password reset link on /forgot, sales-inquiry forwarding on /contact-sales. No-ops if RESEND_API_KEY is unset (local dev / batch runs).DCFN_RESEARCH_ALLOWED_EMAILS env var (comma-separated emails). Unset → open signup. Mirrors Patents' DCFN_PATENTS_ALLOWED_EMAILS pattern.api.VERSION bumped 0.5.10 → 0.5.11.accounts.py has the helpers, route wiring deferred until Tier 1 firm-pool customer #1.Replaced the JSON /pricing stub with a full HTML pricing page covering Tier 0 (free Article), Tier 1 per-seat ($7K/yr), Tier 1 firm-pool ($30K/yr), Tier 2 private VPC ($185K/yr), Strategic Run ($10K+/engagement), Engine Bridge ($60K+/pairing/yr), and the LEF Licensing Guide bridge. Same structure as the Patents pricing page; numbers locked 2026-05-06.
Up to v0.4.x, every Research output was descriptive: Article, Tech Report, Bridge Digest, Syntari Record, JSON. All four external instances (Perplexity, Grok, Gemini Deep Research ×2) independently identified the same gap on review — these are excellent analysis packages, but they are not artifacts a customer can FUND, FILE, or ACT ON immediately. DCFN-Patents earned its category by shipping deliverables (provisional drafts, continuation memos) that decision-makers could take directly into a meeting. Research had nothing of equivalent shape.
v0.5.0 ships the first one: an R&D Intelligence Decision Memo, a 2-3 page persona-targeted prescriptive deliverable produced from any successful engine run. Generated alongside the Article and Tech Report — additive, not a replacement. Audience for this prototype is narrow on purpose: pharma R&D directors, biotech corp-dev leads, deep-tech VC desks, and corporate R&D portfolio heads who allocate $1M-$50M on R&D bets. Same operational pattern as Patents' attorney audience (high-LTV, willing to pay $4-20K/seat for a tool that materially affects large decisions). Other personas (Replication, Funder, Licensee) are deferred — one persona ships first to validate willingness-to-pay before forking the synthesis pipeline.
decision_memo_synth.py. Mirrors continuation_memo_synth.py from DCFN-Patents: read engine session JSON, single Claude Opus 4.7 call with persona-aware system prompt, render a .docx with the centralized attribution footer. Public entry point generate_rd_intelligence_memo(session_dir, claude_client, anthropic_model). Persona spec (PersonaSpec dataclass + PERSONAS registry) is centralized so future personas register a new spec instead of forking the module. Cost: ~$0.10-$0.20 per memo (Claude Opus 4.7, ~5K in / ~3K out typical).attribution.py extended. New write_docx_footer_block(doc, version, *, include_attorney_disclaimer=False) — single source of truth for end-of-body attribution on Research .docx outputs, mirroring DCFN-Patents convention. Soft-fails on missing logo (Research repo currently ships without a static/lef-dba-logo.png asset; the footer renders cleanly without it, picks it up automatically when one lands).api.py and main.py call generate_rd_intelligence_memo() after Article + Tech Report on every successful run, in a try/except so any synth failure (Claude outage, missing key, render error) leaves the existing artifacts intact.api.VERSION bumped 0.4.0 → 0.5.0. Feature addition / output-shape change → minor bump per pre-1.0 versioning convention. attribution.VERSION synced.Generated against data/reports/run_c66198828e46/ (Education & EdTech, 687 articles). Memo correctly cited specific entropy nodes by title + year + severity, named SVW convergence events (svw_002, svw_022, svw_023) with paper titles and scores, surfaced apriori rules with confidence numbers, and honestly flagged the absence of contradiction-resolution data + lack of bridge nodes as engine-input limitations rather than burying them.
Mirrors DCFN-Patents v0.8.0 → v0.9.0 → v0.6.0 playbook validated 2026-05-01. Lays the groundwork for Render → Cloud Run cutover without changing any user-facing behavior on the live Render service. Phase 3 of the migration plan documented at Needs Review/Pricing + Architecture Decisions/RESEARCH_MIGRATION_PLAN_2026-05-02.md.
Dockerfile base swap. python:3.11-slim → pytorch/pytorch:2.4.0-cuda12.1-cudnn9-runtime. SentenceTransformer auto-detects torch.cuda.is_available() and uses GPU when present (Cloud Run with --gpu=1 --gpu-type=nvidia-l4 gets ~50-100x speedup on SBERT-heavy steps); falls back to CPU transparently when no GPU is attached. COPY . . instead of COPY *.py . so new modules + future static//templates/ dirs land automatically.session_storage.py. LocalSessionStorage / GCSSessionStorage adapter behind a single session_store singleton. Backend selected via DCFN_SESSION_BACKEND={local,gcs}; gcs requires DCFN_SESSION_BUCKET. Defaults to local (no production behavior change). Cloud Run will set DCFN_SESSION_BACKEND=gcs DCFN_SESSION_BUCKET=lef-ai-dcfn-research-sessions.tier_config.py. Per-tier engine knob overrides (Tier 0 / 1 / 2). Tier 0 caps match current Render production exactly. Resolution: DCFN_TIER env → session_state["tier"] → dcfn_tier cookie → fallback tier_0. Pricing strings deliberately NOT in this module — those land in a later phase gated on Z's pricing decision per migration plan §5.attribution.py. Single source of truth for footer attribution: BUILD_NAME, VERSION, LLC_NAME, LLC_DBA, NV_BUSINESS_LICENSE, PATENT_ATTRIBUTIONS, plus render functions. Patent attribution list matches v0.3.11 site footer copy exactly — refactor, not a content change. Cross-build attribution rule (Z 2026-04-30) noted in module docstring.requirements.txt. Added google-cloud-storage>=2.14.0 for GCSSessionStorage (lazy import; LocalSessionStorage doesn't depend on it).attribution.py, tier_config.py, and session_storage.py exist but no module imports them. Wiring in subsequent v0.4.x commits.compute_portfolio_topic.py (mirror of Patents' compute_portfolio_domain.py for Drive filename topic labels) — deferred to publish.py call-site migration.accounts.py / auth_session.py / usage_tracker.py — deferred to migration plan Phase 5-6.dcfn-research.onrender.com → research.livingedenframeworks.com.docx, "Go Deeper" markdown link, deployment site references) carried the legacy Render URL. Replaced across api.py (DCFN_BASE_URL default), report_generator.py (3 callsites: Go Deeper link + 2 footer references), and publish.py (2 footer references).research.livingedenframeworks.com not yet pointed at the new substrate — that lands as part of the Cloud Run migration (RESEARCH_MIGRATION_PLAN_2026-05-02). Customers visiting the URL today still hit Squarespace's NX. Output text now reflects the planned canonical brand URL ahead of the cutover (mirrors Patents v0.9.1 sequencing).report_generator.py:7507 (matches an even-older lef-dcfn.onrender.com pattern from the pre-rename era) intentionally untouched — it works as designed for stripping cached old markdown.v0.3.5's bidirectional citation walk shipped assuming all reference IDs were Semantic Scholar paperIds (40-char hex). In practice the merged corpus pulls from 4-6 sources and references[] is mixed-format: OpenAlex Work IDs, PubMed UIDs, arXiv IDs. v0.3.8's S2-only filter prevented the resulting 400-Bad-Request crash but at the cost of ~zero expansion on multi-source corpora (one local test: 749 non-S2 IDs filtered, 0 added).
v0.3.10 closes the gap with a hybrid two-pass design:
/works, PubMed esummary). Reformat as S2's DOI:10.x prefix syntax and send through the existing S2 batch endpoint. Captures the ~75-85% of academic papers that have DOIs./works?filter=ids.openalex:, PubMed efetch, arXiv query?id_list=. Reuses parsing logic from existing ingestion_* modules so the article record shape is identical to the standard pipeline.Graceful degradation: if S2 batch returns 429 (free-tier rate limit, common) or any other error, the IDs that came in via DOI translation get re-attempted via per-source fetch. So the entire walk doesn't depend on S2 cooperating.
Metadata richness: expand_via_citation_walk return dict now includes ids_resolved_via_s2_native, ids_resolved_via_doi_translation, ids_resolved_via_per_source, ids_unresolved, per_source_breakdown. Operator (and Z reading the report) can see exactly where each neighbor came from and which sources contributed.
Empirical validation (local Single-Cell corpus, 100 OpenAlex neighbors, S2 rate-limited): 25 articles added in 8.6s via Pass 2 OpenAlex fallback alone. With production S2 API key cooperating, Pass 1 + Pass 2 combined would land substantially more.
New module id_translation.py centralizes paper-ID source recognition + DOI prefix formatting so downstream code doesn't sprinkle prefix-matching logic.
Coverage note: papers without abstracts are filtered by the standard _to_article_record schema requirement. Tier 1+ engine variant will handle abstract-less papers via structural-metadata-only ingest path (separate ship).
main.py's user-driven path already had per-stage timing via stage_timings. The autonomous-scheduler path (scheduler.py:_run_autonomous_pipeline) was missing it — only total elapsed was logged. Added per-stage capture for: qeb_encoding, concept_graph, cte_traversal, apriori, svw, hypothesis_generation, calibration, bridge_detection_and_rerank. Surfaces as a single [PIPELINE_TIMING] log line per run + persisted to the report's stage_timings field for downstream tooling.
Triggered by Charter §16 codification (Patents L1 ran 50 min and we had no per-step data to answer "should we upgrade Render tier?"). This closes the gap on the Research autonomous path so the same question is answerable empirically there too.
Note: the multi-source citation walk hybrid (DOI translation + per-source fanout) flagged in v0.3.8 is now tracked as v0.3.10 (next minor).
Local Research validation surfaced two bugs in code I shipped earlier today.
Numpy truthiness crash (blocking). The topical-coherence term I added in v0.3.7 used d.get("v_unit") or d.get("v_seed") to pick a vector — classic Python+numpy gotcha: when v_unit is a numpy array, the or operator triggers numpy's __bool__, which raises ValueError: The truth value of an array with more than one element is ambiguous. Two sites in cte_operations.py:golden_token_pathfinding. Both now use explicit None-checks. Effect: every autonomous run since v0.3.7 deployed (2026-04-30) crashed silently after the CTE ops stage. The v0.3.5–v0.3.7 quality fixes never actually produced a usable report. Local re-validation post-fix: 4 succeeded, 0 failed (was 0/4).
Citation-walk batch endpoint rejecting all requests (silent). v0.3.5's bidirectional citation walk was sending paper IDs to Semantic Scholar's /paper/batch endpoint that the endpoint refused with {"error":"No valid paper ids given"}. Cause: in the multi-source merged corpus, references[] contains IDs in mixed formats (S2 hex, openalex:WXX, pmid:NNN, arxiv:XX.XX). S2's batch endpoint only accepts S2 hex IDs (or its own prefix-tagged syntax which we don't yet emit). Fix: filter neighbor IDs to S2-format (40-char hex) before batching; non-S2 IDs are dropped with a logged count. Also added 4xx response-body capture so future S2 errors show the actual error message on the first round-trip instead of an opaque 400 Bad Request.
S2 ID filter is a safety net, not the production architecture. Multi-source corpora (OpenAlex, PubMed dominated) require cross-source ID resolution. Hybrid two-pass implementation lands in v0.3.10 (DOI translation + per-source fanout).
Follow-on work tracked separately for v0.3.9: translate non-S2 IDs to S2's prefix syntax (DOI:10.x, PMID:NNN) before batching, OR fan out per-source (OpenAlex API for openalex: IDs, PubMed E-utilities for pmid: IDs). Not a v0.3.8 ship — needs design.
Two coupled fixes for Perplexity's 2026-04-30 broad-vocabulary findings.
source_title lookup. Hypotheses now resolve to specific paper titles ("will unlock currently blocked progress toward: fields_of_study intersect the corpus's dominant fields (≥30% of DOCUMENT nodes). Methodology papers typically declare different fields (Computer Science, Bioinformatics) than the substantive research papers (Biology, Medicine), so the centroid stays anchored to subject matter, not tooling. The other four PATHFINDING_WEIGHTS dropped uniformly (0.25 → 0.2125) so the new mass doesn't compound.session_corpus_pull.py. Discovery-driven topic runs (queue-managed via topic_queue_runtime) now expand the corpus with a 1-hop citation-graph walk after multi-source ingest completes. Takes the top 50 most-cited papers from the initial pull, collects both their references (backward — ancestral foundations) and citations (forward — downstream sub-communities), batch-fetches the metadata via Semantic Scholar's /paper/batch endpoint, dedupes against the existing corpus, and appends. Hard-capped at 400 net new neighbor IDs per run to bound API cost + wall-clock; typical add lands at 100-300 articles in 30-60 seconds.pending_items.md proposals into topic_queue.json and registered into DOMAINS at runtime). Fixed-config domains have curated query sets and skip this step. Failure modes are non-fatal — on any S2 error the run continues with the unexpanded corpus.Corpus fingerprint: no-corpus even though the run ingested 542 sources. Root cause: in the autonomous-scheduler code path, the article_index was being built AFTER the report was rendered, so the report's fingerprint check (report.get("article_index", {})) saw an empty dict and emitted "no-corpus" regardless of how many articles ingested. Fix: build article_index and assign it into the report dict BEFORE generate_article / generate_technical_report run. Receipts now show the real corpus signature. Note: this is the surface-symptom fix; the deeper architectural item (citation-graph 1-hop expansion to address flat-cluster structure on broad-vocabulary domains) is tracked separately and is multi-day work._detect_tooling_obi_signals() runs between citation-velocity and the hidden-citation bigram check. Two-layer detector: a STRONG signal (a single GitHub URL, "R package" / "Python package" / Bioconductor / CRAN / PyPI mention, or "available at https://" link) is sufficient on its own; a WEAK signal (generic terms like "framework", "library", "implementation") only fires when co-occurring with a package-name pattern in the title (all-caps acronym like HTSeq/BLAST, or CamelCase like DESeq2/uniCATE). Designed for precision — generic prose like "in our framework we propose..." won't trip it.Footer's "Built on" line was undercounting: said "6 U.S. Patents Pending" and named CTE + QECO. Actual total since the Tesseract Composition supplemental landed (2026-04-20) is 8, and the engine rides more than two substrate patents. Updated to:
Same correction applied to the Firebase brand site's DCFN-Research card.
The Research engine's autonomous-run path now drives from a discovery-agent-fed queue instead of cycling fixed domains. A discovery agent identifies new research topics worth running by querying Semantic Scholar (with PubMed fallback) for substantive recent activity in curated seed areas, derives a topic configuration from the top results, and proposes it for human review. After a 7-day cooldown without rejection, the proposal auto-promotes into the live run queue, where the engine executes the full pipeline against it once or twice before going dormant.
Why this matters: it converts the autonomous path from "run the same three domains every day" (which produces noise) into "surface new research territory worth exploring" (which produces signal). Each run feeds the Bridge Inbox + LEF Ai Engine Upstream telemetry channels — autonomous runs are the substrate's input.
Solved Obliteration by Incorporation (OBI) — flagged by Gemini 2026-04-30 deep-research review of the v0.2 era output. Previously the engine was treating universally-adopted methods as "decayed" simply because they'd stopped being explicitly cited (their methods became the field's default vocabulary). The engine now distinguishes "Canonical Foundations (Absorbed by Incorporation)" from genuinely abandoned work. Concrete validation from Gemini: the engine correctly identifies the HTSeq Python framework — "22,482 lifetime citations but 0 in the last 5 years; hasn't decayed; it has just become structural canon" — instead of false-flagging it. This removes a major false-positive class from the engine's untested-foundation analysis.
High-signal convergence anchor detection — the engine surfaces single papers that multiple research clusters orbit without explicitly cross-citing. Gemini 2026-04-30 validated on the Trauma-Informed Care × Restorative Justice run: "353 independent research groups across 42 years converging on the exact same academic success metrics without sharing a direct citation path." Convergence anchors are the engine's strongest signal for "where the field is heading without anyone having named it yet."
Bridge digest format — autonomous runs now produce a structured Bridge Digest containing all bridge intelligence (gaps, severity, gap types, abstracts) suitable for ingestion by future Bridge engines that sit between two DCFN builds.
Syntari Record (JSON twin) — every run now produces a structured JSON twin alongside the prose Article, suitable for downstream machine-readable consumption.
Initial deployment. Single-page intake → multi-source ingest → concept graph construction with typed edges → Cognitive Traversal Engine (5 operations: backward / forward / branch cataloging / entropy / golden token) → SVW convergence detection → Apriori pattern mining → Article + Technical Report generation. Free 5 runs / month / browser; $15 unlock for Layer 2 + Layer 3 deeper traversal.