diff --git a/ROADMAP.md b/ROADMAP.md index 19c3fc8..d106d97 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -1,6 +1,8 @@ # Mira roadmap -**Current October28:** #91 merged a461f86. Its exact rollout c42efc65 passed startup and the normal how-to smoke. The broken-device reply preserved earlier restarts and delivered the full case privately, but applied Limitless-specific guidance without identifying the hardware. Independent review classified that as failed source applicability; rollback toa9c9508/a6ef6b22 is verified healthy and the third smoke held. #90 integrates #91:1,258/offline8 and independent240-check review pass; final-head review/CI precede merge. This does not fix unknown source applicability or produce a new generated score. Hold further releases while #83 receives a general offline repair and required review; no paid run, memory enablement or customer-resolution claim. Scores64/100 implementation and56/100 delivery remain unchanged. +**October29 current checkpoint:** Main cffb46b; successful rollback baseline a9c9508/a6ef6b22, one active and auto-deploy off on the fresh read. #90 metadata provenance does not enforce hardware applicability; do not deploy it as the failed smoke’s repair. Three open drafts: #92 bounded current-contact actor, #93 production metadata trace (1,266 full/8 offline, independent review, exact-head CI40918151890 PASS), #94 evidence policy/adversarial checks (1,266 full/8 policy groups and independent scoped review pass, but refund-approval and hardware-applicability probes remain genuinely red). #94 policy is not installed or required on main yet; branch protection/rule reads show no effective requirements. The master plan records installation/accuracy limits. No paid run, merge, deployment, optional enablement or new Discord test; third smoke held. Scores64/56 unchanged. Older checkpoints below are history where superseded. + +**Current October28:** #91 merged a461f86, then its rollout failed source applicability despite passing context preservation/private delivery. Rollback baseline a9c9508/a6ef6b22 is verified healthy. #90 merged cffb46b after1,258 tests,8 no-model checks, independent integration/final review and exact-head/merged-main Node20/24/PostgreSQL CI; it is not deployed. The earlier PR queue is closed; one new current-contact draft is being prepared under #83. #83 now has three red synthetic reviewer diagnostics plus a passing ordinary-answer control, and an actual-handler unresolved-FAQ failure plus useful-detail control. These are offline injected diagnostics, not an implemented applicability repair or live-model accuracy. The October29 draft preserves a bounded current contact next actor through the existing redirect owner and shared escalation policy; no new model field, prompt or store. Its final review/CI and applicable quality gate remain. Trustworthy source applicability and arbitrary contradiction resolution are still open; this draft does not repair the failed hardware smoke. Further releases and the third smoke remain held; no paid run or memory enablement. Scores64/100 implementation and56/100 delivery unchanged. **Earlier October26 checkpoint:** #86 merged647b549 after1202/no-model8, exact-head hosted Node20/24/real PostgreSQL, independent review and merged-main CI. [Lifecycle details](docs/GITHUB_NOTICE_LIFECYCLE.md). The old PR backlog is cleared; new work is Mira repository presentation and local #83 source provenance/conflict handling. #62 stays open for reproduced narration/context loss despite merged diagnostics. Production stays c6f482d; no paid run, public Omi test issue or memory enablement. Main implementation64/100; delivery56/100;44 left. Technical identifiers remain unchanged under the Mira product name. diff --git a/docs/ANSWER_QUALITY_CONTRACT.md b/docs/ANSWER_QUALITY_CONTRACT.md index 362ee67..50cf66a 100644 --- a/docs/ANSWER_QUALITY_CONTRACT.md +++ b/docs/ANSWER_QUALITY_CONTRACT.md @@ -1,10 +1,13 @@ # Customer answer quality: repair checklist +**October30 status clarification:** Older dated diagnostics below describe their tested commits, not current refund-filter implementation. #95 financial filtering is merged on main9b7154d and not deployed; #96 device applicability and #94 acceptance/enforcement remain pending. #92 is a narrow current-contact handoff repair, not general #83 completion. Use SUPPORT_MASTER_PLAN.md for current gates and avoid treating historical probe results as present implementation. + + Updated October 26, 2026. This is an implementation contract, **not a claim that these checks are all built or live**. It extends A1/A2/A4, B2 and E2 in the [master plan](SUPPORT_MASTER_PLAN.md); memory and the reviewed improvement loop keep their existing gates. ## Priority and status -The [master plan](SUPPORT_MASTER_PLAN.md) takes precedence. The old PR queue is cleared; #71/#75/#82 closed unmerged with unresolved requirements retained. #91 context preservation is merged at a461f86; its rollout failed source applicability and was rolled back. Context/delivery passed, but that does not waive the failed grounding check. #90 provenance integrates that main and awaits final review/CI; the frozen staff-flagging defect is rejected by both integrated #90 and current main. Shared unresolved-next-step/applicability weaknesses remain #83; no new paid run is authorized by these implementation checks. Preserve the maximum of three open PRs. +The [master plan](SUPPORT_MASTER_PLAN.md) takes precedence. The old PR queue is cleared; #71/#75/#82 closed unmerged with unresolved requirements retained. #91 context preservation is merged at a461f86; its rollout failed source applicability and was rolled back. Context/delivery passed, but that does not waive the failed grounding check. #90 provenance is merged as cffb46b after final review/CI; the frozen staff-flagging defect is rejected by both integrated #90 and current main. Shared unresolved-next-step/applicability weaknesses remain #83; no new paid run is authorized by these implementation checks. Preserve the maximum of three open PRs. | Order | Customer failure to prevent | Required regression / acceptance | State | | --- | --- | --- | --- | @@ -45,3 +48,8 @@ One customer problem per draft PR. Record baseline failure, passing checks at th ### Relative merge gate — Aryan's October 26 direction Require no material final-answer failure absent from main, no tested protected-handoff regression, and a candidate pass count at least as high as main. Zero material failures is not the gate; track inherited weaknesses separately. Compare final replies/decisions, not a main draft later corrected by review. Preserve frozen grades. Reusing earlier generated evidence requires demonstrated relevant source/runtime/config identity and full saved results; review the restored diff and pass current checks. This grants no new provider quota, deployment, optional enablement or risk waiver. + + +## October29 diagnostic coverage, not accuracy completion + +#90 is merged but remains unreleased because declared provenance is not an enforced device-applicability verdict. New draft #94 adds six original fictional no-model boundary stress probes through production owners. Customer instruction role separation, off-topic suppression/person protection, invented staff receipt and ordinary sourced-answer controls pass. Refund-approval text and unidentified-hardware guidance remain actual acceptance failures; CI must stay blocked until a general repair makes those assertions pass with relevant controls/review. Injected hostile replies test application acceptance, not live-model injection resistance or protected-set coverage. #93’s metadata trace is a separate observation-only draft; no customer/model text is logged and no quality point is earned. #92 remains a partial next-actor repair. The maximum of three open PRs is reached and the third smoke/release remain held. diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 039e112..336a4c9 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -1,6 +1,8 @@ # Mira architecture -**Current October28:** #91 merged a461f86. Its exact rollout c42efc65 passed startup and the normal how-to smoke. The broken-device reply preserved earlier restarts and delivered the full case privately, but applied Limitless-specific guidance without identifying the hardware. Independent review classified that as failed source applicability; rollback toa9c9508/a6ef6b22 is verified healthy and the third smoke held. #90 integrates #91:1,258/offline8 and independent240-check review pass; final-head review/CI precede merge. This does not fix unknown source applicability or produce a new generated score. Hold further releases while #83 receives a general offline repair and required review; no paid run, memory enablement or customer-resolution claim. Scores64/100 implementation and56/100 delivery remain unchanged. +**October29 current checkpoint:** Main cffb46b; successful rollback baseline a9c9508/a6ef6b22, one active and auto-deploy off on the fresh read. #90 metadata provenance does not enforce hardware applicability; do not deploy it as the failed smoke’s repair. Three open drafts: #92 bounded current-contact actor, #93 production metadata trace (1,266 full/8 offline, independent review, exact-head CI40918151890 PASS), #94 evidence policy/adversarial checks (1,266 full/8 policy groups and independent scoped review pass, but refund-approval and hardware-applicability probes remain genuinely red). #94 policy is not installed or required on main yet; branch protection/rule reads show no effective requirements. The master plan records installation/accuracy limits. No paid run, merge, deployment, optional enablement or new Discord test; third smoke held. Scores64/56 unchanged. Older checkpoints below are history where superseded. + +**Current October28:** #91 merged a461f86, then its rollout failed source applicability despite passing context preservation/private delivery. Rollback baseline a9c9508/a6ef6b22 is verified healthy. #90 merged cffb46b after1,258 tests,8 no-model checks, independent integration/final review and exact-head/merged-main Node20/24/PostgreSQL CI; it is not deployed. The earlier PR queue is closed; one new current-contact draft is being prepared under #83. #83 now has three red synthetic reviewer diagnostics plus a passing ordinary-answer control, and an actual-handler unresolved-FAQ failure plus useful-detail control. These are offline injected diagnostics, not an implemented applicability repair or live-model accuracy. The October29 draft preserves a bounded current contact next actor through the existing redirect owner and shared escalation policy; no new model field, prompt or store. Its final review/CI and applicable quality gate remain. Trustworthy source applicability and arbitrary contradiction resolution are still open; this draft does not repair the failed hardware smoke. Further releases and the third smoke remain held; no paid run or memory enablement. Scores64/100 implementation and56/100 delivery unchanged. **Earlier October26 checkpoint:** #86 merged647b549 after1202/no-model8, exact-head hosted Node20/24/real PostgreSQL, final independent review and merged-main CI. Its30-day subject-time replay guard, customer erasure and non-starvable cleanup are on main, awaiting release. [Lifecycle details](GITHUB_NOTICE_LIFECYCLE.md). Production stays c6f482d; no paid run, public Omi test issue or memory enablement. The product name is Mira; technical identifiers are stable. Separate #83 source-provenance work is local and not an accuracy claim. diff --git a/docs/RUNBOOK.md b/docs/RUNBOOK.md index 7672798..4bb55a9 100644 --- a/docs/RUNBOOK.md +++ b/docs/RUNBOOK.md @@ -1,6 +1,11 @@ # Mira operations runbook -**Current October28 operator receipt:** #91 mergeda461f868ad097ec93512aeaf111d63f4e4c96997 and was deployed asc42efc65-0efb-4ca2-adca-f5f93627b37f, created20:05:37IST. Exact merged-main CI, rollback availability/cadence/source/off-state preflight, startup/health/schema/login and one running instance passed. Normal phone-only how-to smoke passed. The second smoke preserved the symptom/earlier attempts and delivered one matching private staff card, but improperly applied Limitless-specific guidance to unidentified hardware. Independent review called this a grounding failure. Under Aryan's failure rule, deploymentRollback of verified914a38f0/a9c9508 returnedtrue. Replacementa6ef6b22-26b3-4744-ab8d-e067311ff7da/a9c9508, createdOctober28 at20:27:42IST, is SUCCESS/latest/one running; health/schema/login pass with zero matched startup failures and optional/automatic deployment controls off. Earliest cadence-only window isOctober29 at20:27:42IST; applicability repair/review remains a separate release hold. Third smoke and further releases are held. #90 is not deployed. No environment/settings changes, paid rerun, memory enablement or agent Discord posts. [Master plan](SUPPORT_MASTER_PLAN.md) controls current status. +**October30 current checkpoint:** GitHub main9b7154d includes #90 provenance, #93 trace and #95 financial-outcome filtering. Live remains verified rollback a9c9508/a6ef6b22; nothing from that newer main is deployed. #92 current-contact integration passes local1,290/8 plus independent runtime review; current-head CI and final docs disposition precede merge. #96 device applicability is draft for deterministic/accuracy gates; reviewer requires a specifically approved paid comparison after repairs. #94 remains draft until fixes and exact-current checks pass; required-check installation is reserved to Aryan. Three open PRs are #92/#94/#96. No quota, deployment, optional feature or Discord input is activated by this checkpoint. [Master plan](SUPPORT_MASTER_PLAN.md) controls current status; earlier checkpoints retain history only. + + +**Historical October29 checkpoint (superseded below and by the master plan):** Main cffb46b; successful rollback baseline a9c9508/a6ef6b22, one active and auto-deploy off on the fresh read. #90 metadata provenance does not enforce hardware applicability; do not deploy it as the failed smoke’s repair. Three open drafts: #92 bounded current-contact actor, #93 production metadata trace (1,266 full/8 offline, independent review, exact-head CI40918151890 PASS), #94 evidence policy/adversarial checks (1,266 full/8 policy groups and independent scoped review pass, but refund-approval and hardware-applicability probes remain genuinely red). #94 policy is not installed or required on main yet; branch protection/rule reads show no effective requirements. The master plan records installation/accuracy limits. No paid run, merge, deployment, optional enablement or new Discord test; third smoke held. Scores64/56 unchanged. Older checkpoints below are history where superseded. + +**Historical October28 operator receipt:** #91 mergeda461f868ad097ec93512aeaf111d63f4e4c96997 and was deployed asc42efc65-0efb-4ca2-adca-f5f93627b37f, created20:05:37IST. Exact merged-main CI, rollback availability/cadence/source/off-state preflight, startup/health/schema/login and one running instance passed. Normal phone-only how-to smoke passed. The second smoke preserved the symptom/earlier attempts and delivered one matching private staff card, but improperly applied Limitless-specific guidance to unidentified hardware. Independent review called this a grounding failure. Under Aryan's failure rule, deploymentRollback of verified914a38f0/a9c9508 returnedtrue. Replacementa6ef6b22-26b3-4744-ab8d-e067311ff7da/a9c9508, createdOctober28 at20:27:42IST, is SUCCESS/latest/one running; health/schema/login pass with zero matched startup failures and optional/automatic deployment controls off. Earliest cadence-only window isOctober29 at20:27:42IST; applicability repair/review remains a separate release hold. Third smoke and further releases are held. #90 merged cffb46b after all review/CI gates and remains not deployed. The previous PR queue is cleared; the separate new #83 current-contact draft is not merged or deployed. #83 source-applicability investigation and the narrow current-contact draft are in [SOURCE_APPLICABILITY_BOUNDARY.md](SOURCE_APPLICABILITY_BOUNDARY.md); no third-smoke input or automatic release is scheduled. No environment/settings changes, paid rerun, memory enablement or agent Discord posts. [Master plan](SUPPORT_MASTER_PLAN.md) controls current status. Do not delete receipt/cutoff rows to force webhook replay. The candidate ignores stale payload subject times, holds uncertain outcomes and retains a minimal customer/time cutoff after owner erasure; cleanup is mandatory even with optional features off. Fixed notice-retention errors mean pending cleanup, not erased records. An unexpected populated pre-lifecycle schema fails closed for review. Use an existing linked synthetic issue/thread for the next approved-release smoke; no new public issue. diff --git a/docs/SOURCE_APPLICABILITY_BOUNDARY.md b/docs/SOURCE_APPLICABILITY_BOUNDARY.md new file mode 100644 index 0000000..9a78088 --- /dev/null +++ b/docs/SOURCE_APPLICABILITY_BOUNDARY.md @@ -0,0 +1,41 @@ +# Applicability and useful next-step boundary — #83 + +October28 offline investigation. The source-applicability portion remains a design/reproduction record. The local draft implements only the bounded current-contact next-actor boundary below; it is not a release-ready applicability repair. Main cffb46b includes #90 provenance and #91 bounded context preservation; production was rolled back to a9c9508/a6ef6b22 after failed source applicability. See the master plan for current status. + +## Observed failure and diagnostic limits + +The rejected release used an official third-party device guide without establishing the customer hardware. Context and private staff delivery worked; authority alone did not establish applicability. Keep these results distinct. A rollback does not prove the baseline cannot make the same mistake. + +New fictional offline tests exercise the real reviewer, second look, presentation and person decision with injected approved responses. Three expected-contract checks fail: explicit product scope with unidentified customer hardware; definite resolution of contradictory unscoped instructions; uncertainty plus an email-only confirmation route. A positive ordinary-answer control passes. These prove acceptance gaps under those injected responses, not natural generation frequency or arbitrary contradiction detection. + +A separate private test loads the unchanged synthetic production-handler fixture and supplies the actual reviewer via its existing post seam. The unresolved, high-confidence FAQ output receives no staff dispatch after the email route is removed; the expected real-person next step fails. The useful platform-question control passes without a case. All external boundaries are synthetic, no provider/network/customer/protected data. Source/trace identities and logs remain private. + +## Required coherent pipeline + +1. Ingestion must carry trustworthy source declarations into the existing parent-page metadata and formatted evidence. Keep source authority, product family/model, platform, app version and firmware version distinct. Do not infer a universal scope from missing metadata, a title, brand, fetch time or a newer date. The existing source-date preference is not an applicability verdict. +2. Bind those declarations to explicit customer context outside the model. Keep matched, explicitly incompatible, missing customer detail and unknown source scope distinct. Customer descriptions can identify a requested device or version; they cannot verify backend state. A planner or reviewer boolean is a proposal, not proof. +3. An unresolved material applicability condition must survive ordinary-FAQ approval clearing, second look, selection and presentation. Ask one genuinely useful missing detail where that can resolve the scope; otherwise use the existing verified private handoff. Removing email or adding reply-here does not establish that next step. +4. Preserve current human-action intent before redirect removal, without treating a conditional future contact footer as a current requirement. Keep the staff delivery notice application-owned and distinguish delivery from acceptance. A failed delivery retains the existing honest fallback. +5. Contradiction requires more than different strings or dates. Preserve complementary facts and protective warnings. Unknown semantic relationships remain unresolved; do not claim a general solver from matching IDs or model-reported completeness. + +## Before claiming a source-applicability repair + +Prove how the actual ingestion owner creates trustworthy scope/conflict signals and how the application enforces unresolved next steps. Include general red-before tests and positive controls for matched/mismatched/unknown products; separate version dimensions; absent metadata; complementary/conflicting sources; protected/current-person requests; useful detail questions; ordinary FAQs; conditional future contact; source/secret/custody warnings; prior attempts; compact review, second-look/fallback and honest dispatch failure. + +No URL-, article-, product-, language- or evaluation-question-specific exception. No new store, model stage, private capability, customer data, enabled memory or deployment. A future paid comparison needs a reviewed plan and separate authorization; no previous unused ceiling applies. Until this boundary is concrete, keep the investigation local and #83 open rather than opening an unverified repair PR. + +## Narrow current-contact draft — October29 + +The concrete failure is loss of a next actor: a high-confidence reviewed FAQ can ask the customer to contact support now, then redirect removal deletes that request and leaves only a generic reply-here line. An actual-handler red-before test produced zero staff cards where one current handoff was required; the failed-delivery control also lacked the expected honest fallback. + +The existing redirect-removal owner now optionally returns cleaned text plus a text-free `currentContactRequested` bit from the same removed clause. Its original string API/cleaning behavior is retained. A complete bounded English grammar binds the imperative to Omi support and a small set of complete current-purpose forms. Free-form suffixes, uncertain scopes, other recipients and address mentions do not grant routing authority. Quoted/code ranges are tracked before segmentation; an unfinished heading/condition/list continuation holds scope across physical lines until a paragraph boundary. Completed facts, including quoted values and Markdown emphasis, do not hide a later independent current action. + +The existing shared escalation policy checks this bit before the FAQ/confidence exemption. It then uses the unchanged ownership fence, durable case and actual staff delivery workflow. Successful/failed receipt copy remains application-owned. No new provider stage, model field, store, prompt change, data access or optional feature. There is no separate forum-only workflow and no claim of broad multilingual or arbitrary conditional-language comprehension. + +Observed review findings were fixed with controls: conditional alternatives, quoted examples split across sentences, an explicitly different recipient, wrapped headings, invalid code-fence closures and closed quoted/formatted facts. Existing protection, source preservation, earlier-attempt, conditional footer, useful-detail, replayed-input and failed-delivery controls remain. The later positive grammar deliberately treats unrestricted purposes as unknown instead of guessing current intent; it does not claim every contact instruction is recognized. + +This draft does not establish hardware applicability, resolve arbitrary source contradictions or verify model compliance. The two factual-applicability red diagnostics remain open. Keep #83 and the production release hold open; do not deploy or claim the third smoke passed. Independent final review, exact-head CI and the remaining behavior-quality gate precede readiness. No paid run is authorized by deterministic tests or prior unused quota ceilings. + +### Verification checkpoint + +Local **1,268/1,268 full tests** and **8/8 no-model checks** pass. Independent final runtime review passes an8-case actual-handler matrix and168 legacy cleaned-text comparisons against main. The observed false-handoff/formatting findings above were repaired, not waived; one added fixture assertion was corrected to check its own exact retained fact. Generation, prompt, reviewer, selection and index-handler source files remain identical to main; only the existing redirect metadata and shared decision owner change. These are deterministic/synthetic checks, not a new model-accuracy score. Exact-head hosted checks and the applicable quality/approval gate remain required before readiness; the PR stays draft and no release follows. diff --git a/docs/SUPPORT_MASTER_PLAN.md b/docs/SUPPORT_MASTER_PLAN.md index fe0c3a5..e06c90f 100644 --- a/docs/SUPPORT_MASTER_PLAN.md +++ b/docs/SUPPORT_MASTER_PLAN.md @@ -1,6 +1,19 @@ # Mira: master product plan -Updated October 28, 2026 (IST). #91 merged as `a461f868ad097ec93512aeaf111d63f4e4c96997` and was deployed as `c42efc65-0efb-4ca2-adca-f5f93627b37f`, then rolled back; normal how-to smoke passed, but the broken-device smoke failed source applicability and rollback to a9c9508/a6ef6b22 is verified healthy; the third smoke is held. Current GitHub main is `a461f868ad097ec93512aeaf111d63f4e4c96997`; the fixed milestone foundation audit remains recorded against `647b549bade498573e6fb2a16bf4544377884b1e`. The repository-guide update adds no completed milestone; evidence hooks alone do not complete an additional product requirement. Aryan sets product priorities; this is the single current product checklist. The product is Mira; technical repository/deployment/package identifiers remain unchanged. +Updated October30,2026 (IST). GitHub main is **9b7154df6226dec6bfea5a32e2225e9f7d627019**. #90 provenance, #93 trace and #95 financial-outcome guard are merged; none is deployed. Live remains the verified **a9c9508 / a6ef6b22** rollback after the failed #91 device-applicability smoke. Aryan owns priorities. Product name is Mira, Omi's AI support assistant; technical identifiers stay unchanged. + +## October30 — production fixes and acceptance gates + +- **#93 merged6dcf4c1:** metadata-only production trace. Original1,266/8 checks, independent40focused+3handler review, current-head CI40918151890 and merged-main40997767666 pass. It observes decisions; it does not establish applicable hardware or customer resolution. +- **#95 merged9b7154d:** removes recognized unverified financial outcomes/commitments through draft, review/second review and late public output. Final runtime6c1900c:1,280 full/8 no-model, independent37focused+3actual-handler scoped PASS, current Node20/24/PostgreSQL41010058117 and merged-main41011204548 PASS. Earlier held review rounds exposed genuine bypasses; their regressions are retained. No financial lookup or write was added. Bounded lexicon and mostly English whole-form preservation remain explicit limits. +- **#96 draft:** device applicability across publisher ingestion, cached parent/chunk evidence, emitted catalog, customer-owned identity, review and sourced canned answers. Initial independent review correctly held false ownership, legacy software, nonpublisher scope, misleading trace and custody wording. These have deterministic regressions/repairs; final re-review, exact-head CI and quality approval remain pending. Repaired integrated local suite:1,292/1,292; no-model8/8. A prior frozen A/B integration passed all six original #94 scenarios; repeat after final B repair. +- **Paid verification:** reviewer judged B broadly answer-affecting. Prepare twelve new fictional scenarios and a catalog-carrying, budget-enforced simultaneous main/candidate harness; obtain Aryan's specific quota approval before any paid request. Earlier #90/#91 grants are consumed. No automatic rerun or merge follows approval. +- **#94 remains draft:** its two red probes identified real defects. Do not weaken their assertions. After A/B land, merge main into #94, carry the actual formatter catalog in its probe helper, run full/no-model/six scenarios/current CI and independent integration review, then merge. Its policy verifies evidence declarations, not answer accuracy. +- **#92 remains draft for serial merge-or-close decision:** current-contact intent/handoff audit has narrow functional evidence and prior independent review; saved96-output projection triggered the new boundary zero times, so it proves compatibility only. Do not call it a measured quality improvement or resolved #83. + +**Three open PRs:** #92,#94,#96 after #95 merged. A/B were expressly authorized production fixes over the normal cap; do not open unrelated drafts. No paid request, deployment, customer-data use, settings change or Discord input occurred in this repair phase. Memory/context/fix-inbox and automatic deployment remain off. #83 is still open, including unresolved-next-step/conflict work beyond these fixes. Scores remain **64/100 implemented on main,56/100 delivered,44 left**; no defensible current-product accuracy percentage is established. + +**Required check installation is still pending and reserved to Aryan.** After #94 merges, give the exact main protection/ruleset setting for `Mira answer evidence`. Do not change settings unless Aryan explicitly delegates that action. One combined exact-SHA release follows only after all relevant gates, verified current rollback/off-state and24-hour spacing; then Aryan sends the three sequential smokes. No Discord test is needed yet. ## Current score — 56 / 100 done, 44 / 100 left @@ -28,7 +41,10 @@ Require **no candidate-only material final-answer failure**, **no protected-hand | Draft | Evidence and disposition | Remaining work | | --- | --- | --- | | [#91 — context preservation](https://github.com/BasedHardware/omi-vector-bot/pull/91), #62 | **Merged `a461f86`; attempted rollout `c42efc65` rolled back after smoke failure.** Exact original reviewed runtime restored; 22/24 versus main 21/24, no candidate-only material final failure or tested required-person regression. Final independent review, 1,244 full/8 no-model and head/merged-main Node20/24/PostgreSQL CI pass. | Normal how-to passed. Symptom/earlier-attempt preservation and private delivery passed, but the answer applied Limitless-only guidance to unidentified hardware. Independent review called the smoke failed; rollback to a9c9508/a6ef6b22 verified healthy. Third smoke held; fix #83 applicability before another release. | -| [#90 — source provenance](https://github.com/BasedHardware/omi-vector-bot/pull/90), #83 | Frozen 21/24 versus old main 19/24; mapping below complete. New main with #91 integrated via merge commit; preserve both source policy and first-filter audit. Full 1,258 and no-model 8 pass. Independent integration code review and 240 focused checks pass. | Final-commit review and current Node20/24/PostgreSQL CI, then authorized merge. No paid rerun: current main and integrated #90 both reject the observed candidate-only staff claim. Frozen counts are not a fresh integrated accuracy score. | +| [#90 — source provenance](https://github.com/BasedHardware/omi-vector-bot/pull/90), #83 | **Merged `cffb46b`, not deployed.** Integration merge preserves source policy and #91 removal audit. Full1,258/no-model8, independent240-check integration review, final ca59fe0 review, exact-head CI40712936315 and merged-main CI40715091486 pass. | Further deployment held after failed #91 applicability smoke. Frozen21/24 versus old main19/24 remains historical; no paid rerun or integrated generated score. Continue #83 below. | +| [#92 — current-contact next actor](https://github.com/BasedHardware/omi-vector-bot/pull/92), #83 | 1,268 full/8 no-model, independent handler/cleanup parity/final runtime review and hosted CI40807186982 PASS at66aa6f4; later plan-only edits reuse runtime evidence and require current-head CI. Existing redirect owner/shared policy retain bounded current contact intent. | Draft for evidence/quality disposition and approval. Hardware applicability and arbitrary conflicts remain open; no release. | +| [#93 — production trace](https://github.com/BasedHardware/omi-vector-bot/pull/93) | **Merged6dcf4c1**; exact-head and merged-main CI pass, scoped independent review. | Not deployed; metadata only. | +| [#94 — evidence gate/adversarial checks](https://github.com/BasedHardware/omi-vector-bot/pull/94) | Draft; original two red probes are real production failures. Six original scenarios pass in a prior frozen A/B integration. | Update after final B merge; full/no-model/current CI/independent review, then merge. Aryan owns required-check installation. | ### #90 frozen final-answer failure mapping @@ -48,7 +64,7 @@ The withdrawn #91 follow-up remains a failed attempt: 23/24 versus main 21/24, w | State | Current evidence and limit | | --- | --- | -| **On main** | Concise support voice/routing/retrieval/clipping; #48 confidence/source-fit foundation; #59 calm practical AI-labelled voice; #41 staff case/pickup lifecycle; #60 localized closure; #76 request limits and #70 known-unsent recovery; #67/#80 in-thread/redirect cleanup; #81 localized rejected-review copy; #28 durable private engineering approvals; #84 application-owned public-intake privacy. | +| **On main** | Concise support voice/routing/retrieval/clipping; #48 confidence/source-fit foundation; #59 calm practical AI-labelled voice; #41 staff case/pickup lifecycle; #60 localized closure; #76 request limits and #70 known-unsent recovery; #67/#80 in-thread/redirect cleanup; #81 localized rejected-review copy; #28 durable private engineering approvals; #84 application-owned public-intake privacy. #90 provenance, #93 production trace and #95 deterministic financial-outcome guard are also on main, not deployed. | | **On main, disabled** | #61 references-only memory and bounded context, #73 SQL/reader safety rehearsal, #74 owner-scoped correction-link forgetting, #49 reviewed-fact/revocation foundation. Merged code is not permission to use customer history or publish facts. | | **Release rolled back; baseline verified** | #91 exact a461f86/c42efc65 passed startup but failed the broken-device source-applicability smoke. Verified rollback replacementa6ef6b22 runs baselinea9c9508, healthy/latest/one running with schema/login ready. Normal how-to and context/private-delivery portions passed; do not call the release accepted. Third smoke held. Optional/automatic deployment controls remain off. | | **Passed limited release checks** | October25 phone-only how-to, damaged-item privacy, order-status privacy, and exact staff-authored sanitized private engineering preview. These are bounded scenarios, not full A–E acceptance. | @@ -56,7 +72,7 @@ The withdrawn #91 follow-up remains a failed attempt: 23/24 versus main 21/24, w | **Deployed, scoped notice smoke passed** | [#86](https://github.com/BasedHardware/omi-vector-bot/pull/86), merge `647b549`: **Receipt lifecycle approved October26:**30 days, original payload-subject-age rejection and customer erasure. Full 1,202/no-model 8, exact-head hosted Node 20/24/real PostgreSQL and independent 85-test/signed HTTP/SQL/two-migration-probe review passed. Aryan deployed it; health/startup pass. He explicitly approved a reopen/verify/close/verify round trip on existing synthetic issue #23602. One notice per event, ordered open checkpoint then closure, final issue closed not planned and no extra notice at the follow-up read. This does not prove every replay/external-send outcome. [Lifecycle and limits](GITHUB_NOTICE_LIFECYCLE.md). No implicit memory enablement. | | **Closed without merge** | #71, #75 and #82 failed their final accuracy/execution disposition; #29/#30/#68/#77/#78 were closed with remaining scope/evidence retained. Do not reopen or rerun them automatically. #65/#51/#56/#62 keep the unresolved needs. | -The earlier PR backlog is cleared, not the full product backlog. #88 merged884fb46; #87 merged928676b; #86 merged647b549 after all required checks/review. Aryan's647b549/dba28f7d rollout and scoped #86 smoke are verified separately. #89's Mira repository guide is on maina9c9508. #91 context preservation is merged; its rollout failed the source-applicability smoke and was rolled back; #90 provenance is integrated and awaiting its final gates. Broader #83/#65 work remains. Stay within the standing maximum of three open PRs, including ready PRs; every new PR starts draft. No count-driven merge or scope loss. Runtime/notice wording approvals do not grant deployment, settings, assignment, paid reruns or memory enablement. +The earlier PR backlog is cleared, not the full product backlog. #88 merged884fb46; #87 merged928676b; #86 merged647b549 after all required checks/review. Aryan's647b549/dba28f7d rollout and scoped #86 smoke are verified separately. #89's Mira repository guide is on maina9c9508. #91 context preservation is merged; its rollout failed the source-applicability smoke and was rolled back; #90 provenance is merged as cffb46b, not deployed. The former queue is cleared; current #92/#94/#96 drafts and broader #83 work remain. #93/#95 are merged, not deployed. Broader #83/#65 work remains. Stay within the standing maximum of three open PRs, including ready PRs; every new PR starts draft. No count-driven merge or scope loss. Runtime/notice wording approvals do not grant deployment, settings, assignment, paid reruns or memory enablement. ## Issues — audited decisions, not count-driven closure @@ -70,8 +86,8 @@ The earlier PR backlog is cleared, not the full product backlog. #88 merged884fb ## Next steps — accuracy first, then controlled enablement -1. **Finish #91 release acceptance.** Merge is complete; release is rejected and rollback baseline health/startup is verified. Fix the general applicability boundary under #83. Preserve the passing how-to and context/delivery evidence without presenting them as whole-release acceptance. Do not request the third smoke on the rejected image. -2. **Finish #90 final gates and merge.** Integration, 1,258/8 checks and independent code/replay review pass; final head review/CI remain. Further release is held after the failed #91 smoke. Complete #83 applicability work/review and fresh release timing/exact-SHA/rollback/off-state gates before shipping anything. Start #83 offline next: general unresolved-next-step and conflicting-source applicability boundaries with synthetic red-before tests, no paid run or assumed model self-certification. +1. **Finish the #96 device boundary and quality gate.** #93/#95 are merged; B deterministic repairs and all six fictional acceptance scenarios pass locally. Freeze/re-review the integrated candidate, complete current CI and prepare the independently reviewed catalog-carrying comparison. Ask Aryan before quota use. Keep the rejected #91 image rolled back; no Discord smoke yet. +2. **Complete #94 and one combined release.** After approved B verification and merge, update #94 from main, retain the unchanged scenarios, pass full/no-model/current CI/independent review and merge. Give Aryan the required `Mira answer evidence` protection setting; do not apply it on his behalf. Then exact-SHA/rollback/off-state/24-hour gates precede the three sequential Discord smokes. General unresolved-next-step and conflicting-source work stays #83; no count-driven closure. 3. **Return to multipart phone-only accuracy (#65, A2).** #71/#75/#82 remain closed unmerged; do not reopen or rerun them automatically. Preserve their evidence and unfinished requirements. General routing/retrieval/coverage changes belong in the same answer/review pipeline, with no claim that #62 context repair alone resolves multipart accuracy. 4. **Complete memory preparation before a separately approved pilot (C1–C4).** The [pilot checklist](MEMORY_PILOT_PREPARATION.md) is drafted: test forum only, references rather than copied messages, 30 days, owner erasure, switch/restart timing, two-post scenario, 48 clean hours and rollback. Revised provider-disclosing notice wording is approved but not published; #86's separately approved existing-issue notice smoke passed. Processor/backup/privacy checks, approved isolated runtime/release and Aryan's explicit enable instruction still precede any saving or use of history. No pilot has begun. 5. **Build reviewed improvements through the same pipeline (D1–D6, then E1–E3).** Minimized owner signals → safe grouping/private review → official-source and regression validation → authorized fact publication/revocation → offline nightly checks and visible failures → honest weekly outcome reporting → the full end-to-end demonstration. Existing disabled stores are foundations, not completed D requirements or permission to publish/train. @@ -79,7 +95,15 @@ The earlier PR backlog is cleared, not the full product backlog. #88 merged884fb **Release timing:** #91 rollout a461f86/c42efc65 failed the broken-device smoke: Limitless-specific guidance was presented without identifying the customer hardware. Rollback to a9c9508 was explicitly requested under the approved failure rule. Replacementa6ef6b22/a9c9508 is verified healthy, createdOctober28 at20:27:42IST; earliest cadence-only window isOctober29 at20:27:42IST, not permission to deploy. Hold further releases until the general source-applicability issue and required checks are resolved. #90 is not deployed. Never use Restart for teardown. -**Need Aryan now:** no additional Discord input; the third smoke is held after the failed second smoke. Continue #90 final gates and #83 offline work. Aryan sends every message, command and button action. No new quota, enabled memory, customer data or automatic message is requested. No memory flag until notice approval **and** an explicit enable instruction. Continue #90's final gates and #83 offline work while waiting. +**Need Aryan next:** reviewed, repaired B will require a specifically approved paid comparison; no provider request before that approval. No additional Discord input; the third smoke is held after the failed second smoke. Continue #83 offline work. #90 is merged, not deployed. Aryan sends every message, command and button action. Any new quota request must name the frozen candidate, fictional scenarios and hard request ceiling. No enabled memory, customer data or automatic message is authorized. No memory flag until notice approval **and** an explicit enable instruction. No further Discord input is pending. Continue the #83 draft review and trustworthy source-applicability design. + +## #83 offline boundary investigation — started October28 + +[Design and reproduction scope](SOURCE_APPLICABILITY_BOUNDARY.md). Current review booleans do not establish claim-to-source applicability. Source date ordering is separate from hardware, OS, app version and firmware fit. A general repair must carry trustworthy source declarations from actual ingestion and explicit customer context; missing scope stays unknown. No title/brand inference, model self-certification or article-specific exception is a verified remedy. + +The actual-handler reproduction also shows that stripping a current email-confirmation request can leave a high-confidence FAQ with only a generic reply-here footer and no staff dispatch. Preserve the current unresolved next actor through review, FAQ clearing and presentation; a conditional future contact footer must not manufacture a case. Useful missing-detail questions remain valid next steps. Require protected-person, ordinary FAQ, warning, prior-attempt, second-look and failed-delivery controls before a candidate exists. + +**Current October29 draft:** the existing redirect owner returns a text-free current-contact flag from a bounded, complete action-to-support-target grammar. Shared escalation checks it before FAQ confidence can cancel the next actor; existing case/ownership/dispatch and receipt wording remain authoritative. Actual-handler success, failed-delivery and duplicate-input controls plus conditional/quoted/other-recipient/formatted-fact regressions are covered. This is only the lost-next-actor repair. Unknown hardware applicability and unsupported conflict resolution remain unrepaired; source declarations must still be proven from ingestion. Keep the PR draft pending final review/CI and its applicable quality gate; no paid run or release. #83 stays open and scores do not increase. ## Fixed milestone ledger diff --git a/docs/SUPPORT_PROGRESS.json b/docs/SUPPORT_PROGRESS.json index e112fca..30ec91c 100644 --- a/docs/SUPPORT_PROGRESS.json +++ b/docs/SUPPORT_PROGRESS.json @@ -1,8 +1,8 @@ { "schemaVersion": 1, - "auditedOn": "2026-10-26", + "auditedOn": "2026-10-28", "timezone": "Asia/Kolkata", - "auditedMain": "a9c9508ac9be03a2bfd0f571e90f6779b6d96a48", + "auditedMain": "cffb46bd0cbc0cf773df6827783f5d82cc859bfb", "rubric": "25 fixed milestones; one point per main implementation, tested, independently reviewed and relevant live/tool-operation verification", "notAccuracy": true, "milestones": [ @@ -272,5 +272,8 @@ "liveVerified": false, "evidence": "Full staged, enabled end-to-end demonstration has not happened." } - ] + ], + "stateObservedOn": "2026-10-30", + "currentMainObserved": "9b7154df6226dec6bfea5a32e2225e9f7d627019", + "currentChangeNote": "93/95 merged;96/94/92 pending. No new milestone credit or accuracy percentage." } diff --git a/escalationPolicy.js b/escalationPolicy.js index c538cf9..d07f7aa 100644 --- a/escalationPolicy.js +++ b/escalationPolicy.js @@ -1,6 +1,6 @@ const router = require('./router'); const plannerPolicy = require('./plannerPolicy'); -const { shouldEscalate, CONFIDENCE_THRESHOLD, containsEscalationKeyword, needsHumanAccess } = require('./utils'); +const { shouldEscalate, CONFIDENCE_THRESHOLD, containsEscalationKeyword, needsHumanAccess, stripSupportRedirectWithAudit } = require('./utils'); const { hasUnsyncedDataRisk } = require('./answerPipeline'); function officialCitationUrl(value) { @@ -78,9 +78,13 @@ function answerNeedsPerson(answer) { function decideEscalation({ route = {}, question = '', answer = '', agent = {}, caption = '', triaged = {}, holdPublicCopy = false, dataLossRisk = false, reviewApproved = false, retrievedUrls = [], supportKind = '' } = {}) { const answerPerson = answerNeedsPerson(answer); + // Preserve the next actor before presentation removes an external contact + // route. This signal requires the same removed clause's bounded current + // instruction, never an address mention or model-authored receipt claim. + const currentContact = stripSupportRedirectWithAudit(answer).currentContactRequested; const needsPerson = Boolean( agent.escalate || route.wantHuman || route.escalate || triaged.escalate || - dataLossRisk || answerPerson + dataLossRisk || answerPerson || currentContact ); const docsQuiet = !needsPerson && ( plannerPolicy.isGroundedHowTo(route, question, answer) || @@ -105,6 +109,7 @@ function decideEscalation({ route = {}, question = '', answer = '', agent = {}, ['triage', Boolean(triaged.escalate)], ['data_loss', Boolean(dataLossRisk)], ['answer_person', answerPerson], + ['current_contact_redirect', currentContact], ['public_copy', Boolean(holdPublicCopy)], ['low_confidence', lowConfidence && !confidenceOnlyExempt], ['caption', captionSignal], diff --git a/test/currentContactRedirect.test.js b/test/currentContactRedirect.test.js new file mode 100644 index 0000000..5172dfa --- /dev/null +++ b/test/currentContactRedirect.test.js @@ -0,0 +1,101 @@ +const test = require('node:test'); +const assert = require('node:assert/strict'); +const { stripSupportRedirect, stripSupportRedirectWithAudit } = require('../utils'); +const { decideEscalation } = require('../escalationPolicy'); + +test('redirect removal retains only bounded current contact intent as text-free metadata', () => { + for (const clause of [ + 'Contact support for confirmation.', + 'Please email help@omi.me for a review.', + 'For confirmation, write to team@basedhardware.com.', + 'You need to contact the support team.', + 'Please **contact support**.', + ]) { + const text = `The supported range is not listed. ${clause}\nSource: https://help.omi.me/en/articles/synthetic-range`; + const result = stripSupportRedirectWithAudit(text); + assert.equal(result.currentContactRequested, true, clause); + assert.equal(result.text, stripSupportRedirect(text)); + assert.match(result.text, /supported range is not listed/); + assert.ok(result.text.endsWith('Source: https://help.omi.me/en/articles/synthetic-range')); + assert.deepEqual(Object.keys(result).sort(), ['currentContactRequested', 'text']); + } +}); + +test('conditional future quoted protective and address-only units do not assert a current contact action', () => { + for (const text of [ + 'Open Status. If it fails, contact support.', + 'Open Status. Contact support if it fails.', + 'Open Status. Contact support only after the retry fails.', + 'Open Status. Before you contact support, read Status.', + 'Open Status. You can contact support later.', + 'Contact support tomorrow.', + 'Contact support next week.', + 'Contact support to confirm the supported firmware.', + 'Contact support in case the problem returns.', + 'Contact support should the problem return.', + 'Contact support as needed.', + 'Contact support or try the documented check first.', + 'Try the documented check first or contact support.', + 'Contact your IT administrator rather than help@omi.me.', + 'Open Status. Consider contacting support.', + 'Open Status. Help is available at help@omi.me.', + 'Open Status. They recommend help@omi.me.', + 'Never email your secret key to help@omi.me.', + 'Do not contact support about this example.', + 'The example says "Contact support."', + "The example says 'Check Status. Contact support.'", + 'The example says ‘Check Status. Contact support.’', + "The example says 'Check Status;\nContact support.'", + "The example says 'Don't change Status.\nContact support.'", + 'The example says "Check Status. Contact support. Then wait."', + '> Contact support.', + '`Contact support.`', + '```text\nContact support.\n```', + '~~~text\nContact support.\n~~~', + ' Contact support.', + '\tContact support.', + '```example\n```not-a-closing-fence\nContact support.\n```', + 'Source: https://help.omi.me/guide?email=help@omi.me', + 'Contact support; if the retry fails.', + 'Open Status.\nIf needed:\nContact support.', + 'If the problem returns\n- Contact support.', + 'As needed:\nContact support.', + '**If needed:**\nContact support.', + ]) assert.equal(stripSupportRedirectWithAudit(text).currentContactRequested, false, text); +}); + +test('a real current instruction after a completed code fence still reaches the audit', () => { + for (const fence of ['```', '~~~']) { + const result = stripSupportRedirectWithAudit(`${fence}example\nContact support later.\n${fence}\nPlease contact support for confirmation.`); + assert.equal(result.currentContactRequested, true); + } +}); + +test('closed quoted facts and paragraph boundaries do not hide an independent current instruction', () => { + for (const text of [ + "The indicator is called 'Status'. Contact support for confirmation.", + 'The indicator is called “Status”; contact support for confirmation.', + 'The indicator is called `Status`. Contact support for confirmation.', + '**The range is unknown.**\nContact support for confirmation.', + 'The range is **unknown.**\nContact support for confirmation.', + 'If needed:\nContact support.\n\nContact support for confirmation.', + ]) assert.equal(stripSupportRedirectWithAudit(text).currentContactRequested, true, text); +}); + +test('current contact metadata does not delete completed attempts or protective instructions', () => { + const text = 'The upload is still pending after your retry; contact support. Do not clear local recordings.\nSource: https://help.omi.me/en/articles/synthetic-upload'; + const result = stripSupportRedirectWithAudit(text); + assert.equal(result.currentContactRequested, true); + assert.match(result.text, /still pending after your retry/); + assert.match(result.text, /Do not clear local recordings/); + assert.doesNotMatch(result.text, /contact support/); +}); + +test('the shared decision preserves a current contact actor despite approved FAQ confidence', () => { + const result = decideEscalation({ route: { lane: 'faq' }, triaged: { lane: 'faq' }, + question: 'Where is documentation for validation badges?', answer: 'The range remains uncertain. Contact support for confirmation.', + agent: { confidence: 0.99, escalate: false }, reviewApproved: true }); + assert.equal(result.escalate, true); + assert.equal(result.docsQuiet, false); + assert.ok(result.signals.includes('current_contact_redirect')); +}); diff --git a/test/index.test.js b/test/index.test.js index 1e61dad..4448419 100644 --- a/test/index.test.js +++ b/test/index.test.js @@ -3424,6 +3424,79 @@ test('a report five minutes after /done still opens a new Handoff', async (t) => assert.equal(r.thread.sent.length, r.sentBefore); }); +test('a current contact instruction survives FAQ redirect cleanup as one verified staff handoff', async t => { + const staff = enableStaffDelivery(t); + process.env.CMD_API_KEY = 'synthetic-never-live'; + const source = 'https://help.omi.me/en/articles/synthetic-validation-range'; + docsObserver = async (_q, opts) => { + opts.onSources?.([source]); + return `[S1 | Official Help Center | authoritative]\nValidation range\n${source}\nThe supported firmware range is not listed.`; + }; + modelReply = { final_answer: 'The supported firmware range is not listed. Contact support for confirmation.', confidence: 0.9, escalate: false }; + reviewerResponse = args => realReviewAnswer({ ...args, post: async () => ({ data: { choices: [{ message: { + content: JSON.stringify({ final_answer: args.draft, grounded: true, relevant: true, confidence: 0.9, escalate: false, sources_used: ['S1'] }), + } }] } }) }); + const channel = makeChannel({ thread: true, parentId: TEST_CHANNEL, name: 'Validation badge documentation' }); + const result = await ask('Where is documentation for configurable validation badges?', { channel }); + assert.equal(staff.length, 1); + assert.match(result.reply, /supported firmware range is not listed/); + assert.ok(result.reply.includes(source)); + assert.equal((result.reply.match(/will reply in this thread/g) || []).length, 1); + assert.doesNotMatch(result.reply, /contact support|help@omi\.me|reply here in this thread|already investigating|accepted/i); + await handleMessage(result.message); + assert.equal(staff.length, 1, 'replayed input does not dispatch a second staff card'); +}); + +test('current-contact staff delivery failure keeps uncertainty and the application-owned fallback', async () => { + process.env.CMD_API_KEY = 'synthetic-never-live'; + modelReply = { final_answer: 'The supported range remains unclear. Please email help@omi.me for confirmation.', confidence: 0.9, escalate: false }; + const result = await ask('Where is documentation for the validation indicator?'); + assert.match(result.reply, /supported range remains unclear/); + assert.match(result.reply, /could not deliver|could not reach|couldn.t reach/i); + assert.equal((result.reply.match(/help@omi\.me/g) || []).length, 1); + assert.doesNotMatch(result.reply, /has this now|will reply in this thread|accepted|reply here in this thread/i); +}); + +test('a closed quoted fact does not erase a later independent contact action in the actual handler', async t => { + const staff = enableStaffDelivery(t); + for (const [answer, retainedFact] of [ + ["The indicator is called 'Status'. Contact support for confirmation.", /indicator is called 'Status'/], + ['The indicator is called “Status”; contact support for confirmation.', /indicator is called “Status”/], + ['**The range is unknown.**\nContact support for confirmation.', /\*\*The range is unknown\.\*\*/], + ]) { + const before = staff.length; + modelReply = { final_answer: answer, confidence: 0.9, escalate: false }; + const channel = makeChannel({ thread: true, parentId: TEST_CHANNEL, name: 'Validation indicator documentation' }); + const result = await ask('Where is documentation for validation indicators?', { channel }); + assert.equal(staff.length, before + 1); + assert.match(result.reply, retainedFact); + assert.match(result.reply, /will reply in this thread/); + assert.doesNotMatch(result.reply, /contact support|reply here in this thread/i); + } +}); + +test('optional future contact and useful missing-detail questions keep an ordinary FAQ path', async t => { + const staff = enableStaffDelivery(t); + for (const answer of [ + 'Open Status to see the indicator. If you later need help, contact support.', + 'Open Status to see the indicator. Contact support if it still fails.', + 'Open Status to see the indicator. Contact support in case the problem returns.', + 'Open Status to see the indicator. Contact support should the problem return.', + 'Open Status to see the indicator. Contact support as needed.', + 'Open Status to see the indicator. Contact support or try the documented check first.', + 'Open Status to see the indicator. Contact your IT administrator rather than help@omi.me.', + "The example says 'Check Status. Contact support.'", + 'Open Status to see the indicator.\nIf needed:\nContact support.', + 'The location depends on your platform. Are you using the desktop or phone app?', + ]) { + modelReply = { final_answer: answer, confidence: 0.9, escalate: false }; + const result = await ask('Where is documentation for validation indicators?'); + assert.equal(staff.length, 0, answer); + assert.doesNotMatch(result.reply, /has this now|will reply in this thread|accepted/i); + assert.match(result.reply, /Open Status|Check Status|desktop or phone app/); + } +}); + test('production trace emits one metadata-only record for actual answer and private handoff paths', async t => { const lines=[]; diff --git a/utils.js b/utils.js index 600d657..145dd81 100644 --- a/utils.js +++ b/utils.js @@ -164,12 +164,59 @@ function hasIndependentDirective(text) { return hasSafetyWarning(shown) || hasTroubleshootingStep(shown) || /https?:\/\//iu.test(shown); } -function stripSupportRedirect(text, options = {}) { - const result = stripSupportRedirectImpl(text,options); - answerTrace.filter('support_redirect',text,result); - return result; +// This bounded English grammar recognizes a current instruction, not every +// possible way to request help. Unknown wording/address mentions grant no +// routing authority. The same removed clause must establish the action. +function isCurrentContactInstruction(clause, sentence, { quoted = false } = {}) { + if (quoted) return false; + const directive = String(clause).replace(/[*_~]/g, '').replace(/^\s*(?:[-+•]|\d+[.)])\s+/, '').trim(); + const at = String(sentence).indexOf(clause); + const prefix = String(sentence).slice(0, at).replace(/[*_~]/g, ''); + const suffix = String(sentence).slice(at + clause.length).replace(/[*_~]/g, ''); + // A completed fact can contain a past temporal phrase without conditioning + // a later independent instruction. A leading condition fragment or trailing + // condition still scopes that instruction conservatively. + if (prefix.split(/[;;]/u).some(part => /^\s*(?:if|unless|when|until|before|after|once|provided|assuming)\b|\b(?:only\s+(?:if|when|after|once)|first|otherwise|alternatively|or)\b/i.test(part)) || suffix.replace(/[;;.!?\s]/gu, '')) return false; + // A complete positive grammar binds the action to Omi support. Arbitrary + // purposes/suffixes can contain conditions or alternative recipients; they + // stay unrecognized rather than becoming a guessed current requirement. + return /^(?:for (?:confirmation|help|assistance|support|review),\s*)?(?:please\s+)?(?:you\s+(?:need to|have to|must|should)\s+)?(?:e-?mail|contact|reach out to|write to|message|get in touch with)\s+(?:(?:the|our)\s+)?(?:omi\s+support|support(?:\s+team)?|help@omi\.me|team@basedhardware\.com)(?:\s+(?:now|directly))?(?:\s+for\s+(?:confirmation|help|assistance|support|review|a review))?[.!]*$/i.test(directive); +} + +function contactQuoteSpans(line, previous) { + const characters = [...line], positions = []; + let offset = 0; + for (const character of characters) { positions.push(offset); offset += character.length; } + const spans = []; + let open = previous, start = open ? 0 : -1; + const word = character => /[\p{L}\p{N}]/u.test(character || ''); + for (let index = 0; index < characters.length; index++) { + const character = characters[index]; + if (character === '`') { + let end = index + 1; + while (characters[end] === '`') end++; + const count = end - index; + if (!open) { open = { closing: '`', count }; start = positions[index]; } + else if (open.closing === '`' && open.count === count) { + spans.push([start, positions[end] ?? line.length]); open = null; + } + index = end - 1; + } else if (open) { + const contraction = (character === "'" || character === '’') && word(characters[index - 1]) && word(characters[index + 1]); + if (character === open.closing && !contraction) { + spans.push([start, positions[index] + character.length]); open = null; + } + } else if (["'", '‘', '"', '“'].includes(character) && + (character !== "'" || !word(characters[index - 1]))) { + open = { closing: { "'": "'", '‘': '’', '"': '"', '“': '”' }[character] }; + start = positions[index]; + } + } + if (open) spans.push([start, line.length]); + return { spans, open }; } -function stripSupportRedirectImpl(text, {language = 'en'} = {}) { + +function stripSupportRedirectWithAudit(text, {language = 'en'} = {}) { const isRedirect = (sentence) => { // A warning not to send secrets is not an instruction to leave this thread. if (/\b(?:never|do not|don['’]t)\s+(?:e-?mail|send|share)|\bno\s+(?:env[ií]es|compartas)|不要(?:发送|分享)/i.test(sentence)) return false; @@ -183,16 +230,38 @@ function stripSupportRedirectImpl(text, {language = 'en'} = {}) { return directContact.test(sentence) || supportForm.test(sentence) || supportChannel.test(sentence) || contactControl.test(sentence); }; let removedReference = false; + let currentContactRequested = false; + let fenced = null; + let openQuote = null; + let continuationScope = false; const supported = REDIRECT_LANGUAGES.has(String(language).toLowerCase().split('-')[0]); - return String(text || '') + const cleaned = String(text || '') .split('\n') .map((line) => { - if (!line.trim()) { removedReference = false; return line; } + const fenceMatch = line.match(/^ {0,3}(`{3,}|~{3,})(.*)$/u); + const fence = fenceMatch?.[1]; + const codeOrQuote = Boolean(fenced || fence || /^\s*>|^ {4}|^\t/.test(line)); + if (fence) { + if (!fenced) fenced = { character: fence[0], length: fence.length }; + else if (fence[0] === fenced.character && fence.length >= fenced.length && !fenceMatch[2].trim()) fenced = null; + } + if (!line.trim()) { removedReference = false; continuationScope = false; return line; } if (SOURCE_HEADING.test(line)) return line; + const quote = codeOrQuote ? { spans: [[0, line.length]], open: openQuote } : contactQuoteSpans(line, openQuote); + openQuote = quote.open; + const displayed = line.replace(/^\s*(?:[-+*•]|\d+[.)])\s+/, '').replace(/[*_~]/g, '').trim(); + const condition = /^(?:if|unless|when|until|before|after|once|provided|assuming)\b/i.test(displayed); + const scopeHeld = continuationScope || condition; + // An unfinished heading/condition can scope the following physical lines + // or list. Do not reinterpret that continuation as a fresh imperative. + if (!codeOrQuote && (condition || !/[.!?。!?]["'”’`]*$/u.test(displayed))) continuationScope = true; const privateOrderIntake = sentence => /^\s*include (?:the )?order (?:number|#)/i.test(sentence); const originalClauses = line.split(/(?<=[.!?])\s+|[;;]\s*|(?<=[。!?])\s*|\s+(?:and|y)\s+(?=(?:do\s+not|don't|never|no)\b)/iu); if (!removedReference && !originalClauses.some(s => isRedirect(s) || privateOrderIntake(s))) return line; + let sentenceCursor = 0; return line.split(/(?<=[.!?])\s+|(?<=[。!?])\s*/u).filter(Boolean).flatMap(sentence => { + const sentenceAt = line.indexOf(sentence, sentenceCursor); + sentenceCursor = sentenceAt + sentence.length; const clauses = sentence.split(/[;;]\s*|\s+(?:and|y)\s+(?=(?:do\s+not|don't|never|no)\b)/iu).map(s=>s.trim()).filter(Boolean); const removed = clauses.some(s => isRedirect(s) || privateOrderIntake(s)); if (!removed) { @@ -201,7 +270,12 @@ function stripSupportRedirectImpl(text, {language = 'en'} = {}) { return [sentence]; } removedReference = true; + let clauseCursor = 0; return clauses.flatMap(clause => { + const clauseAt = sentence.indexOf(clause, clauseCursor); + clauseCursor = clauseAt + clause.length; + const start = sentenceAt + clauseAt, end = start + clause.length; + const quoted = scopeHeld || quote.spans.some(([left, right]) => start < right && end > left); if (SOURCE_HEADING.test(clause)) return [clause]; if (privateOrderIntake(clause)) return []; if (!isRedirect(clause)) { @@ -210,6 +284,7 @@ function stripSupportRedirectImpl(text, {language = 'en'} = {}) { if (!supported && !hasIndependentDirective(clause)) return []; return startsRedirectReference(clause) && !hasIndependentDirective(clause) ? [] : [clause]; } + currentContactRequested ||= isCurrentContactInstruction(clause, sentence, { quoted }); const details = clause.match(/\b(?:please\s+)?include\b.+$/i); return details && !isRedirect(details[0]) ? [`Please ${details[0].replace(/^please\s+/i, '')}`] : []; }); @@ -219,6 +294,13 @@ function stripSupportRedirectImpl(text, {language = 'en'} = {}) { .join('\n') .replace(/\n{3,}/g, '\n\n') .trim(); + return { text: cleaned, currentContactRequested }; +} + +function stripSupportRedirect(text, options) { + const result=stripSupportRedirectWithAudit(text, options).text; + answerTrace.filter('support_redirect',text,result); + return result; } const IN_THREAD_NEXT = { @@ -594,6 +676,7 @@ module.exports = { typingDelay, sanitizeReply, stripSupportRedirect, + stripSupportRedirectWithAudit, inThreadReply, formatDiscordReply, clipForDiscord,