/p/products-convergence-verdict
Products convergence council verdict
Council verdict captured from the products-convergence artifact and published through Packet CLI.
Convergence Council — Verdict (2026-06-30)
I have both grounding documents and the four council proposals. Let me note one structural fact: the JSON contains three proposals (not four), with stances B-staged-hybrid, A-now-B-earned, and A-sequenced-with-rider. All three converge on rejecting C, ratifying packet-as-host, keris-separate-but-share-substrate, and inverting the schema center to notes' quintet. The real disagreement is the extraction tempo: how much L1 work happens before vs. after the merge. That is what I must adjudicate.
Let me reconcile decisively.
VERDICT — products convergence (press · packet · notes · keris)
1. THE RECOMMENDATION
ARCH-A-sequenced — "ratify the locked §D4 decision, ship the merge, and extract exactly ONE L1 package (@creative-int/press-render) along the way." The June §D4 decision survives contact with the real schemas and should be ratified and executed, not revisited: packet is the host app, notes+press fold in, keris stays a separate product that shares substrate (option-b: share press-render + sources, do not generalize its team-scoped evidence engine yet, do not make it the host). This wins over pure ARCH-B because B converts a parked, fully-specified port into an open-ended substrate-extraction program before a single notes doc lands in packet — and the schemas prove a generalized context-packet L1 table today would be a string-keyed lowest-common-denominator that strips keris's v.id("teams") referential integrity for zero benefit at 0→1 consumers. It wins over ARCH-C decisively: keris-as-host instantiates the literal product-coupling.md anti-pattern ("consumer product as spine"), drags 8,787 lines of videoPipeline.ts gravity into notes/curate, and reopens exactly the template-drift keris's own AGENTS.md fought to close — the keris audit's own recommendation (extract-evidence-first) is ARCH-B wearing a keris hat, not C.
The one amendment to the locked decision: invert the merged schema's center of gravity. Packet is the host name + identity + proof spine, but the merged capture/curate body centers on notes' quintet (documentCuration / readingStates / inboxItems / collections / views) because it is the only already-source-agnostic schema in the corpus. Packet absorbs notes' curation engine; it does not flatten notes into receipt-shaped tables.
2. WHERE EVERYTHING LIVES
L1 packages (@creative-int/*)
| Action | Package | Why now / why not |
|---|---|---|
| EXTRACT NOW | @creative-int/press-render (promote apps/press/packages/core — compile.ts/render.ts/starters.ts verbatim) |
Verified backend-agnostic (zero Convex, deps = beautiful-mermaid/marked/playwright/yaml). The corpus demanded this renderer twice: packet's packetExportReceipts provider:"press" is a dangling enum waiting for it, and keris's internal press-layer-artifact-campaign is building a parallel compiler — that duplication is the extraction trigger. This is a scope-rename of a clean boundary, not a build. |
| ACTIVATE (already L1, just adopt) | @creative-int/sources + @creative-int/convex-sources |
This is the "context-packet L1 core" the brief keeps reaching for — it already does "source → sync run → context packet." Notes consumes it; the merged packet adopts it as the ingest layer so packetSourceDocuments and notes' inboxItems stop being two re-inventions. The move is adoption-leveling, not a new table. |
| DEFER (gate at 2 real consumers) | @creative-int/context-packet core (durable evidence-packet store with referential integrity) |
Forcing it now = a string-keyed table that strips keris's v.id("teams")/v.id("codebaseConnections") FKs. Trigger: a second app needs team-scoped evidence packets with integrity. Until then, packet and keris are two honest faces over shared sources, not one forced table. |
| DEFER (gate at 2 real consumers — sine is the 2nd) | @creative-int/publish-lifecycle (render-job→artifact→share→receipt) |
§D4 already ruled this; honor it. PDF/video/audio renderers stay product-local; press-render is a document compiler that emits PDF, never a media renderer, so extracting it does not violate the "media renderers stay local" rule. |
| ACTIVATE post-merge (Wave 2, NOT merge-blocking) | @creative-int/connectors (0 consumers) + @creative-int/reflector (0 consumers) |
connectors is the canonical answer to Gmail/Drive/X ingestion-as-context-source — the exact OAuth substrate each app would otherwise re-invent. reflector ("scheduled corpus-analysis → curated-canon suggestions") is the context-learning differentiator that turns the merged app from a folder into the agent-native context app. Both gate behind a landed corpus — activating two greenfield primitives during the merge is precisely the scope-creep that stalled S7. |
Product faces vs. archive
- packet — SURVIVES as THE product (the merged knowledge-artifact face). Host name, Clerk auth, receipt/proof spine, production maturity. Consumes
press-render+sources+convex-rag+ (Wave 2)connectors/reflector. - press — SPLITS. Read/publish half ports into packet. Local-first authoring CLI + Rust TUI SURVIVE as a standalone operator-authoring face over
@creative-int/press-render. This is doctrine-clean: press isproduct-tui-host; path-as-identity local authoring is a genuinely different user promise from packet's Clerk-multi-tenant hosted product, and it is the only create/render loop that works today. It consumes only the L1 renderer (down-dependency, allowed) with zero coupling to the packet product. - notes — ARCHIVES (web + TUI) after its quintet becomes packet's canonical capture schema. Its reader-CLI ingestion engine survives as a source adapter feeding
@creative-int/sources, not a standalone app. No long-lived app-to-app bridge. - keris — SEPARATE PRODUCT, unchanged in identity. Keeps its team-scoped evidence engine and
videoPipeline.tsin place. Shares exactly two L1 surfaces with the merged app:press-render(new) andsources(existing). ItscodebaseEvidencePackets/agentRunEvidencestay keris-owned with FK integrity intact. Its press-layer-campaign stops being a 2nd renderer and becomes apress-renderconsumer.
The artifact-making capability's home
The capability crystallizes in @creative-int/press-render (the renderer) + @creative-int/sources (the ingest) — not in any one host app and not in a speculative context-packet table. The receipt/proof spine stays packet-app-owned until a 2nd app proves it needs the same ledger (it does not — keris has usageEvents/videoEvidence, packet has the credit ledger; different accounting promises).
The capability audit's 3-build plan — where each lands
This maps cleanly and reinforces the recommendation (the 3 builds were already authored "rule = bar, skill = workflow, package = CSS+engine"):
mastheadpress starter + hero partial → lands inside@creative-int/press-renderas a canonical starter/theme (starters.ts+masthead.css). The L1 extraction is the natural home for it — promoting.sip-heroout of the SIP fork and into the now-shared renderer is the same move, done once. MUST, build-first, smallest diff.rules/artifacts.md(config/agents/rules + rules.index.json) → orthogonal to the merge; ship immediately, independent of everything. "Designed deliverables route through press-render, not hand-rolled markdown→PDF." Makes the bar trigger-discoverable. MUST.artifactskill (via skill-factory — direct SKILL.md authoring forbidden) → orthogonal; ship after #1 so it can call the masthead starter. Owns enrich→scaffold→structure→diagram→render→verify→deliver, with the keris 7-anti-pattern VQA gate. MUST, keystone.
The capability-audit builds do not wait on the product merge — they ride the press-render extraction, which is exactly the one L1 move this verdict front-loads. That alignment is the strongest signal that the renderer-first sequence is correct.
3. THE 7 QUESTIONS — decisive one-liners
- Ratify / revisit / execute? → RATIFY + EXECUTE. Answer keris-as-host NO and close it; the S7 stall is missing Luke-signoff, not product friction (proof:
contentSourceDocuments/contentIdentityMappingsexist in zero apps — no porting friction has been encountered yet). Unblock by shrinking the ask to the single non-destructive import-one-doc step. - Capability own-in-app vs L1? → SPLIT. Extract
@creative-int/press-renderto L1 now (2 consumers-in-waiting prove it). Adopt existing@creative-int/sourcesas the context-packet ingest. Keep receipt/proof packet-app-local. Defercontext-packet/publish-lifecyclecores to the 2-consumer gate. - keris generalize vs pure? → PURE — share substrate only (option b, but conservatively). Share
press-render+sources; do not extract its evidence engine yet (itsv.id("teams")FKs would be stripped by a generalized string-keyed table). Reject host (c). Revisit evidence-engine extraction only when a 2nd app needs team-scoped packets with integrity. - packet identity stretch? → packet = host SHELL + name + proof spine; merged capture/curate schema CENTERS on notes' quintet. Packet gains the curate layer it lacks; it does not force notes into a receipt-shaped hole. The host is packet; the curation canon is notes.
- Survives vs archives? → packet SURVIVES (the product). press SPLITS — read/publish ports in, local-first authoring CLI+TUI survives as an operator face on
press-render. notes ARCHIVES (quintet → packet; reader-CLI →sourcesadapter). No long-lived bridges. - Activate reflector/connectors? → YES, in the merged packet, as Wave 2 — post-port, NOT merge-blocking.
connectors= the answer to Gmail/Drive/X ingestion (vs N apps re-inventing OAuth);reflector= the context-learning moat. Both 0-consumer today; the merged app is their first consumer; gate them behind a landed corpus. - Multi-tenancy? → packet's Clerk users + a notes-style string
workspaceId(user:<clerkId>|org:<orgId>) — notes already proved that shape is source-agnostic and packet'screatedBy:v.id("users")maps onto it. Migration tax: press = highest (no userId anywhere — butpress-renderis stateless so the tax falls only on ported publish rows; the local-authoring face stays single-tenant); notes = low (already userId-keyed); packet = closest to ready. keris is OUT of this decision (stays teams-scoped). Tax owner = the merge campaign; press port first.
4. SEQUENCED PLAN
The leverage insight: the one L1 extraction this verdict front-loads (press-render) also unblocks all three capability-audit builds. So Wave 0 buys two wins — it de-risks the merge AND crystallizes the artifact capability — without opening the over-extraction program ARCH-B implies.
Wave 0 — UNBLOCK (this week, parallel, zero merge risk) — MUST
- STEP 1 (the first concrete step Luke can take): a 30-minute drop-list review where Luke can veto specific ports, not a rubber stamp. Present only the
contentSourceDocuments+contentIdentityMappings+ import-one-notes-reader-doc step — non-destructive, identity-safe. This is the literal S7 gate; clearing it is the single highest-leverage act. (If Luke balks specifically at notes→packet, that is the signal to weigh ARCH-B — see Dissent.) - STEP 2 (parallel, independent): ship
rules/artifacts.md+ rules.index.json entry. No dependency on anything.
Wave 1 — EXTRACT ONE + ADOPT — MUST
- Extract
apps/press/packages/core→@creative-int/press-render(scope-rename; press stays consumer #1). Fold in the masthead starter (.sip-hero→starters.ts) +print.csshere. Wire packet'spacketExportReceipts provider:"press"to the real import. Point keris's press-layer-campaign at it. - Bootstrap the
artifactskill via skill-factory (now that the masthead starter exists for it to call). - Adopt
@creative-int/sourcesin packet as the ingest layer (press gainsconvex-ragtoo — the one RAG gap).
Wave 2 — MERGE (the locked S7 port, schema-inverted) — MUST
- Land notes' curation quintet as packet's canonical capture schema; bolt packet's receipt/proof tables on as the create/publish/proof layer.
- Port press's read/publish half into packet. Port notes' reader docs; prove parity; archive notes web/TUI.
- Stand up packet's tenancy model (
workspaceIdstring key); stamp ported rows with userId.
Wave 3 — DIFFERENTIATE (fast-follow, gated on a landed corpus) — SHOULD
- Activate
connectors(Gmail/Drive/X as context sources) andreflector(learn-the-corpus) in the merged packet as their first consumer.
OPTIONAL / deferred (do NOT do now)
@creative-int/context-packetcore — wait for a 2nd team-scoped-evidence consumer.@creative-int/publish-lifecycle— wait for sine (audio) as the 2nd consumer.- Keris evidence-engine generalization — strictly downstream of "a 2nd app needs it"; never speculative.
- notes' reader-binary cloud-ization — face-internal, blocks nothing, sequence last.
Must-do vs optional line: Waves 0–2 are MUST. Wave 3 is SHOULD (it is the soul of the bet, but it must not block the merge). Everything under OPTIONAL is gated on real 2nd consumers — pulling any of it forward is the over-extraction trap.
5. DISSENT
Objection 1 — "A-now degenerates into A-now-B-never; packet's product taste calcifies as de-facto infrastructure" (the ARCH-B steelman, and product-coupling.md's literal text — "consumer product as spine → put the spine in packages"). This is the strongest objection and it indicts packet-as-host, not just keris-as-host. Why I still hold: (a) §D4 re-ratified packet-as-merge-target after that doctrine existed — it is a boundary ruling, not a violation; "host app" ≠"spine package" when the spine (renderer, sources, receipts) is extractable underneath it. (b) The mitigation is concrete, not a promise: this verdict extracts press-render now (proves the spine-underneath pattern is real, not deferred) and adopts sources as the L1 ingest now — the durable engine genuinely lives in packages while packet is only the face over it. (c) The honest hedge: parked phase-2 work has a 6-month track record of never happening here, so the context-packet/publish-lifecycle deferrals must be written as named campaigns with their 2nd consumers pre-identified (keris-evidence; sine-audio), or B's critique comes true. I weight migration-cost-and-integrity over doctrine-purity because the schemas make B's "extract now" produce a strictly worse artifact today (a string-keyed table that strips keris's FKs) — purity that destroys referential integrity is not purity.
Objection 2 — "Ratifying rewards the stall; the 6-month silence IS Luke's gut saying packet-as-host is wrong, which is why the convergence prompt resurfaces keris-as-host." Why I still hold: keris-as-host fails on first principles independent of the locked decision — it pulls 8,787 lines of video gravity into notes/curate, couples apps→apps, and the keris audit itself recommends extract-evidence-first (= ARCH-B, not C). But I take the reservation seriously, which is why Wave-0-Step-1 is a veto-capable drop-list review, not a rubber stamp: if Luke balks specifically at notes→packet, the schema-inversion amendment (center on notes' quintet) is likely what he actually wants — and if he balks at packet-as-host entirely, that is the one signal that should reopen the L1-faces shape of ARCH-B. The architecture is decisive; the gate is honest about where Luke's taste can still interrupt it. That is the operate-at-intent contract: the machine executes the locked plan, and only Luke's taste-moment interrupts it.
Bottom line: Ratify §D4. Ship the merge with notes' quintet as the schema center and packet as the name+proof host. Extract exactly one L1 package now (press-render — which doubles as the artifact-capability home and absorbs all three capability-audit builds). Adopt sources as the L1 context-packet ingest. Keep keris a separate product sharing two L1 surfaces, evidence-engine integrity intact. Activate connectors+reflector as Wave-2 fast-follow once a real corpus exists. First step: the 30-minute, veto-capable S7 drop-list review on the single non-destructive import.
source ledger
- Products convergence council verdict (file)
proof ledger
- none