Pending: 0 Building: 0 Running: 8 Failed: 178
Created Date Type Name Commit Description State Age Up Time Life Time Action
merged [FIX] viin_brain,viin_web_editor: Brain core launch-hardening (T-1/T-2/T-3) [FIX] viin_brain,viin_web_editor: Brain core launch-hardening (T-1/T-2/T-3) - T-2 privacy: daily notes can never be shared via link (ValidationError in _check_page_shareable); share comment state no longer hardcoded (honors comment_auto_approve). - T-3 ACL: complete the 40-cell matrix in tests — non-owner (incl brain/vault admin) cannot read/write another user's daily note; commenter cannot write own daily body. No rule change (rule_page_daily_global already enforces). - T-1 concurrency: deterministic version token (isoformat ms) + re-enable first-save optimistic-concurrency check in page_editor (realtime untouched). - Tests: viin_web_editor powerbox-registry QUnit, trigger-regex edge cases, block_parser round-trip tour + wrapper. - Docs: CHANGELOGs, brain/security.md ACL matrix, decisions/wi-005 (privacy-first). Failed
merged [DOC] root: AI agent onboarding guides (AGENTS/CLAUDE/GEMINI) [DOC] root: add AI agent onboarding guides (AGENTS/CLAUDE/GEMINI) SSOT in AGENTS.md (read directly by Codex); CLAUDE.md and GEMINI.md @import it plus per-CLI notes. Positions ai17 as two independent products bridged modularly: Viindoo Brain (knowledge OS — Notion for humans + Obsidian-style second brain for AI agents) and Viindoo AI (agentic orchestration OS). Captures must-read docs, core security prohibitions, git/worktree discipline, Runbot test model. Shared-repo hygiene: guides contain NO machine/personal-local info. AGENTS.md adds prohibitions 18-21 — never commit absolute home paths, internal infra, per-developer AI config (MCP/skills/local models), or secrets; keep per-developer config outside the repo; self-check diffs before PR. CLAUDE.md/GEMINI.md kept generic and portable. Killed Not finished
merged [DOC] root: AI agent onboarding guides (AGENTS/CLAUDE/GEMINI) [DOC] root: add AI agent onboarding guides (AGENTS/CLAUDE/GEMINI) SSOT in AGENTS.md (read directly by Codex); CLAUDE.md and GEMINI.md @import it plus per-CLI notes. Positions ai17 as two independent products bridged modularly: Viindoo Brain (knowledge OS — Notion for humans + Obsidian-style second brain for AI agents) and Viindoo AI (agentic orchestration OS). Captures must-read docs, core security prohibitions, git/worktree discipline, Runbot test model. Killed Not finished
merged [IMP] viin_brain,viin_web_editor: Brain core UI polish wave — runtime bug + a11y/responsive [IMP] viin_brain,viin_web_editor: Brain core UI/UX polish wave Squashed integration of the Brain core polish wave (branch wave/integration-brain-polish-w1): runtime bug fixes, theme repair, a11y/responsive, the form-sidebar quick-create drawer reworked onto the native web_editor editor, plus JS/behaviour tests and doc sync. Scope is viin_brain + viin_web_editor only; rebased on origin/17.0. Added - Quick-create drawer note body now mounts the native web_editor Wysiwyg (OdooEditor), lazy-loaded from web_editor.backend_assets_wysiwyg, working on in-memory HTML (no persisted page) so the create-on-save/discard flow is preserved; body saved into content_html. First surface delegated to the audited editor per ADR-003 Path B (PageEditor migration stays P16). - Responsive 3-pane layout (_responsive.scss): tablet 2-pane with the context pane as an overlay; phone single-pane with a slide-in sidebar drawer and ellipsised title. - A11y: <main role="main"> landmark, page-title aria-label, disabled "Related" tab aria-disabled + tabindex=-1; header hamburger toggles the sidebar; timeline icon corrected. Changed - Form sidebar lists notes LINKED to a record, not only inline @-mentions: _brain_mentioning_page_ids unions viin.brain.link record-mentions with viin.brain.page.record.link rows, and _compute_brain_page_count uses the same union via a distinct page-id set (no double count) with ACL filtering. - "Link a record" replaced by a friendly two-step "Link a document" picker (core ModelSelector + RecordSelector); model:id output contract unchanged. - Filter pills compacted to a single scrolling row; panel/graph bars wrap instead of overflowing in the ~300px context pane. Fixed - Theme token system repair (theme_tokens.scss): Odoo 17 emits no --bs-* runtime properties and the prior self-referential shims formed a CSS cycle resolving empty (theme-blind UI); redefined non-self-referentially from live Odoo vars with literal fallbacks. - OWL this-binding crashes in bare inline arrow handlers (drawer vault / entry-kind clicks, calendar view, moderation panel). - Form sidebar layout is resize-reactive: ui service useState-wrapped so layoutMode recomputes on viewport change. - Share dialog reveals the public URL on save + .bind toggle; template dialog body moved to the Dialog default slot; sidebar label live-updates on rename via a brain-page-renamed bus event; removed the hardcoded "P12" badge; badges migrated to text-bg-secondary. - viin_web_editor: removed the spike powerbox demo commands (viin_spike_hello / viin_spike_block + brain category); registries ship empty; embedded_component_host docstring repointed to native_commands.js. Tests - Drawer tour (crash guards + native Wysiwyg mount + Save) with a Python runner asserting the server outcome; BrainFormSidebar layout + resize reactivity unit tests; backend tests for the linked-notes union. Verified on a clean pg16 DB: drawer tour green, backend suites green. Docs - CHANGELOG [Unreleased] entries (viin_brain + viin_web_editor); README "what's new"/responsive/sidebar updates; contenteditable_policy.md reconciled (Path-B delegated surface, status, change history). Killed
merged [IMP] viin_brain,viin_web_editor: Brain core UI polish wave — runtime bug + a11y/responsive [IMP] viin_brain,viin_web_editor: Brain core UI/UX polish wave Squashed integration of the Brain core polish wave (branch wave/integration-brain-polish-w1): runtime bug fixes, theme repair, a11y/responsive, the form-sidebar quick-create drawer reworked onto the native web_editor editor, plus JS/behaviour tests and doc sync. Scope is viin_brain + viin_web_editor only; rebased on origin/17.0. Added - Quick-create drawer note body now mounts the native web_editor Wysiwyg (OdooEditor), lazy-loaded from web_editor.backend_assets_wysiwyg, working on in-memory HTML (no persisted page) so the create-on-save/discard flow is preserved; body saved into content_html. First surface delegated to the audited editor per ADR-003 Path B (PageEditor migration stays P16). - Responsive 3-pane layout (_responsive.scss): tablet 2-pane with the context pane as an overlay; phone single-pane with a slide-in sidebar drawer and ellipsised title. - A11y: <main role="main"> landmark, page-title aria-label, disabled "Related" tab aria-disabled + tabindex=-1; header hamburger toggles the sidebar; timeline icon corrected. Changed - Form sidebar lists notes LINKED to a record, not only inline @-mentions: _brain_mentioning_page_ids unions viin.brain.link record-mentions with viin.brain.page.record.link rows, and _compute_brain_page_count uses the same union via a distinct page-id set (no double count) with ACL filtering. - "Link a record" replaced by a friendly two-step "Link a document" picker (core ModelSelector + RecordSelector); model:id output contract unchanged. - Filter pills compacted to a single scrolling row; panel/graph bars wrap instead of overflowing in the ~300px context pane. Fixed - Theme token system repair (theme_tokens.scss): Odoo 17 emits no --bs-* runtime properties and the prior self-referential shims formed a CSS cycle resolving empty (theme-blind UI); redefined non-self-referentially from live Odoo vars with literal fallbacks. - OWL this-binding crashes in bare inline arrow handlers (drawer vault / entry-kind clicks, calendar view, moderation panel). - Form sidebar layout is resize-reactive: ui service useState-wrapped so layoutMode recomputes on viewport change. - Share dialog reveals the public URL on save + .bind toggle; template dialog body moved to the Dialog default slot; sidebar label live-updates on rename via a brain-page-renamed bus event; removed the hardcoded "P12" badge; badges migrated to text-bg-secondary. - viin_web_editor: removed the spike powerbox demo commands (viin_spike_hello / viin_spike_block + brain category); registries ship empty; embedded_component_host docstring repointed to native_commands.js. Tests - Drawer tour (crash guards + native Wysiwyg mount + Save) with a Python runner asserting the server outcome; BrainFormSidebar layout + resize reactivity unit tests; backend tests for the linked-notes union. Verified on a clean pg16 DB: drawer tour green, backend suites green. Docs - CHANGELOG [Unreleased] entries (viin_brain + viin_web_editor); README "what's new"/responsive/sidebar updates; contenteditable_policy.md reconciled (Path-B delegated surface, status, change history). Failed
merged [IMP] viin_brain,viin_web_editor: Brain core UI polish wave — runtime bug + a11y/responsive [DOC] viin_brain,viin_web_editor: sync docs with the UI/UX polish wave The wave shipped substantial behaviour/architecture changes with no doc updates (except a partial contenteditable_policy edit). Two read-only drift analyses (one per module) mapped the gaps; this commit closes them. No code changes - docs only. viin_brain/CHANGELOG.md - New "## [Unreleased]" section (Keep-a-Changelog; PR not merged so no version fabricated - manifest stays 0.3). Added/Changed/Fixed covering: native web_editor Wysiwyg in the quick-create drawer (ADR-003 Path B), responsive 3-pane layout, a11y landmarks, sidebar lists linked notes (mention + record-link union), friendly "Link a document" picker, theme token cycle repair, resize-reactive layout, this-binding crash fixes, share-dialog/template-dialog fixes, P12 badge removal. viin_brain/README.md - "What's new - UI/UX polish wave (unreleased)" subsection; responsive note in the OWL client-action description; ChatterAware sidebar bullet expanded (resize-reactive + linked-notes union); record-mention section notes explicit record links surface in the form sidebar; one sentence on the runtime --bs-* shim mechanism under Theme Compatibility. viin_brain/docs/brain/contenteditable_policy.md - Reconciled internal inconsistencies introduced when the drawer Path-B note was added earlier in this PR: bumped "Last verified at" to SHA e45c3a4 / 2026-06-02 (and re-confirmed the section-5 rogue grep is empty), added a dated section-8 status bullet recording the first Path-B surface, and reordered the section-7 change history to newest-last. viin_web_editor/CHANGELOG.md - New "## [Unreleased]" section: Removed the spike powerbox demo commands (viin_spike_hello / viin_spike_block + brain category); Changed the embedded_component_host docstring to point at native_commands.js (T-5). Known pre-existing nit (out of scope, anchors still resolve): the section-3 audit table line numbers in contenteditable_policy.md have drifted from the source; the durable grep anchors remain valid. Killed Not finished
merged [IMP] viin_brain,viin_web_editor: Brain core UI polish wave — runtime bug + a11y/responsive [TEST] viin_brain: JS smoke + behaviour tests for the UI/UX polish wave The wave reworked the form-sidebar quick-create flow heavily but left the JS surfaces unguarded. Adds protection at two altitudes (ETHOS §11 - guard the behaviour, not the click): 1. Quick-create drawer tour (brain_form_sidebar_drawer.js + Python runner): open the drawer, click a vault item and an entry-kind button (both crashed pre-fix via the bare-arrow "this" loss), assert the native web_editor Wysiwyg mounts, type a rich body, Save & Close. The runner then asserts the server outcome - page created, title + rich body persisted, entry_kind applied (so the crash fix produced an *effect*, not just "did not throw"), and the note surfaces on the record via the sidebar union (#1). Verified on a clean DB: 12/12 steps + all assertions green. 2. BrainFormSidebar layout unit tests (brain_form_sidebar_layout_tests.js): panel/rail/strip mapping + the resize-reactive guard - mutating the viewport size after mount must re-render the layout. This fails if the useState(useService('ui')) wrap regresses to a bare useService (the #3 bug). All assertions pass (verified in isolation: 4/4). Registers both in __manifest__.py (web.assets_tests / web.qunit_suite_tests) and the runner in tests/__init__.py. Killed Not finished
merged [IMP] viin_brain,viin_web_editor: Brain core UI polish wave — runtime bug + a11y/responsive [TEST] viin_brain: JS smoke + behaviour tests for the UI/UX polish wave The wave reworked the form-sidebar quick-create flow heavily but left the JS surfaces unguarded. Adds protection at two altitudes (ETHOS §11 - guard the behaviour, not the click): 1. Quick-create drawer tour (brain_form_sidebar_drawer.js + Python runner): open the drawer, click a vault item and an entry-kind button (both crashed pre-fix via the bare-arrow "this" loss), assert the native web_editor Wysiwyg mounts, type a rich body, Save & Close. The runner then asserts the server outcome - page created, title + rich body persisted, entry_kind applied (so the crash fix produced an *effect*, not just "did not throw"), and the note surfaces on the record via the sidebar union (#1). Verified on a clean DB: 12/12 steps + all assertions green. 2. BrainFormSidebar layout unit tests (brain_form_sidebar_layout_tests.js): panel/rail/strip mapping + the resize-reactive guard - mutating the viewport size after mount must re-render the layout. This fails if the useState(useService('ui')) wrap regresses to a bare useService (the #3 bug). All assertions pass (verified in isolation: 4/4). Registers both in __manifest__.py (web.assets_tests / web.qunit_suite_tests) and the runner in tests/__init__.py. Failed
merged [IMP] viin_brain,viin_web_editor: Brain core UI polish wave — runtime bug + a11y/responsive [TEST] viin_brain: JS smoke + behaviour tests for the UI/UX polish wave The wave reworked the form-sidebar quick-create flow heavily but left the JS surfaces unguarded. Adds protection at two altitudes (ETHOS §11 — guard the behaviour, not the click): 1. Quick-create drawer tour (brain_form_sidebar_drawer.js + Python runner): open the drawer, click a vault item and an entry-kind button (both crashed pre-fix via the bare-arrow loss), assert the native web_editor Wysiwyg mounts, type a rich body, Save & Close. The runner then asserts the server outcome — page created, title + rich body persisted, entry_kind applied (so the crash fix produced an *effect*, not just "did not throw"), and the note surfaces on the record via the sidebar union (#1). Verified on a clean DB: 12/12 steps + all assertions green. 2. BrainFormSidebar layout unit tests (brain_form_sidebar_layout_tests.js): panel/rail/strip mapping + the resize-reactive guard — mutating the viewport size after mount must re-render the layout. This fails if the useState(useService('ui')) wrap regresses to a bare useService (the #3 bug). All assertions pass (verified in isolation: 4/4). Registers both in __manifest__.py (web.assets_tests / web.qunit_suite_tests) and the runner in tests/__init__.py. Killed Not started Not finished
merged [IMP] viin_brain,viin_web_editor: Brain core UI polish wave — runtime bug + a11y/responsive [IMP] viin_brain: drawer note body uses native web_editor Wysiwyg (ADR-003 Path B) Replaces the quick-create drawer's hand-rolled contenteditable + execCommand toolbar with the native web_editor Wysiwyg (OdooEditor) — the editor the project's own ADR-003 mandates (TipTap rejected; PageEditor migration is P16). Why the previous approach was wrong: - It declared a raw, static contenteditable="true" in Brain markup, which is a rogue editable surface under the normative contenteditable_policy.md (two-surface invariant §2). The §5 rogue-detection lint went non-empty. Why native Wysiwyg fits here (and PageEditor does not): - Wysiwyg edits in-memory HTML and exposes getValue(), so it needs no persisted page — the drawer's create-on-save / discard flow is preserved. PageEditor requires an existing pageId and brings full-pane chrome + autosave/collab machinery, unsuitable for a quick-capture drawer. - viin_web_editor already patches Wysiwyg._getPowerboxOptions, so the Brain powerbox/slash commands appear automatically (parity, no extra code). Implementation (OSM-grounded, mirrors web_editor HtmlField + the in-org viin_customizer HTMLEditor pattern): - Lazy-load web_editor.backend_assets_wysiwyg in onWillStart, mount Wysiwyg as a dynamic <t t-component>; capture the instance via the startWysiwyg prop. - Build the Wysiwyg props ONCE (stable identity) so the dynamic component does not remount and drop the captured instance. - _bodyHtml() reads getValue(); empty sentinel <p><br></p> => no content. - The editable's contenteditable lives inside web_editor (audited), so Brain declares none: contenteditable_policy.md §5 grep is empty again. Policy §2 + change history updated to document the delegated surface. Verified live (sale.order form, pg16): drawer mounts exactly one Wysiwyg, rich content persists (content_html=<p><b>…</b></p>), §5 lint empty, module upgrade compiles assets clean. Failed
merged [IMP] viin_brain,viin_web_editor: Brain core UI polish wave — runtime bug + a11y/responsive [FIX] viin_brain: sidebar lists linked notes + rich-text drawer + resize-reactive layout Three review findings on the form-view Brain sidebar (sale.order): 1. A note created via the quick-create drawer links the record on the Brain side but never appeared on the record's own sidebar/stat count. Root cause: the sidebar query (_brain_mentioning_page_ids) and the stat compute (_compute_brain_page_count) only looked at record_mention links, while the drawer writes an explicit viin.brain.page.record.link (linked_record_ids) — two distinct mechanisms. Union both so a note 'about this record' shows on the record. Page-level ACL preserved (count filtered through an ACL-applied page search; list filtered by the downstream page read). Behaviour tests added (fail pre-fix). 2. Drawer body was a plain textarea, so notes could not be formatted. Replaced with a contenteditable rich-text region + a static toolbar (bold / italic / heading / bulleted list) emitting semantic tags; innerHTML is saved as content_html (mirrors PageEditor). 3. The form sidebar layout (panel/rail/strip) did not react to browser resize. Root cause: uiService was read via bare useService('ui'), so reads of ui.size did not subscribe the component. Wrapped with useState (canonical Odoo 17 pattern) so layoutMode recomputes on resize. Failed
merged [IMP] viin_brain,viin_web_editor: Brain core UI polish wave — runtime bug + a11y/responsive [FIX] viin_brain: form-sidebar drawer crashes + inline note body + header padding Review of the Brain form sidebar (sale.order / res.partner) surfaced three issues: 1. Create-drawer crashes (same unbound-`this` class as the share-dialog fix): `t-on-click="() => onVaultSelect(vault.id)"` / `() => onEntryKindSelect(...)` call a BARE method inside an inline arrow, so OWL invokes it without the component as `this` → "Cannot read properties of undefined (reading 'state')" when picking a vault or an entry kind. Swept the whole class: every `=> onXxx(` arrow handler now uses `=> this.onXxx(` (9 sites across brain_create_drawer, brain_form_sidebar [onOpenPage — would crash on a linked page click], moderation_panel, database_calendar_view drag/drop). 2. Header "too close to the left": the form-sidebar header rendered with NO padding. Root cause — `padding: … calc(map-get($spacers, 2) * 0.75)`: SCSS does NOT evaluate `map-get()` inside a CSS `calc()`, so it compiled to the literal `calc(map-get($spacers, 2) * 0.75)` — invalid, which makes the browser drop the ENTIRE padding declaration → 0 padding. Same class as the earlier LibSass `min()` regression. Fixed by letting Sass compute the value directly: `(map-get($spacers, 2) * 0.75)` → `padding: 8px 16px 6px`. 3. Note body not editable inline (had to leave the form for the Brain app — a UX failure when the note must reference the open record): the create drawer now has an inline body textarea; its content is saved as `content_html` on creation (the page model syncs content_plain/blocks), so the user writes the note while the record stays on screen. "Save & Open in Brain" still available for rich editing. Verified live (res.partner form): vault + entry-kind selection no longer crash; note created with body content + entry_kind + record link; header padding renders. Killed Not finished
merged [IMP] viin_brain,viin_web_editor: Brain core UI polish wave — runtime bug + a11y/responsive [FIX] viin_brain: share dialog crash/no-link + friendly link-to-record picker Two UX/runtime issues found in review: 1. Share dialog (share_dialog): - Toggling "Public link" threw "Cannot read properties of undefined (reading 'state')" — the CheckBox onChange was wired as `onChange="(val) => onToggleLink(val)"`, an unbound inline arrow that OWL invoked without the component as `this`. Use `onChange.bind` so the handler keeps its component binding. - "Save settings" created the link but the public URL never appeared: the URL block is gated on `state.enabled`, which onSave never set. Saving a share link now sets `state.enabled = true` so the URL + Copy show. 2. Link-to-record (link_record_dialog): replaced the raw "model:id" text box (e.g. "res.partner:42" — meaningless to end users) with Odoo's native friendly pickers — ModelSelector ("Document type", model display names) + RecordSelector ("Document", record-name autocomplete). Optional admin whitelist via _brain_default_linkable_models; empty = all models (Odoo reference-field default). Output contract unchanged (onConfirm "model:id"). Handlers passed with `.bind` to avoid the same unbound-`this` class of bug. Verified in a live Odoo 17 instance: share toggle no longer crashes and the URL shows after save; the link dialog renders the model→record friendly chain; the Brain form-sidebar (Brain Pages stat + Brain Note + BRAIN rail) renders correctly on chatter forms (res.partner) — issue #3 was blocked by #2, not a bug. Killed Not finished
merged [IMP] viin_brain,viin_web_editor: Brain core UI polish wave — runtime bug + a11y/responsive [IMP] viin_brain: filter pills compact single row (mockup parity) + note SSOT dup Killed Not finished
merged [IMP] viin_brain,viin_web_editor: Brain core UI polish wave — runtime bug + a11y/responsive [FIX] viin_brain: repair theme token system — Brain UI was theme-blind (off-theme) Root cause (CEO-reported "rất xấu, không khớp theme Odoo"; PRE-EXISTING, not the polish wave): theme_tokens.scss Block 1 shimmed Bootstrap-5.3 CSS custom props with a SELF-REFERENTIAL pattern `--bs-x: var(--bs-x, fallback)`. A custom property referencing itself is a CSS dependency cycle → computes to the guaranteed-invalid (empty) value; the fallback is never reached. Odoo 17 ships Bootstrap 5.1.3 and emits NONE of --bs-* at runtime (verified empty at :root on the live instance), so every --o-brain-* token that chained into --bs-* (page / sidebar / context backgrounds, borders, muted text, badge text, trust + AI surfaces) resolved to empty → panes rendered transparent with no borders, text fell back to gray, badges lost their fill. The whole app looked flat/off-theme. Fix: rewrite Block 1 as PLAIN (non-self-referential) assignments anchored to Odoo-17 runtime vars that DO carry values (--gray-100..900, --primary, --secondary, --success/-warning/-danger/-info, --body-*), each with a literal fallback. This single change resolves the entire downstream token chain (Block 2 surfaces/borders/text, Block 3 trust/AI) — verified in-browser: --o-brain-bg-sidebar #f8f9fa, --o-brain-border #dee2e6, badge text #fff, header white + 1px borders. Odoo consumes no runtime --bs-*, so global :root definition is side-effect-free; a themed deploy that emits real --bs-* overrides by cascade. Also: vault badge reverted to brand accent fill with white text (earlier wave darkening treated the wrong cause — gray text came from the empty --bs-white, not the fill); badge radius 6px→4px and page title 2.1rem→2rem (mockup/spec). Killed Not finished
merged [IMP] viin_brain,viin_web_editor: Brain core UI polish wave — runtime bug + a11y/responsive [IMP] viin_brain,viin_web_editor: Brain core UI polish wave — runtime bug + a11y/responsive Khảo sát UI live cụm Brain core phát hiện loạt defect runtime + a11y/responsive mà tour test chưa phủ. Wave này đun cạn nhóm bug + polish (low-risk, không chạm kiến trúc; tách khỏi P16 OdooEditor / P14 CRDT còn gated). Runtime bug: - C-1: dialog "+ New page" body rỗng — web.Dialog (Odoo 17) render body qua DEFAULT slot, không phải named "body" slot; bỏ <t t-set-slot="body"> (khớp MovePageDialog). Reproduce bằng click thật + thêm tour brain_new_page_tour. - C-2: context-pane tab bar overflow ở desktop — 4/6 tab bị giấu; flex-wrap để cả 6 tab truy cập được (root cause hiệu lực ở _misc.scss override, fix cả 2). a11y: - H-1: bỏ badge dev "P12" lộ ra UI; nhãn tab trung tính. - H-3: contrast badge vault initials 2.33:1 -> 5.09:1 (token color-mix riêng). - H-4: thêm landmark <main> bọc center pane (Lighthouse landmark-one-main). - M-2/M-3/M-4/M-7: badge class nhất quán, aria-disabled tab, aria-label title động. responsive (H-2): - _responsive.scss: <768px single-pane + sidebar drawer (hamburger header toggle), 768-1024px 2-pane, title ellipsis; escape LibSass min() (mixed px/vw). khác: - M-1: đồng bộ nhãn sidebar khi rename page (env.bus brain-page-renamed). - M-6/L-1/L-2/L-5: graph filter wrap, icon timeline calendar, collapsed sidebar clip, dedupe message daily-note. - T-5: gỡ powerbox spike demo command (viin_web_editor) + scrub comment chết. Verified: cài sạch trên Odoo 17 community + pg16; web.assets_backend compile sạch; UI re-review 9/9 PASS; Lighthouse a11y 76 -> 77. Killed Not finished
merged [ADD] viin_ai_ops: Operating Layer foundation (P-OPS-1) [FIX] viin_ai_agent: stub contract test robust to framework-injected x_ fields The post_install tests test_schedule_stub_has_no_rogue_fields and test_approval_chain_stub_has_no_rogue_fields failed on runbot because viin_workflow_automation grafts x_workflow_* computed fields onto base (every concrete model) in the full Viindoo suite. Those framework-owned fields are outside the P-OPS-1 stub contract, which governs only viin_ai-declared fields. Exclude x_-prefixed fields from the comparison; viin_ai never declares x_-prefixed fields, so the contract's protection is preserved. Killed
merged [ADD] viin_ai_ops: Operating Layer foundation (P-OPS-1) [IMP] viin_ai_ops,viin_ai_agent,viin_ai_chat: address PR #36 review findings Fixes from OSM-grounded (Viindoo 17.0) code review of this PR. viin_ai_ops (HIGH): - control_policy._match_proposal: scope policy search by the proposal's company_id ('|' company_id=False / =proposal.company) — ir.rule only scopes to the *current user's* allowed companies, not the proposal's, so explicit filtering is mandatory for multi-company isolation. Drop the redundant ('active','=',True) term (auto-filtered by _active_name). - goal / work_item / agent_ext / trace_ext compute counts: replace search_count() inside a for-loop (N+1) with a single read_group(); add @api.depends('work_item_ids' / 'proposal_ids') where a reverse O2M exists (goal, work_item). agent_ext/trace_ext have no reverse O2M yet → empty @api.depends() documented, deferred to P-OPS-2. viin_ai_ops (MED): - action_proposal.action_route: gate behind base.group_system so a regular internal user (perm_write) cannot self-route a proposal to 'approved' via a low-risk auto_execute policy. Flow-lock unchanged. Documented assumption: swap for a dedicated approval group in P-OPS-2. - control_policy.model_id: documented as not-yet-matched (proposal has no res_model field this phase) with an explicit P-OPS-2 TODO instead of a silent no-op. - trace form: insert the stat button_box before the first <sheet> group (was position='inside' → rendered at sheet bottom); rename the div to the canonical name='button_box'. viin_ai_agent (HIGH/MED): - test_stub_deprecation_contract: replace dead assertIsNotNone(env[...]) (env[] raises KeyError before the assert → ERROR not FAIL) with assertIn(name, env.registry.models); add rogue-field contract tests so the suite turns RED if a deprecated stub ever accumulates a field. - stubs.py: docstring 'AbstractModels' → 'concrete Models'. - pre-migrate 17.0.0.2.1: document the idempotency contract for future SQL (no behaviour change). viin_ai_chat (LOW): - wrap the NONCE_MISMATCH content string in _() for i18n parity with the NO_PENDING branch. Failed
merged [ADD] viin_ai_ops: Operating Layer foundation (P-OPS-1) [FIX] viin_ai_chat: absent pending tool call → NO_PENDING, not a server warning Root cause (not the symptom): /viin_ai/chat/tool_confirm raised UserError('No pending tool call: %s') whenever _load_pending_tool returned None. But an absent pending state is a NORMAL, designed-in client condition — the proposal was already handled, the single-use nonce was burned, the session-stored state expired, or the user double-submitted the dialog. Raising UserError from a JSON route makes Odoo log it at WARNING on the odoo.http logger, so this fired for ordinary user behaviour in production (and surfaced on runbot as 'Subbuild #...: No pending tool call: wi15-nonce-burn-001'). The sibling NONCE_MISMATCH condition already returns a structured, FE-renderable error instead of raising. Make the no-pending branch do the same: return {status:'error', error_code:'NO_PENDING'}. The agent loop is never entered, nothing is logged, the FE renders a friendly recovery message via its existing status==='error' branch. This supersedes the earlier change that merely @mute_logger'd the AC10 test — that hid the test warning while production logs kept filling. Tests now assert the corrected contract (intent, not output): - AC06: unknown/expired id → NO_PENDING + tool never executed - AC10: post-burn retry → NO_PENDING (was: tolerate UserError) docs/ai/security.md documents the NO_PENDING contract beside NONCE_MISMATCH. Killed Not finished
merged [ADD] viin_ai_ops: Operating Layer foundation (P-OPS-1) [FIX] viin_ai_chat: mute odoo.http in AC10 nonce-burn test test_AC10_nonce_burned_after_mismatch intentionally triggers the 'No pending tool call' UserError on its step-2 retry (the pending state was burned after the prior NONCE_MISMATCH). Odoo's JSON dispatcher logs that UserError at WARNING on the odoo.http logger, which runbot surfaces as a build warning (Subbuild #384049: 'No pending tool call: wi15-nonce-burn-001'). The expected-error sibling tests in this class (AC01/02/03/06) already carry @mute_logger('odoo.http', ...); AC10 was added in M1 W5 without it. Apply the same decorator so the deliberately provoked warning no longer pollutes the log. No behavior or assertion change. Killed Not finished
merged [ADD] viin_ai_ops: Operating Layer foundation (P-OPS-1) [ADD] viin_ai_ops: Operating Layer foundation (P-OPS-1) New Community-compatible module sitting between the AI capability layer (viin_ai_agent) and external approval/workflow systems. Provides four operating objects and the side-effect flow lock from operating-model.md §3. Models: - viin.ai.goal: typed operational goal (KPI / initiative / routine / risk_control) - viin.ai.work.item: authoritative task state (draft -> in_progress -> done/cancelled) - viin.ai.action.proposal: a side-effecting action awaiting governance routing - viin.ai.control.policy: sequence-ordered rule routing proposals to auto_execute / require_approval / block Side-effect flow lock: medium/high risk proposals can never auto-execute; action_route() forces them to 'pending' regardless of policy, and an unmatched proposal defaults to 'pending' (safe default). Smart buttons: Work Items count on viin.ai.agent; Proposals count on viin.ai.trace. Multi-company ir.rule on all four models; control.policy is read-only for standard users. Also marks the viin.ai.schedule / viin.ai.approval.chain stub anchors in viin_ai_agent as deprecated (module + class docstrings, removal checklist, "deprecated" in _description) and adds a non-destructive migration scaffold. Deprecation is documentation-only by design: no per-registry-load warning, which would flood server/CI logs on every startup. FK anchors are kept intact until the relations are migrated in a later phase. Tests: 46 (viin_ai_ops) + stub-deprecation contract; full suite green (0 failed, 0 error of 104 across viin_ai_ops + viin_ai_agent). Killed
merged [ADD] viin_ai_ops: Operating Layer foundation (P-OPS-1) [ADD] viin_ai_ops: Operating Layer foundation (P-OPS-1) New Community-compatible module sitting between the AI capability layer (viin_ai_agent) and external approval/workflow systems. Provides four operating objects and the side-effect flow lock from operating-model.md §3. Models: - viin.ai.goal: typed operational goal (KPI / initiative / routine / risk_control) - viin.ai.work.item: authoritative task state (draft -> in_progress -> done/cancelled) - viin.ai.action.proposal: a side-effecting action awaiting governance routing - viin.ai.control.policy: sequence-ordered rule routing proposals to auto_execute / require_approval / block Side-effect flow lock: medium/high risk proposals can never auto-execute; action_route() forces them to 'pending' regardless of policy, and an unmatched proposal defaults to 'pending' (safe default). Smart buttons: Work Items count on viin.ai.agent; Proposals count on viin.ai.trace. Multi-company ir.rule on all four models; control.policy is read-only for standard users. Also marks the viin.ai.schedule / viin.ai.approval.chain stub anchors in viin_ai_agent as deprecated (docstring + registry warning) and adds a non-destructive migration scaffold. FK anchors are intentionally kept intact until the relations are migrated in a later phase. Tests: 46 (viin_ai_ops) + stub-deprecation contract; full suite green. Failed
merged [DOC] docs,ci: close M1 — SQL template ACL ✅ + Runbot-only CI model + local pre-commit hook [REM] docs: purge viinForge residue — deprecated product viinForge (orchestration platform/wrapper) đã bị loại bỏ. Gỡ toàn bộ 13 reference trên 9 file: - CONTRIBUTING.md: thay wrapper ~/viinforge/ops/scripts/run_{tests,odoo}.sh + venv rỗng viindoo17 bằng lệnh odoo-bin native (venv odoo17 + addons-path deps) — giải luôn gốc 'không biết cách chạy test'. - conventions.md, brain/architecture.md, brain/ui-design.md: gỡ con trỏ tới viinForge workspace/knowledge/reuse-map, giữ quy tắc cứng inline. - decisions/wi-001, wi-003, history/release-notes-v1.3, contenteditable_policy: gỡ con trỏ audit/pattern/worktree tới viinforge repo (dead pointer), giữ nội dung coherent. - brain/mockups/v3/ui_design_v3.html: gỡ checklist item 'viinForge Monitor TUI' (demo data). Verify: grep -rIni viinforge + git grep = 0 match. Append-only decision records chỉ gỡ dead pointer, không sửa nội dung quyết định. Killed
merged [DOC] docs,ci: close M1 — SQL template ACL ✅ + Runbot-only CI model + local pre-commit hook [DOC] docs,ci: close M1 — SQL template ACL ✅ + Runbot-only CI model + local pre-commit hook Phase 3.7 carry-over / Gate M1 closure: - roadmap §5 + security.md checklist: tick SQL template ACL (evidence: sql_template.py _check_sql_safety + ACL CTE __acl_allowed + group_ids allowlist + JSON Schema params; test_sql_template.py ma trận ACL/multi-company all pass). - roadmap §6: định nghĩa CI gate = Viindoo Runbot 'CI/runbot' (Runbot-only theo chuẩn org, tvtmaaddons cũng zero GitHub Actions); gỡ giả định P15 tour gate khóa bởi Chrome runner GitHub Actions — tour chạy trên Runbot. Đồng bộ M1 condition + Track B refs + REPO_LAYOUT. - tooling: thêm husky + mở rộng lint-staged (ruff check/format cho *.py) làm lớp verify local; CONTRIBUTING hướng dẫn chạy test qua odoo-bin --test-tags (không phải pytest thuần). Why: PR #34 chủ động drop CI repo-specific để dùng Runbot external; docs cần khớp thực tế để M1 đóng sạch và dev có lớp verify nhanh trước push. Killed Not finished
merged M1 Wave 1: 3 security HIGH gap closure (trace ir.rule + nl_query sanitize + confirmation nonce) [REMOVE] ci: drop all repo-specific CI — workflows + scripts (PR #34) Stop maintaining ai17's own GitHub Actions CI; rely on the external Viindoo Runbot check instead. Deleted: .github/workflows/{brain-tours,ci,preflight-pgvector}.yml; ops/ci/* (5 files); tools/brain_v3_ci_check.py; docs/brain/ci-tour-gate.md (runbook for the removed gate). Docs cleaned (no history/changelog touched): README.md drops CI Tour Gate link; pgvector_install.md replaces check_pgvector.sh with inline psql, removes the CI section, renumbers §6-§8; tools/README.md drops the brain_v3_ci_check.py section + pre-push runbook. Part of Wave 1 — PR #34. Killed
merged M1 Wave 1: 3 security HIGH gap closure (trace ir.rule + nl_query sanitize + confirmation nonce) [REVERT] .github: back out CI runner switch — return to GitHub-hosted (PR #34) Per decision to abandon the self-hosted Viindoo Runbot switch (M1 W4/W6): - ci.yaml: restore all 5 jobs to runs-on: ubuntu-latest + setup-python steps - preflight-pgvector.yml: restore ubuntu-22.04 + original branch/path triggers Both files now match origin/17.0 byte-for-byte. Security fixes (trace ir.rule, nl_query sanitize, confirmation nonce) untouched. ai17 returns to GitHub-hosted runners; quota strategy handled separately. Part of Wave 1 — PR #34. Killed Not finished
merged M1 Wave 1: 3 security HIGH gap closure (trace ir.rule + nl_query sanitize + confirmation nonce) [FIX] viin_ai_*: root-cause boil-the-lake of /code-review findings — preflight self-hosted + SSOT + dedupe + aggregation fixture + nonce burn (M1 W6) Root-cause fix all 5 findings from /code-review of PR #34. Per boil-the-lake, no shortcuts. 1. preflight-pgvector.yml: switch runs-on from ubuntu-22.04 to [self-hosted, "Viindoo Runbot"]. Root cause of "preflight dead" was org-Free-tier GH Actions quota exhaustion, not workflow code (proven by run 26076812824 which succeeded in 38s before quota hit). Self-hosted Runbot has identical pgvector/pgvector:0.8.2-pg14 service container confirmed via brain-tours.yml. 2. viin_ai_search/controllers/search_controller.py: error message now uses MAX_NL_QUERY_CHARS constant via %d interpolation (SSOT — CLAUDE.md Rule 10). 3. viin_ai_base/tests/test_trace_acl.py: remove duplicate .browse().read() call in test_user_cannot_read_other_users_trace — the first call's result was discarded, dead code. 4. viin_ai_search/tests/test_search_controller.py: replace TODO stub with full integration test for the aggregation path — seeds topic+template+ provider, mocks call_completion, asserts <untrusted_context> wrap in the captured user message of the aggregation LLM call. 5. viin_ai_chat/controllers/chat_controller.py: nonce now single-use — _clear_pending_tool called on NONCE_MISMATCH to burn pending state. Adds AC10 test. Updates security.md §3.1 to document single-use semantics. Part of Wave 1 — PR #34. Killed Not started Not finished
merged [REF] all modules: switch to short version scheme (strip 17.0. prefix) [REF] all modules: switch to short version scheme (strip 17.0. prefix) Odoo recommends short version format (x.y.z) over full (17.0.x.y.z) so that porting to a new Odoo series requires no manifest version bump. - 11 __manifest__.py: strip 17.0. prefix - docs/ai/README.md, roadmap.md, conventions.md, migration.md: update version references and remove stale note about viin_ai_rag alignment - viin_ai_rag/migrations/17.0.0.1.0/pre-migrate.py: update docstring - viin_brain/tests: update migration version reference in comment Migration folder 17.0.0.1.0/ kept as-is (must match what Odoo stored in DB on existing installs). Killed
merged [REF] all modules: switch to short version scheme (strip 17.0. prefix) [REF] all modules: switch to short version scheme (strip 17.0. prefix) Odoo recommends short version format (x.y.z) over full (17.0.x.y.z) so that porting to a new Odoo series requires no manifest version bump. - 11 __manifest__.py: strip 17.0. prefix - docs/ai/README.md, roadmap.md, conventions.md, migration.md: update version references and remove stale note about viin_ai_rag alignment - viin_ai_rag/migrations/17.0.0.1.0/pre-migrate.py: update docstring - viin_brain/tests: update migration version reference in comment Migration folder 17.0.0.1.0/ kept as-is (must match what Odoo stored in DB on existing installs). Killed Not finished
merged [Phase 3.7] Gate M1 carry-over: SQL templates, aggregation router, AI Draft smart button, Brain bridge deprecate [FIX] viin_brain: remove orphan test_ir_http.py — ir_http.py deleted in f815901 (TipTap rejected) Commit f815901 deleted viin_brain/models/ir_http.py and its __init__ import when TipTap editor was rejected in favour of OdooEditor (ADR-003 update). The companion test file viin_brain/tests/test_ir_http.py was not removed, leaving 2 HttpCase tests (test_session_info_includes_editor_backend_flag, test_session_info_defaults_to_odoo_when_invalid) that assert on viin_web_editor_editor_backend in session_info — a key that no longer exists because the injector (ir_http.py) was deleted. Runbot build 381692 (rb-84f5047-221719) caught both failures: AssertionError: None != 'tiptap' AssertionError: None != 'odoo' Fix: delete test_ir_http.py and remove its import from tests/__init__.py. No functional change — the WI-11 classmethod regression guard is no longer needed since the override that triggered it no longer exists. Killed
merged [Phase 3.7] Gate M1 carry-over: SQL templates, aggregation router, AI Draft smart button, Brain bridge deprecate [REF] viin_ai_account,viin_ai_sale,viin_ai_stock: remove <delete> migration guards — no existing installs to upgrade Failed
merged [Phase 3.7] Gate M1 carry-over: SQL templates, aggregation router, AI Draft smart button, Brain bridge deprecate [FIX] viin_ai_account,viin_ai_sale,viin_ai_stock: add <delete> to remove legacy viin_ai_agent placeholder records on install (UniqueViolation fix) Killed Not started Not finished
merged [Phase 3.7] Gate M1 carry-over: SQL templates, aggregation router, AI Draft smart button, Brain bridge deprecate [FIX] viin_ai_agent: stock_on_hand template — use parent_path/view_location_id FK join instead of fragile name LIKE Failed
merged [DOC] Fix documentation drift — editor ADR (OdooEditor), stale state, nav breadcrumbs, Brain bridge timeline [DOC] docs: fix documentation drift — editor ADR, stale state, nav breadcrumbs, Brain bridge timeline Group A — Stale / Navigation (8 fixes): - REPO_LAYOUT.md: replace stale 2026-04-16 skeleton status with accurate Phase 0-3 / P0-P13 ship state - README.md: remove duplicate conventions row, add docs/README.md persona pointer, update date - docs/README.md: add breadcrumb back to root README - docs/brain/README.md: add breadcrumb, remove absolute local path from footer, update date - CONTRIBUTING.md: add Brain cluster onboarding step (step 7) - docs/ai/README.md: add note explaining viin_ai_rag version scheme divergence - docs/brain/data-models.md: add v1.0 note clarifying viin.brain.block is v1.1+ spec Group B — Architecture drift (6 fixes): - docs/decisions/adr-003-wysiwyg-path-b.md: update status Proposed→active; rewrite Decision section — OdooEditor proper extension (NOT TipTap); move TipTap to Alternatives Considered - docs/decisions/README.md: update ADR-003 summary to reflect OdooEditor + TipTap rejected - docs/roadmap.md: fix Track B W12-W17 TipTap→OdooEditor; fix Brain bridge deprecation timeline (W4-W6 bridges redundant, formal remove deferred to v1.2 per ADR-001) - docs/brain/architecture.md: add v1.0 interim callout (raw contenteditable, migration P16) - docs/history/wysiwyg-migration-progress.md: add SUPERSEDED banner (TipTap rejected) - viin_brain/docs/brain/contenteditable_policy.md: rewrite §8 to reflect OdooEditor decision, remove TipTap activation requirements, note tiptap_adapter.js deleted Group C — Code cleanup (1 artifact removed): - viin_web_editor/__manifest__.py: remove tiptap_adapter.js asset entry - viin_brain/models/__init__.py: remove ir_http import - viin_web_editor/static/src/adapters/tiptap_adapter.js: delete TipTap stub - viin_brain/models/ir_http.py: delete TipTap feature flag injector Killed Not finished
merged [DOC] Fix 7 doc conflicts: viin_ai_documents rescope, version pin, branch naming, encapsulation, stub cleanup [DOC] docs: fix 7 conflicts — rescope viin_ai_documents, fix version pin, branch naming, encapsulation, eliminate stub redirects C1: rescope viin_ai_documents from SKIP to Phase 7.4 Wave-C - architecture.md: depends documents -> viin_document (Viindoo Enterprise) - roadmap.md: add to Wave-C W28-W30; footnote fix; inventory 30->31; §10 count update C2: README.md: viin_api_request_logger >= 0.2 -> >= 0.1.1 (actual version in tvtmaaddons17) C3: CONTRIBUTING.md: clarify external vs internal branch naming convention C4: docs/conventions.md: add note that ai17 daily branch is 17.0 (not master) C5: docs/ai/operating-model.md §4.1: remove optional external deps from viin_ai_ops C6: docs/brain/README.md: update roadmap description (absorbed into C7) C7: eliminate 2 stub redirect files (docs/ai/roadmap.md, docs/brain/roadmap.md) - reroute all relative roadmap.md links in docs/ai/*.md and docs/brain/*.md to ../roadmap.md - fix stale anchor in observability.md - update frozen decision records historical notes - update docs/README.md mention of stubs Killed Not started Not finished
merged [DOC] docs: consolidate AI + Brain roadmap into unified W1-W30 plan [DOC] research/cowork-docs: restructure to match CoWork-OS repo layout Move 12 files from flat root into docs/ subdirectory to mirror the original CoWork-OS docs/ layout. The import had flattened this structure, creating 116+ broken links with docs/ prefix in root-level files. Files moved to docs/: - architecture.md, features.md, providers.md, core-automation.md - context-compaction.md, workflow-intelligence.md, heartbeat-v3.md - skills-runtime-model.md, knowledge-graph.md, memory-observations.md - operator-runtime-visibility.md, integration-skill-bootstrap-lifecycle.md Cross-reference fixes (8 links): - docs/architecture.md: managed-agents.md → ../managed-agents.md - docs/core-automation.md: permission-system.md → ../permission-system.md - docs/features.md: managed-agents.md → ../managed-agents.md - execution-runtime-model.md: bare architecture/features → docs/ prefix - permission-system.md: bare core-automation/architecture/features → docs/ prefix Result: broken links reduced from 213 to 185 (-28). Remaining 185 are Type 2 (files never imported from CoWork-OS — not fixable without importing additional source material). Killed Not finished
merged [DOC] docs: consolidate AI + Brain roadmap into unified W1-W30 plan [DOC] compact: merge ui-design pair + merge glossary into conventions A — Merge ui-design files: - docs/brain/ui-design-overview.md (190 lines) + ui-design-waves.md (528 lines) → docs/brain/ui-design.md (single spec, Overview + Component & Wave Specs sections). Removes cross-file navigation overhead. - Update references in brain/README.md, brain/architecture.md, brain/roadmap.md. B — Merge glossary into conventions: - docs/glossary.md (155 lines) absorbed into docs/conventions.md as new §Thuật ngữ section (terminology rules + 10 term tables for phases 3.8/3.9 + Cognitive Layer). - Remove duplicate "Vendor vs Provider" English dispatch section from conventions.md; keep the Vietnamese-focused table from glossary. - Update references in README.md, docs/README.md, docs/roadmap.md, CONTRIBUTING.md, SUPPORT.md, decisions/adr-004. Net: -3 files, -2 cross-file nav sections, conventions.md now single coding-standards-and-terminology reference. Killed Not finished
merged [DOC] docs: consolidate AI + Brain roadmap into unified W1-W30 plan [DOC] dead content cleanup: placeholders, history, orphan links - Remove screenshot placeholder sections from 3 module READMEs (viin_brain, viin_ai_brain, viin_brain_account_reports): TODO images violate ETHOS §4.4 visual evidence — remove until real screenshots exist. - Move 4 cancelled Phase 3.5 dogfood files to docs/history/ (CANCELLED). - Move 2 UAT files (2026-04-17) to docs/history/ (historical artifacts). - Update docs/history/README.md index with 6 new entries. - Fix wi-001-cluster-audit.md: Phase 3.5 status was "Not started" → "CANCELLED — zero legacy traffic; replaced by internal QA gate". - Rewrite docs/roadmap.md §1: remove historical narrative ("trước đây có hai roadmap song song...") — forward-looking only. - Add "See also" links in 3 docs to resolve orphaned files: docs/ai/security.md → phase1/phase2 security checklists docs/brain/security.md → conflict_registry + contenteditable_policy docs/ai/architecture.md → pgvector_install guide Killed Not finished
merged [DOC] docs: consolidate AI + Brain roadmap into unified W1-W30 plan [DOC] research/README.md: document external CoWork-OS origin + known dead-link limitation research/cowork-docs/ and research/cowork-skills/ are partial imports of the CoWork-OS repo (MIT), used as reference input for ADR-004 through ADR-008. Only a subset of CoWork-OS files was imported, so ~220 internal cross-links within those files are broken when navigating on GitHub. Add README explaining: - Source: CoWork-OS (MIT license) - Purpose: design reference, not production code - Known limitation: internal links broken (full import is out of scope) - Navigation workaround: use upstream CoWork-OS repo docs/ and all root .md files: verified 0 dead links. Killed Not finished
merged [IMP] viin_brain,viin_web_editor: UI hardening v1 (token + polish + Odoo-native + v2 seams) [IMP] viin_brain: extend TourCaseBase with _ensure_contracts_database (round 4 follow-up) Address Gap 2 from CEO intent review: 7 tour JS files hardcode :contains("Contracts Database") + :contains("Contract Alpha") selectors, making those tours fail with --without-demo=all even after Phase B switch to TourCaseBase. Per CEO directive (Boil-the-Lake max): seed the demo_db_page_contracts fixture inside cls._tour_vault so tours pass deterministically regardless of demo data state. _ensure_contracts_database() seeds (idempotent — prefer demo, fallback search, finally create): - Contracts Database page (page_type=database, icon 🗂️) - Status property (select with Draft/Review/Signed options) - Effective Date property (date) - Contract Alpha + Contract Beta child pages (Gamma omitted — tours reference only Alpha; Beta provides second row for List/Kanban) - Property values for Alpha (Status=Review, Date=2025-01-15) - Default database view (kind=list, is_default=True) Sets cls._contracts_db_page + cls._contract_alpha_page for subclasses. Tours now pass with both --without-demo=all and demo loaded: brain_database_view, brain_database_calendar_tour, brain_database_gallery_tour, brain_database_board_tour, brain_properties, brain_wikilink (line 97 Contracts Database step) WI14 cluster (graph_panel tour) already covered by test_brain_graph_panel_tour.py's own setUpClass — no fixture extension needed. Refs PR #27. Killed