|
|
|
merged
[IMP] viin_ai_brain, viin_brain, docs: Brain Standard-17 closeout (11 tools + native OT + drift reconcile)
|
[IMP] viin_brain: harden CW2 collab tests per code-review
Post-review hardening for PR #68 (review report
.odoo-ai/reviews/pr68-2026-06-22/viin_brain.md):
- test_brain_collab_activation_tour.py: make the native-collab precondition
deterministic so the tour's channel assertion actually runs instead of being
silently skipped - set the admin notification_type to 'inbox' in setUpClass
(drives session.notification_type truthy -> _hasICEServers ->
_isCollaborationEnabled). The assertion still FAILS when wiring is wrong
(collaborationChannel/busService remain required). Add tearDownClass to
restore notification_type and reset realtime_collab=False (no state leak).
- test_brain_collab_block_roundtrip.py: exercise the real ORM path
(write content_html/blocks -> re-read) instead of calling the private
_derive_from_* helpers directly, keeping the suite red-able.
- test_brain_realtime_collab.py: assertEqual(stored, 'True') (exact) instead
of a permissive membership check.
- brain_collab_activation_tour.js: keep the canonical
odoo.loader.modules.get(...) pattern (matches Odoo 17 core rte.js; require()
is not a global in tour run callbacks) - add a comment to prevent re-flagging.
Review finding F-1 (switch to require) was a false positive.
- CHANGELOG.md: link ADR-002 for traceability.
Browser tour verified by Runbot (headless tour not runnable locally).
|
Killed
|
|
|
|
|
|
|
|
merged
[IMP] viin_ai_brain, viin_brain, docs: Brain Standard-17 closeout (11 tools + native OT + drift reconcile)
|
[FIX] viin_ai_brain, viin_brain: prettier/prettier in QUnit tests (test_eslint gate)
test_pylint/tests/test_eslint::TestESLint.test_eslint failed with 84
prettier/prettier errors across 3 JS test files. The gate runs eslint with
web/tooling/_eslintrc.json, which sets no trailingComma and therefore follows
the bundled prettier 2.8.8 default (es5): no trailing comma after the last
function-call argument, and short multiline calls collapsed.
Fix applied via `eslint --no-eslintrc -c web/tooling/_eslintrc.json --fix`
resolved against prettier 2.8.8 (NOT prettier 3.x, whose trailingComma=all
default produces the opposite and would keep the gate red), bound strictly to:
- viin_ai_brain/static/tests/components/ai_block_tests.js (47)
- viin_ai_brain/static/tests/registries/powerbox_commands_tests.js (32)
- viin_brain/static/tests/tours/brain_collab_activation_tour.js (5)
Formatting only (remove trailing commas, join short multiline calls); no test
logic, assertion, or message string changed. Post-fix: gate exit 0; full
118-file eslint sweep of both modules exit 0.
|
Killed
|
|
Not finished
|
|
|
|
|
|
merged
[IMP] viin_ai_brain, viin_brain, docs: Brain Standard-17 closeout (11 tools + native OT + drift reconcile)
|
[IMP] viin_ai_brain, viin_brain, docs: Brain Standard-17 closeout (11 tools + native OT + drift reconcile)
PR #68 - Brain cluster closeout on Viindoo Standard 17, grounded in a code-level
deep-survey of the cluster.
CW1 (viin_ai_brain): wire the 2 Wave-2 KG-temporal tools (brain_temporal_diff,
brain_record_state_as_of) to the Knowledge Base Assistant topic so the agent reaches
all 11 tools; version 0.1.0 -> 0.1.1 (noupdate=0 re-seed on -u); membership-asserting
RED-GREEN test; CHANGELOG.
CW2 (viin_brain): native OdooEditor WebRTC OT collaboration (ADR-002 Option 1).
_buildWysiwygOptions passes collaborationChannel {model,field,resId} + collaborativeTrigger
to the standalone Wysiwyg, gated on the realtime_collab flag + canEdit; OdooEditor's own
WebRTC P2P + ICE (mail.ice.server) handles OT - zero OT logic reimplemented. The interim
snapshot-relay (collab.py, collab_step_service.js, viin.brain.collab.step) is retired.
Flag-OFF path (autosave + version-token + conflict dialog) unchanged. block_parser
roundtrip test for native-serialized HTML; activation tour + flag tests adapted. Live
2-peer WebRTC convergence is a manual staging check (not headless-CI-testable).
CW3 (viin_ai_brain): QUnit for the AIBlock 5-state machine + powerbox Brain-context gate;
new web.qunit_suite_tests bundle.
Docs (reconcile SSOT to shipped code): adr-003 Accepted (P16 shipped); adr-002 closeout
(native OT shipped, relay retired); security.md (WI-005 declined / WI-006 closed);
roadmap Track B (P16 date, W18-22 panels shipped, OT-final native DONE); "9 tool" -> "11
tool"; adr-001 ADR-012 supersede note; new docs/brain/install-tiers.md (Standard vs
Enterprise).
|
Failed
|
|
|
|
|
|
|
|
merged
[IMP] viin_ai_agent, viin_ai_base: streaming trace header lifecycle + provider Test Connection
|
[IMP] viin_ai_agent, viin_ai_base: streaming trace header lifecycle + provider Test Connection
WI-A (viin_ai_agent): run_streaming() now materializes + closes the viin.ai.trace
header symmetric to run(); run() also closes its header (end_time/status/final_response);
_ensure_trace_header stamps agent_id. Closes the ADR-019 deferred follow-up - streamed
sessions are now observable in the P-OPS-4 cockpit, retention, and proposal.trace_id.
Header create-to-loop span is guarded so an error still closes the header (AGENTS.md #7).
WI-B (viin_ai_base): provider "Test Connection" button (WI-008 WI-F) - a BYOK
reachability/auth probe routed through call_completion (satisfies AGENTS.md #7/#11/#12),
returns {status, latency_ms, model_list} via the built-in display_notification. Vendor
error text is redacted (_redact_secrets) so a BYOK api_key can never leak to the surface.
Docs: roadmap, AGENTS status, observability, wi-008 updated to reflect both changes.
Tests: 333 Odoo-native tests (viin_ai_agent 181 + viin_ai_base 318), 0 failed / 0 error.
|
Failed
|
|
|
|
|
|
|
|
merged
[IMP] viin_ai_brain, viin_brain, docs: Brain Standard-17 closeout (11 tools + native OT + drift reconcile)
|
[IMP] viin_ai_brain, docs: Brain Standard-17 closeout - wire 11 tools to KBA + doc-drift reconcile
CW1: wire the 2 Wave-2 KG-temporal tools (brain_temporal_diff, brain_record_state_as_of)
to the Knowledge Base Assistant topic so the agent can reach all 11 tools; bump
viin_ai_brain 0.1.0 -> 0.1.1 (noupdate=0 re-seed on -u); add membership-asserting
RED-GREEN test (135 viin_ai_brain tests pass, 0 failed); add viin_ai_brain CHANGELOG.
Docs (current-state reconciliation to shipped code):
- adr-003 Status active -> Accepted (P16 shipped 2026-06-07) + checklist
- adr-002 correct false 'collaborative=True already wired' claim (post-P16)
- security.md: admin audit-read DECLINED (WI-005); 7 daily-note cells closed hard-DENY (WI-006)
- roadmap Track B: P16 date, W18-22 panels shipped, P14/P15 header current
- '9 tool' -> '11 tool' across module + docs + AGENTS
- adr-001 inline ADR-012 supersede note on bridge removal clause
- add docs/brain/install-tiers.md (Standard-vs-Enterprise install matrix)
|
Killed
|
|
Not finished
|
|
|
|
|
|
merged
[ADD] Phase 4 Buoc 2: viin_ai accounting write-tools (create_invoice_draft / match_payment / tax_lookup)
|
[DOC] AGENTS, roadmap, decisions, observability: reflect Phase 4 Buoc 2 account write-tools (ADR-019, PR #67)
|
Killed
|
|
|
|
|
|
|
|
merged
[ADD] Phase 4 Buoc 2: viin_ai accounting write-tools (create_invoice_draft / match_payment / tax_lookup)
|
[DOC] AGENTS, roadmap, decisions, observability: reflect Phase 4 Buoc 2 account write-tools (ADR-019, PR #67)
|
Failed
|
|
|
|
|
|
|
|
merged
[ADD] Phase 4 Buoc 2: viin_ai accounting write-tools (create_invoice_draft / match_payment / tax_lookup)
|
[ADD] l10n_vn_viin_ai_account: VN accounting AI guidance (TT99/TT133 additive topic)
|
Killed
|
|
Not finished
|
|
|
|
|
|
merged
[ADD] viin_ai_helpdesk, viin_ai_crm: Phase 4 AI connectors (helpdesk seed + CRM advisory tools)
|
[REM] docs, viin_ai_account, viin_ai_skill, viin_brain_account_reports: drop superseded TT200 accounting refs
TT200 (Thong tu 200/2014/TT-BTC) is superseded by TT99 (Thong tu 99/2025).
TT133 (Thong tu 133/2016, for SMEs) and TT99 both remain in effect and are kept.
- Replace every TT200 reference with its successor TT99: docs (roadmap,
architecture diagram, data-models), README, the account connector manifest
+ seed comment, the accounting skill pack, and the brain account-reports
bridge. The architecture box-drawing diagram keeps its column alignment.
- Keep TT133 and TT99 (both current): the accounting skill pack teaches
TT99 (enterprises) / TT133 (SMEs).
- Attribute receivable-provision rates to the current doubtful-debt
provisioning regulation generically, not to the accounting regime.
The "200h" effort figure in adr-008 is hours, not a circular, and is left
untouched (ADRs are append-only).
|
Killed
|
|
|
|
|
|
|
|
merged
[ADD] viin_ai_helpdesk, viin_ai_crm: Phase 4 AI connectors (helpdesk seed + CRM advisory tools)
|
[IMP] viin_ai_agent, viin_ai_crm, viin_ai_helpdesk: strip HTML from AI tool payloads
Connector tools fed raw Html-field values (lead/ticket description,
activity note, message body) straight into the payload the LLM reads -
HTML tags are token noise and can confuse the model.
- viin_ai_agent: add _tool_plain_text on ir.actions.server, a sibling of
_tool_result that runs a value through html2plaintext ('' for falsy),
callable from a server-action code body (safe_eval). Mirrors the
existing viin_ai_chat plain-text helper; no viin_brain coupling.
- viin_ai_crm: strip crm.lead.description and mail.activity.note.
- viin_ai_helpdesk: strip viin.helpdesk.ticket.description and
mail.message.body (strip first, then truncate so the cap applies to
plain text).
- Surveyed the other connectors (account/sale/sale_crm/stock) and the
AI/Brain tool surface: no other tool returns a raw Html field
(Brain already returns the content_plain T1 representation).
- Tests: red-green behaviour tests assert the payload value carries no
'<' and preserves the readable text, driven through a real
ir.actions.server.run() as the tool's low-privilege group.
- docs: note the _tool_plain_text sibling next to _tool_result in
ai/architecture.md so future connectors strip Html-field values.
|
Killed
|
|
Not finished
|
|
|
|
|
|
merged
[ADD] viin_ai_helpdesk, viin_ai_crm: Phase 4 AI connectors (helpdesk seed + CRM advisory tools)
|
[IMP] viin_ai_agent, viin_ai_crm, viin_ai_helpdesk: strip HTML from AI tool payloads
Connector tools fed raw Html-field values (lead/ticket description,
activity note, message body) straight into the payload the LLM reads -
HTML tags are token noise and can confuse the model.
- viin_ai_agent: add _tool_plain_text on ir.actions.server, a sibling of
_tool_result that runs a value through html2plaintext ('' for falsy),
callable from a server-action code body (safe_eval). Mirrors the
existing viin_ai_chat plain-text helper; no viin_brain coupling.
- viin_ai_crm: strip crm.lead.description and mail.activity.note.
- viin_ai_helpdesk: strip viin.helpdesk.ticket.description and
mail.message.body (strip first, then truncate so the cap applies to
plain text).
- Surveyed the other connectors (account/sale/sale_crm/stock) and the
AI/Brain tool surface: no other tool returns a raw Html field
(Brain already returns the content_plain T1 representation).
- Tests: red-green behaviour tests assert the payload value carries no
'<' and preserves the readable text, driven through a real
ir.actions.server.run() as the tool's low-privilege group.
|
Killed
|
|
Not finished
|
|
|
|
|
|
merged
[ADD] viin_ai_helpdesk, viin_ai_crm: Phase 4 AI connectors (helpdesk seed + CRM advisory tools)
|
[ADD] viin_ai_helpdesk, viin_ai_crm: Phase 4 AI connectors (helpdesk seed + CRM advisory tools)
Phase 4 (Track C) per-app AI connectors, unlocked by M3:
- viin_ai_helpdesk (NEW): AI connector for viin_helpdesk. Seeds 1 agent
(Helpdesk Assistant) + 1 topic (Helpdesk Triage) + 3 READ-only tools on
viin.helpdesk.ticket: triage_ticket, suggest_canned_response,
generate_faq_from_thread. Data-XML, zero Python (Layer-3 convention).
- viin_ai_crm (IMP): adds 3 advisory READ tools (qualify_lead,
next_action_suggest, email_draft_for_lead) wired into the Lead
Qualification topic.
- All tools: requires_confirmation=False (read-only), runs_as_sudo=False,
group_ids ACL-gated; model_id write-gate satisfied (group has perm_write
on the target model). run()-driven boundary tests prove the safe_eval +
write-gate path.
- docs: AGENTS.md + docs/roadmap.md reflect Phase 4 progress; reconcile a
pre-existing roadmap drift (helpdesk dependency named the Odoo-EE
'helpdesk' module instead of Viindoo 'viin_helpdesk').
|
Killed
|
|
Not finished
|
|
|
|
|
|
merged
[IMP] viin_ai_base, viin_ai_agent: bidirectional data-driven message adapter (close #64 #62 #63)
|
[IMP] viin_ai_base, viin_ai_agent: bidirectional data-driven message adapter (close #64 #62 #63)
Symmetric follow-up to the outgoing adapter (#59): make the INCOMING response
normalizer data-driven via viin.ai.message.adapter, add a per-vendor empty-content
knob, and route the streaming path through the adapter with a contract guard.
- #64: viin.ai.message.adapter gains a `direction` discriminator (outgoing|incoming)
+ incoming response-map knobs; viin.ai.provider._normalize_completion_response is
rewired to dispatch data-driven incoming primitives (output byte-stable for the 3
seeded protocols). An admin can hotfix a vendor response-key rename with no release.
- #62: per-vendor `empty_content_repr` knob (empty_string|null|omit), default
empty_string (byte-identical to prior behaviour) for strict gateways (Azure OpenAI).
- #63: viin_ai_agent._do_llm_stream redacts-then-adapts before transport + a contract
guard test that fails if a future streaming multi-turn path bypasses the adapter
(also patches a latent streaming PII-redaction gap).
- Hardening (post code-review): incoming rows must declare all leaf-key paths
(finish/usage/text/tool); incoming rows for an unsupported protocol are rejected at
write time (no silent mis-parse); clearer parse-error diagnostics; tightened
guard tests (per-location PII, value-switch data-driven proof, assertRaises).
- ADR-018 (bidirectional data-driven message adapter); docs/roadmap/module-map
reconcile (32 modules, PR #57/#59/#60 history, ADR ledger, adr-015/016 status sync).
Tests: Odoo native, no-API-key; 302 non-tour tests green (normalize/wire byte-stable
non-regression + incoming data-driven proof + #62 matrix + #63 guard + multiturn loop
+ new validation guards). flake8 clean on the Runbot lint gate. Pre-existing HttpCase
browser tours need a live http server and fail identically on base 17.0 under --no-http.
Claude-Session: https://claude.ai/code/session_01MpghN1mdjfEzHd1yuSqdut
|
Killed
|
|
|
|
|
|
|
|
merged
[IMP] viin_ai_base, viin_ai_agent: bidirectional data-driven message adapter (close #64 #62 #63)
|
[IMP] viin_ai_base, viin_ai_agent: bidirectional data-driven message adapter (close #64 #62 #63)
Symmetric follow-up to the outgoing adapter (#59): make the INCOMING response
normalizer data-driven via viin.ai.message.adapter, add a per-vendor empty-content
knob, and route the streaming path through the adapter with a contract guard.
- #64: viin.ai.message.adapter gains a `direction` discriminator (outgoing|incoming)
+ incoming response-map knobs; viin.ai.provider._normalize_completion_response is
rewired to dispatch data-driven incoming primitives (output byte-stable for the 3
seeded protocols). An admin can hotfix a vendor response-key rename with no release.
- #62: per-vendor `empty_content_repr` knob (empty_string|null|omit), default
empty_string (byte-identical to prior behaviour) for strict gateways (Azure OpenAI).
- #63: viin_ai_agent._do_llm_stream redacts-then-adapts before transport + a contract
guard test that fails if a future streaming multi-turn path bypasses the adapter
(also patches a latent streaming PII-redaction gap).
- Hardening (post code-review): incoming rows must declare all leaf-key paths
(finish/usage/text/tool); incoming rows for an unsupported protocol are rejected at
write time (no silent mis-parse); clearer parse-error diagnostics; tightened
guard tests (per-location PII, value-switch data-driven proof, assertRaises).
- ADR-018 (bidirectional data-driven message adapter); docs/roadmap/module-map
reconcile (32 modules, PR #57/#59/#60 history, ADR ledger, adr-015/016 status sync).
Tests: Odoo native, no-API-key; 302 non-tour tests green (normalize/wire byte-stable
non-regression + incoming data-driven proof + #62 matrix + #63 guard + multiturn loop
+ new validation guards). Pre-existing HttpCase browser tours need a live http server
and fail identically on base 17.0 under --no-http (not part of this change).
Claude-Session: https://claude.ai/code/session_01MpghN1mdjfEzHd1yuSqdut
|
Failed
|
|
|
|
|
|
|
|
merged
[IMP] viin_ai_base, viin_ai_agent: bidirectional data-driven message adapter (close #64 #62 #63)
|
[IMP] viin_ai_base, viin_ai_agent: bidirectional data-driven message adapter (close #64 #62 #63)
Symmetric follow-up to the outgoing adapter (#59): make the INCOMING response
normalizer data-driven via viin.ai.message.adapter, add a per-vendor empty-content
knob, and route the streaming path through the adapter with a contract guard.
- #64: viin.ai.message.adapter gains a `direction` discriminator (outgoing|incoming)
+ incoming response-map knobs; viin.ai.provider._normalize_completion_response is
rewired to dispatch data-driven incoming primitives (output byte-stable for the 3
seeded protocols). An admin can hotfix a vendor response-key rename with no release.
- #62: per-vendor `empty_content_repr` knob (empty_string|null|omit), default
empty_string (byte-identical to prior behaviour) for strict gateways (Azure OpenAI).
- #63: viin_ai_agent._do_llm_stream redacts-then-adapts before transport + a contract
guard test that fails if a future streaming multi-turn path bypasses the adapter
(also patches a latent streaming PII-redaction gap).
- ADR-018 (bidirectional data-driven message adapter); docs/roadmap/module-map
reconcile (32 modules, PR #57/#59/#60 history, ADR ledger, adr-015/016 status sync).
Tests: Odoo native, no-API-key; 74-class net green (normalize/wire byte-stable
non-regression + incoming data-driven proof + #62 matrix + #63 guard + multiturn loop).
Claude-Session: https://claude.ai/code/session_01MpghN1mdjfEzHd1yuSqdut
|
Failed
|
|
|
|
|
|
|
|
merged
[ADD] KG temporal Wave-2 (ADR-006): _as_of reconstruction + live KG tools + memory-brain bridge
|
[FIX] viin_ai_brain: revert record_historian as-of boundary to inclusive-at-ts + lock-in test
verify2 (review iter-2) flagged a silent, undocumented boundary flip in
record_historian._as_of_record Step-4: the tracking-message revert filter had
been changed from ('date','>',ts) to '>=', making a change stamped exactly at
ts get reverted (exclusive-at-ts) - the opposite of the whole-codebase
convention (viin_brain._find_active_at inclusive-at-ts; memory recall <= as_of;
the Step-2 create_date boundary in the same method). "State as of ts" must
reflect a change effective at ts, so revert only strictly-after-ts changes.
- record_historian.py: ('date','>=',ts) -> ('date','>',ts) + convention comment.
- test_record_historian.py: add boundary-exact lock-in test H7
(RED under '>=' AssertionError partner_before reverted; GREEN under '>').
Claude-Session: https://claude.ai/code/session_01EVjERtZ9dnk5fhZHns8vLv
|
Killed
|
|
|
|
|
|
|
|
merged
[ADD] KG temporal Wave-2 (ADR-006): _as_of reconstruction + live KG tools + memory-brain bridge
|
[FIX] viin_ai: PR #60 review-2 - W8150 lint blocker + record_state_as_of ACL guard + temporal test hardening
- viin_ai_brain: fix Runbot test_pylint W8150 (module-level relative import in
test_record_historian.py); add caller-env ACL gate (check_access_rights/rule)
before record_state_as_of reconstruction, return {} on AccessError; RED-GREEN
test as low_priv; perm_write=1 lock-in test + rationale.
- viin_ai_memory: neutralize-proof UUID tokens in as-of recall tests; defensive
str as_of normalize via fields.Datetime.to_datetime + cross-module contract comment.
- viin_brain: boundary-exact active-at fixtures (valid_to==ts / valid_from==ts)
guarding the inclusive operator; expression.AND for temporal domain combine.
- viin_ai_memory_brain: explicit required=False/default=False on vault_id.
- docs: propagate _search_active_at -> _find_active_at; correct stale 2-condition
active-at domain to the shipped 3-condition predicate (ADR-006 append-only Wave-2 note).
Claude-Session: https://claude.ai/code/session_01EVjERtZ9dnk5fhZHns8vLv
|
Killed
|
|
Not finished
|
|
|
|
|
|
merged
[ADD] KG temporal Wave-2 (ADR-006): _as_of reconstruction + live KG tools + memory-brain bridge
|
[FIX] viin_ai: PR #60 review-2 - W8150 lint blocker + record_state_as_of ACL guard + temporal test hardening
- viin_ai_brain: fix Runbot test_pylint W8150 (module-level relative import in
test_record_historian.py); add caller-env ACL gate (check_access_rights/rule)
before record_state_as_of reconstruction, return {} on AccessError; RED-GREEN
test as low_priv; perm_write=1 lock-in test + rationale.
- viin_ai_memory: neutralize-proof UUID tokens in as-of recall tests; defensive
str as_of normalize via fields.Datetime.to_datetime + cross-module contract comment.
- viin_brain: boundary-exact active-at fixtures (valid_to==ts / valid_from==ts)
guarding the inclusive operator; expression.AND for temporal domain combine.
- viin_ai_memory_brain: explicit required=False/default=False on vault_id.
- docs: propagate _search_active_at -> _find_active_at; correct stale 2-condition
active-at domain to the shipped 3-condition predicate (ADR-006 append-only Wave-2 note).
Claude-Session: https://claude.ai/code/session_01EVjERtZ9dnk5fhZHns8vLv
|
Killed
|
|
Not finished
|
|
|
|
|
|
merged
[FIX] viin_ai_base: provider-native outgoing message adapter (#59)
|
[FIX] viin_ai_base: provider-native outgoing message adapter (#59)
The agentic tool loop shipped turn-2 canonical history (assistant tool_calls,
tool role tool_results) to the wire verbatim - no outgoing adapter existed, only
an incoming normalizer. A real tool-using turn returned HTTP 400 on
anthropic_native/openai_compat and silently dropped the tool result on
google_native. The same payload builder dropped the system prompt on all 3
protocols, and the PII redactor skipped tool-turn free-text (tool_calls
arguments, tool_results result/error).
Add a data-driven, UI-editable viin.ai.message.adapter (protocol-keyed with an
optional vendor override, noupdate seed) that reshapes the canonical history into
each provider's native wire format via vetted code primitives - zero eval/template
on the BYOK egress path. A write-time coherence constraint rejects incoherent
(protocol, shape/strategy) admin edits. System-prompt placement is handled per
protocol (anthropic top-level system, google systemInstruction, openai
role=system) with the system kwarg as the single source of truth, which also
fixes viin_ai_search Path B on anthropic/google. PII redaction is extended to
tool-turn free-text and runs before the adapt step (redact-then-adapt).
Add honest tests that stub only the transport seam and assert the built outgoing
payload per protocol (the seam #59 slipped through), plus data-driven,
coherence-gate, and PII-redaction tests.
Claude-Session: https://claude.ai/code/session_0128GTfwboHEZqJZ5xgfkxoL
|
Killed
|
|
|
|
|
|
|
|
merged
[ADD] KG temporal Wave-2 (ADR-006): _as_of reconstruction + live KG tools + memory-brain bridge
|
[FIX] viin_ai: address PR #60 review (temporal_diff ACL, BFS N+1, as-of test gaps, conventions)
H-A: add ACL post-filter in tool_brain_temporal_diff - batch-search readable
page ids after edge set-diff, drop edges where either endpoint is unreadable
(same D6 fix class applied to graph_traverse in Wave-1).
H-B: batch the fallback BFS _acl_filter call - collect all candidate to_page
ids per BFS step BEFORE the ACL check (single Page.search per step, not one
per link, mirroring the primary delegate path).
H-C: add test_observation_recall_as_of_filters - protects the third temporal
leg (created_at <= as_of on observations); RED-then-GREEN verified.
M1: rename _search_active_at -> _find_active_at in viin.brain.link and all
call sites in brain_tools.py and tests (avoids ORM _search_<field> prefix
collision, no active_at field exists).
M2: fix assertIsNotNone(link_a.superseded_at) -> assertTrue (Odoo Datetime
null is False, not None; assertIsNotNone(False) passes silently).
M3: replace (6, 0, [...]) legacy tuples with Command.set([...]) in
viin_ai_memory_brain/tests/test_vault_id_isolation.py (AGENTS.md #7).
M4: move imports (datetime, fields.Datetime/Date) from inside function body
to module top-level in brain_tools.py (python.md imports rule).
Claude-Session: https://claude.ai/code/session_01JTYAzu8ndxtrQGJeTNa3pf
|
Failed
|
|
|
|
|
|
|
|
merged
[ADD] KG temporal Wave-2 (ADR-006): _as_of reconstruction + live KG tools + memory-brain bridge
|
[ADD] viin_ai_memory_brain: AI memory <-> Brain vault bridge (KG temporal Wave-2)
New auto-install bridge (depends viin_ai_memory + viin_brain). Adds an
optional vault_id Many2one('viin.brain.vault') to viin.ai.memory so a memory
can be scoped to a Brain vault, plus a GLOBAL ir.rule that restricts memory
visibility to vaults the user can access (member or access-group), while
vault-less memories remain governed by the existing per-owner rule.
The vault rule is GLOBAL (AND-combines = restricts), not non-global: a
non-global rule with an OR(vault_id=False, ...) disjunct would OR-union with
the owner rule and leak every vault-less memory across owners. Tests cover
cross-vault, cross-company, owner-only vault-less, and the cross-owner
vault-less regression.
Part of ADR-006 KG temporal Wave-2.
Claude-Session: https://claude.ai/code/session_01JTYAzu8ndxtrQGJeTNa3pf
|
Failed
|
|
|
|
|
|
|
|
merged
[REF] viin_ai: standardize AI tool server-action return envelope as ir.actions.client
|
[REF] viin_ai_stock: return AI tool results via the standard envelope helper
The 3 stock tools (get_stock_level, get_low_stock_products, get_product_moves)
now use env['ir.actions.server']._tool_result(payload); tests assert the
ir.actions.client envelope (tag viin_ai_tool_result) under params['data'].
Claude-Session: https://claude.ai/code/session_0128GTfwboHEZqJZ5xgfkxoL
|
Killed
|
|
Not finished
|
|
|
|
|
|
merged
[FIX] viin_ai_account/stock: ADR-012 seed runtime crashes + review-driven hardening
|
[IMP] viin_brain: reconcile linkable docstring with ADR-012 carrier reality
The viin_brain_linkable docstring still claimed the per-app bridges "explicitly
inherit this mixin" (their concrete models were deleted) and that "WI-7 will set
installable:False" (contradicted by the ADR-012 revive). Correct both claims; the
_brain_form_sidebar flag and all logic are untouched.
Claude-Session: https://claude.ai/code/session_01JTYAzu8ndxtrQGJeTNa3pf
|
Killed
|
|
|
|
|
|
|
|
merged
[REF] viin_ai: standardize AI tool server-action return envelope as ir.actions.client
|
[REF] viin_ai_search: tidy stale arguments wording in web_query tool comment/docstring
Replace residual 'tool_web_query(arguments)' prose (which implied 'arguments'
is a safe_eval dispatch-scope variable) with 'tool_web_query(...)'. The bare
'arguments' is the method parameter name, not a server-action context variable.
Comment/docstring only - no behavior change.
Claude-Session: https://claude.ai/code/session_0128GTfwboHEZqJZ5xgfkxoL
|
Killed
|
|
|
|
|
|
|
|
merged
[REF] viin_ai: standardize AI tool server-action return envelope as ir.actions.client
|
[REF] viin_ai_search: return web_query result via the standard envelope helper
Rewrite the web_query server-action body to build its result through
`env['ir.actions.server']._tool_result(...)`, returning a valid
ir.actions.client action instead of the non-standard `tool_result` dict.
Update the header comment and the server-action test to assert the new
envelope while preserving the domain/fallback_used assertions.
|
Killed
|
|
Not finished
|
|
|
|
|
|
merged
[IMP] ADR-012: per-app seed master data - 9 modules (AI connectors + Brain bridges)
|
[DOC] AGENTS,docs,README: reconcile full ADR-012 per-app seed (9 modules) + correct tool names + viin_brain_sale rename
|
Killed
|
|
|
|
|
|
|
|
merged
[IMP] ADR-012: per-app seed master data - 9 modules (AI connectors + Brain bridges)
|
[DOC] AGENTS,docs,README: reconcile ADR-012 CRM+Sale seed state + viin_brain_sale rename across docs
|
Killed
|
|
Not finished
|
|
|
|
|
|
merged
[FIX] viin_ai_brain: tool server-actions read args from context (fix NameError through agent loop)
|
[FIX] viin_ai_search: correct stale tool-args injection comment
The comment claimed `viin_ai_tool_args` is mapped to `arguments` via a
`_get_eval_context` override; no such override exists. The server-action
already reads its arguments via env.context.get('viin_ai_tool_args', {}).
Comment only - no code change.
|
Killed
|
|
Not finished
|
|
|
|
|
|
merged
[IMP] ADR-012: per-app seed master data - 9 modules (AI connectors + Brain bridges)
|
[DOC] AGENTS,docs,README: reconcile ADR-012 CRM+Sale seed state + viin_brain_sale rename across docs
|
Revoked
|
|
|
|
|
|
|
|
merged
[IMP] ADR-012: per-app seed master data - 9 modules (AI connectors + Brain bridges)
|
[DOC] AGENTS,docs,viin_brain: rename viin_brain_sale_management -> viin_brain_sale references + ADR-012 addendum
|
Killed
|
|
Not finished
|
|
|
|
|
|
merged
[IMP] ADR-012: per-app seed master data - 9 modules (AI connectors + Brain bridges)
|
[IMP] viin_ai_sale_crm: cross-domain handoff topic + targeted auto_install (ADR-012)
|
Killed
|
|
Not finished
|
|
|
|
|
|
merged
[ADD] AI Cognitive Wave-1: Memory L0-L3 + Skill runtime + Pulse cost gate + KG temporal (supersedes #53)
|
[FIX] viin_ai: clear Runbot errors and warnings (PR #54)
Resolve every Runbot build error and warning on the Cognitive Wave-1
branch without masking any behavior. Each fix is root-cause proven and
verified by a real Odoo 17 test run on a fresh DB (--skip-auto-install).
- viin_ai_chat: fix stale mock signature in test_user_error_passed_through.
_user_err now matches _collect_allowed_tools(self, applied_skills=None),
which viin_ai_skill's _resolve_run_skills override calls positionally.
This was the only build-breaking failure.
- viin_ai_base: guard the _record_error_usage separate-cursor write so a
provider_id/model_id not yet visible to that cursor is set NULL instead
of raising a ForeignKeyViolation. Removes the odoo.sql_db ERROR noise
while preserving the trace-durability invariant. Add a regression test
that verifies via a fresh cursor (the row is committed by a separate
cursor, invisible to the REPEATABLE READ test cursor).
- viin_ai_approval: remove the dead advisory tool ACL-gap warning in
_advisory_agent_has_tools (unreachable - every caller runs sudo, so it
could never detect a real gap). Assert the H8 executable-tools refusal
warning via assertLogs. Add mail_notify_force_send=False to
TestAdvisoryInfra.setUpClass.
- viin_ai_memory: align the promotion.log / observation owner ir.rule perms
with ir.model.access.csv (promotion.log read-only, observation
append-only), clearing the to_base record-rule validator warning. Add
ACL regression tests driven via with_user. Downgrade the BYOK
no-provider summarize-skip log from WARNING to INFO (expected
steady-state when no key is configured), and keep the cron test asserting
its real contract (zero external call) rather than a data-state-dependent
log.
- viin_ai_agent: assert the sudo-escalation refusal security warning via
assertLogs so the expected signal is captured, not leaked to the log.
- viin_ai_ops / viin_ai_ops_brain / viin_ai_approval_sale: add the
mail_notify_force_send=False test-context guard (OpsBaseTestCase and the
evidence/advisory-sale test classes) so confirm/route/notify flows do not
attempt a synchronous mail send that fails on a runner with no
mail.catchall ICP. These tests assert routing/state, not email delivery.
|
Killed
|
|
|
|
|
|
|
|
merged
[ADD] AI Cognitive Wave-1: Memory L0-L3 + Skill runtime + Pulse cost gate + KG temporal (supersedes #53)
|
[FIX] viin_ai: clear Runbot errors and warnings (PR #54)
Resolve every Runbot build error and warning on the Cognitive Wave-1
branch without masking any behavior. Each fix is root-cause proven and
verified by a real Odoo 17 test run on a fresh DB (--skip-auto-install).
- viin_ai_chat: fix stale mock signature in test_user_error_passed_through.
_user_err now matches _collect_allowed_tools(self, applied_skills=None),
which viin_ai_skill's _resolve_run_skills override calls positionally.
This was the only build-breaking failure.
- viin_ai_base: guard the _record_error_usage separate-cursor write so a
provider_id/model_id not yet visible to that cursor is set NULL instead
of raising a ForeignKeyViolation. Removes the odoo.sql_db ERROR noise
while preserving the trace-durability invariant (the error usage.log is
still committed independently). Add a regression test that verifies via
a fresh cursor.
- viin_ai_approval: remove the dead advisory tool ACL-gap warning in
_advisory_agent_has_tools (unreachable - every caller runs sudo, so it
could never detect a real gap); this clears the false-positive log.
Assert the H8 executable-tools refusal warning via assertLogs instead of
letting it leak. Add mail_notify_force_send=False to
TestAdvisoryInfra.setUpClass to stop the mail.catchall send ERROR.
- viin_ai_memory: align the promotion.log / observation owner ir.rule perms
with ir.model.access.csv (promotion.log read-only, observation
append-only), clearing the to_base record-rule validator warning. Assert
the BYOK no-provider skip warning via assertLogs. Add ACL regression
tests driven via with_user.
- viin_ai_agent: assert the sudo-escalation refusal security warning via
assertLogs so the expected signal is captured, not leaked to the log.
|
Failed
|
|
|
|
|
|
|
|
merged
[ADD] AI Cognitive Wave-1: Memory L0-L3 + Skill runtime + Pulse cost gate + KG temporal (supersedes #53)
|
[FIX] viin_ai: clear Runbot errors and warnings (PR #54)
Resolve every Runbot build error and warning on the Cognitive Wave-1
branch without masking any behavior. Each fix is root-cause proven and
verified by a real Odoo 17 test run on a fresh DB (--skip-auto-install).
- viin_ai_chat: fix stale mock signature in test_user_error_passed_through.
_user_err now matches _collect_allowed_tools(self, applied_skills=None),
which viin_ai_skill's _resolve_run_skills override calls positionally.
This was the only build-breaking failure.
- viin_ai_base: guard the _record_error_usage separate-cursor write so a
provider_id/model_id not yet visible to that cursor is set NULL instead
of raising a ForeignKeyViolation. Removes the odoo.sql_db ERROR noise
while preserving the trace-durability invariant (the error usage.log is
still committed independently). Add a regression test that verifies via
a fresh cursor.
- viin_ai_approval: remove the dead advisory tool ACL-gap warning in
_advisory_agent_has_tools (unreachable - every caller runs sudo, so it
could never detect a real gap); this clears the false-positive log.
Assert the H8 executable-tools refusal warning via assertLogs instead of
letting it leak. Add mail_notify_force_send=False to
TestAdvisoryInfra.setUpClass to stop the mail.catchall send ERROR.
- viin_ai_memory: align the promotion.log / observation owner ir.rule perms
with ir.model.access.csv (promotion.log read-only, observation
append-only), clearing the to_base record-rule validator warning. Assert
the BYOK no-provider skip warning via assertLogs. Add ACL regression
tests driven via with_user.
- viin_ai_agent: assert the sudo-escalation refusal security warning via
assertLogs so the expected signal is captured, not leaked to the log.
|
Failed
|
|
|
|
|
|
|
|
merged
[ADD] AI Cognitive Wave-1: Memory L0-L3 + Skill runtime + Pulse cost gate + KG temporal (supersedes #53)
|
[DOC] docs,AGENTS: reconcile Cognitive Wave-1 + ADR status drift
ADR-009 ratified; module maps + roadmap + AGENTS.md status; ADR-015/016
append-only Accepted; testing.md verify cmd.
|
Failed
|
|
|
|
|
|
|
|
merged
[ADD] AI Cognitive Wave-1: Memory L0-L3 + Skill runtime + Pulse cost gate + KG temporal (supersedes #53)
|
[DOC] docs,AGENTS: reconcile Cognitive Wave-1 + ADR status drift
ADR-009 ratified; module maps + roadmap + AGENTS.md status; ADR-015/016
append-only Accepted; testing.md verify cmd. (= PR #53 docs reconcile.)
|
Killed
|
|
Not finished
|
|
|
|
|
|
closed
[ADD] Phase 3.9 Cognitive Wave-1: Memory + Skill + KG temporal + Pulse + CoWork bundle
|
[DOC] docs,AGENTS: reconcile Cognitive Wave-1 + ADR status drift (PR #53)
PR #53 (Cognitive Wave-1) shipped viin_ai_memory/skill/pulse + KG temporal
signature + CoWork 5-pack and ratified ADR-009, but the living status docs
stayed stale. Reconcile across the count-bearing + map docs:
- AGENTS.md §3: Track A now reflects M3 achieved (PR #50) + P-OPS-3/4 shipped;
Phase 3.9 Cognitive Wave-1 marked shipped (PR #53), not future.
- AGENTS.md §2 + docs/ai/architecture.md: add viin_ai_memory/skill/pulse
(+ viin_ai_workflow) to the module / dependency maps with real depends.
- docs/roadmap.md: ADR-009 footnotes/open-list resolved (3 separate modules,
Accepted PR #53); W13-W17 drift-note (Wave-1 code shipped); ADR counts
reconciled to 16 ADR (14 accepted + 2 proposed).
- docs/decisions/README.md: ADR-015/016 status proposed -> accepted (PR #47);
index date bumped.
- adr-015/adr-016: append-only Status update line (Accepted, PR #47).
- docs/ai/testing.md: add the 3 cognitive modules to the no-key verify command.
Docs-only, no code touched.
|
Killed
|
|
Not finished
|
|
|
|
|
|
closed
[ADD] Phase 3.9 Cognitive Wave-1: Memory + Skill + KG temporal + Pulse + CoWork bundle
|
[FIX] viin_ai_memory,viin_ai_skill: Runbot lint (default manifest key + W391)
- viin_ai_memory/__manifest__.py: remove auto_install=False (equals the default;
the Viindoo manifest linter test_manifests rejects redundant default keys).
- viin_ai_skill/tests/test_cowork_bundle.py: strip trailing blank line (flake8 W391).
|
Killed
|
|
Not finished
|
|
|
|
|
|
closed
[ADD] Phase 3.9 Cognitive Wave-1: Memory + Skill + KG temporal + Pulse + CoWork bundle
|
[FIX] viin_ai cluster,viin_brain: full-width text fields across form views (colspan sweep)
Repo-wide sweep of the same layout bug fixed earlier: a free-text/tag field
that is the sole (or last) child of a default two-column <group> renders
squeezed into a one-character-wide column. The canonical Odoo idiom is
colspan="2" (core sale_order_views.xml note field). Added it to 8 more fields:
- viin_ai_agent: system_prompt (agent form), ai_prompt (ir.actions.server form)
- viin_ai_base: final_response (trace form)
- viin_ai_ops: payload (action proposal form), description (goal form)
- viin_ai_approval: prompt_snapshot (action proposal form)
- viin_brain: ambiguous_candidate_ids (link form)
- viin_ai_skill: description (skill pack form)
Pure view-XML (no SCSS/JS). Found by a form-view scan, pre-checked for layout
edge cases (all default col=2 groups; no sibling-field regression), and
verified full-width by live render after -u.
|
Failed
|
|
|
|
|
|
|
|
closed
[ADD] Phase 3.9 Cognitive Wave-1: Memory + Skill + KG temporal + Pulse + CoWork bundle
|
[FIX] viin_ai_skill,viin_ai_memory,viin_ai_pulse: full-width text fields in form views
The Level-1/Level-2 description fields (skill), the summary (memory) and the
signal payload/evidence fields rendered squeezed into a one-character-wide
column. A nolabel field inside a default two-column <group> lands in the narrow
label slot; the canonical Odoo idiom (e.g. sale.order note, sale_order_views.xml)
is to add colspan="2" so the field spans the full group width.
- viin_ai_skill: description, manifest_text
- viin_ai_memory: summary, access_group_ids
- viin_ai_pulse: signal payload, evidence_refs
Pure view-XML fix (no SCSS/JS). Verified full-width by live render.
|
Failed
|
|
|
|
|