refactor: update agent sync behavior, improve freshness detection patterns, and add diagnostic troubleshooting script

This commit is contained in:
2026-05-05 07:43:45 -06:00
parent f685ac37dd
commit 63e784cc97
11 changed files with 168 additions and 61 deletions

View File

@@ -26,6 +26,7 @@ Behavior rules:
- Daily notes should include `focus`, `work-items`, and `blockers` when those values are clear.
- Before answering a prompt that depends on current state, verify the latest relevant files instead of relying only on conversation history.
- If the prompt asks for the latest Mattermost message, the last message from Jeff/current manager, or what someone just said, force a Mattermost refresh before answering and do not rely on stale inbox context.
- Treat latest-message prompts as read-first: answer from refreshed evidence and report memory update candidates instead of editing canonical memory by default.
- For learning-style questions, answer from known context and verified facts only; explicitly label unknowns, assumptions, and inferences.
- For learning sessions, prioritize durable architecture, process, ownership, debugging strategy, release mechanics, domain concepts, and decision rules over transient ticket status.
- If the user asks what to clarify, ask 3 to 5 high-leverage questions that would help a senior iOS engineer ramp into the project; include why each question matters.
@@ -56,6 +57,7 @@ Behavior rules:
- Do not wait for a dedicated sync command if the correct memory update is already obvious.
- For analysis, drafting, review, or translation prompts, answer first and persist second unless saving the fact is required to produce the answer safely.
- Avoid creating brand-new canonical notes in the middle of a response unless the user explicitly asked for persistence or the new note is the smallest correct update.
- If a non-essential memory patch fails verification, stop retrying and return the answer plus the intended target file.
- Do not leave behavior-only corrections only in daily logs. If a correction should affect future output, update the tool or instruction that produces that output.
- If the memory interface or Obsidian adapter fails, continue with direct Markdown operations when safe and do not promote the failure as project memory.
- Do not over-promote uncertain information. Keep uncertain items in the daily log.

View File

@@ -13,6 +13,12 @@ function nowIso() {
return new Date().toISOString()
}
function envFlag(name, defaultValue = false) {
const value = process.env[name]
if (value === undefined) return defaultValue
return ["1", "true", "yes", "on"].includes(value.trim().toLowerCase())
}
async function resolveSyncCommand(directory) {
const configured =
process.env.AIW_MATTERMOST_SYNC_CMD?.trim() ||
@@ -66,30 +72,16 @@ function requiresFreshMattermost(promptText) {
.replace(/[\u0300-\u036f]/g, "")
.toLowerCase()
const freshnessTerms = [
"ultimo",
"ultimos",
"ultima",
"ultimas",
"latest",
"last",
"reciente",
"recent",
"nuevo",
"new",
"actualiza",
"sync",
"sincroniza",
"revisa",
"dijo",
"menciono",
"respondio",
"contesto",
"check",
"look at",
"said",
"mentioned",
"replied",
const freshnessPatterns = [
/\bultimo(?:s|a|as)?\s+(?:mensaje|mensajes|respuesta|respuestas|update|updates)\b/,
/\bmensaje(?:s)?\s+(?:mas\s+)?reciente(?:s)?\b/,
/\bque\s+(?:dijo|menciono|respondio|contesto)\b/,
/\b(?:dijo|menciono|respondio|contesto)\s+(?:jeff|manager|supervisor)\b/,
/\b(?:latest|last|recent)\s+(?:message|messages|reply|replies|update|updates)\b/,
/\bwhat\s+did\s+.+\s+(?:say|mention|reply)\b/,
/\b(?:said|mentioned|replied)\s+(?:jeff|manager|supervisor)\b/,
/\b(?:sync|refresh|sincroniza|actualiza)\s+(?:mattermost|mensajes|messages|inbox)\b/,
/\b(?:revisa|check|look\s+at)\s+(?:mattermost|mensajes|messages|inbox)\b/,
]
const mattermostTerms = [
@@ -123,10 +115,8 @@ function requiresFreshMattermost(promptText) {
...configuredTerms,
]
return (
freshnessTerms.some((term) => text.includes(term)) &&
return freshnessPatterns.some((pattern) => pattern.test(text)) &&
sourceTerms.some((term) => text.includes(term))
)
}
export const MattermostInbox = async ({ $, directory, client }) => {
@@ -152,6 +142,7 @@ export const MattermostInbox = async ({ $, directory, client }) => {
if (!options.force && now - lastSyncAt < minIntervalMs) return
lastSyncAt = now
const syncStartedAt = Date.now()
const inboxDir = path.join(directory, "ai/inbox")
const latestPath = path.join(inboxDir, "mattermost-latest.md")
@@ -179,6 +170,7 @@ export const MattermostInbox = async ({ $, directory, client }) => {
await writeStatus(statusPath, {
syncedAt: nowIso(),
durationMs: Date.now() - syncStartedAt,
reason,
forced: Boolean(options.force),
changed: previous !== `${output}\n` && previous !== output,
@@ -188,6 +180,7 @@ export const MattermostInbox = async ({ $, directory, client }) => {
} else {
await writeStatus(statusPath, {
syncedAt: nowIso(),
durationMs: Date.now() - syncStartedAt,
reason,
forced: Boolean(options.force),
changed: false,
@@ -199,6 +192,7 @@ export const MattermostInbox = async ({ $, directory, client }) => {
} catch (error) {
await writeStatus(statusPath, {
syncedAt: nowIso(),
durationMs: Date.now() - syncStartedAt,
reason,
forced: Boolean(options.force),
changed: false,
@@ -223,13 +217,20 @@ export const MattermostInbox = async ({ $, directory, client }) => {
return {
event: async ({ event }) => {
if (event.type === "session.created") {
if (
event.type === "session.created" &&
envFlag("AIW_MATTERMOST_SYNC_ON_SESSION", false)
) {
await sync("session.created")
}
if (event.type === "tui.prompt.append") {
const promptText = extractPromptText(event)
const forceFreshMattermost = requiresFreshMattermost(promptText)
const allowPromptSync = envFlag("AIW_MATTERMOST_SYNC_ON_PROMPT", false)
if (!forceFreshMattermost && !allowPromptSync) return
await sync(
forceFreshMattermost
? "tui.prompt.append:fresh-mattermost-request"