mirror of
https://github.com/Patiun/com.gregkilmer.www.git
synced 2026-11-08 04:08:24 +00:00
Phase 6: sync jobs, inquiry and order forms
- Sync scheduler in the content service with a per-job cache (sync_cache), sync_runs reporting and Healthchecks pings. Jobs: Archidekt, BoardGameGeek, cover art (Open Library, TMDB, AniList), Suwayomi and Kavita reading progress, Bambuddy filament and Homebox material stock. A note's own value always wins over a synced one. - PersonalReader: updates only Library notes with a matching anilistId, changes to Greg's notes are held for review; Reading series with no note show as suggestions on the admin Overview. - /api/inquiries and /api/orders: Turnstile, rate limits, a saved copy in the content service (intake token) plus email over SMTP. Orders are re-checked against the live notes: accepted only when the category's ordersOpen is true and the line has capacity. - Admin Inbox for saved submissions. Options' inStock is optional so synced stock can fill it. All settings from process.env; .env.example per service. - Sources could not be reached from the build environment; parsers are tested against fixtures labelled as not live. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012aSbo2D1qP8cMFQCykf7kx
This commit is contained in:
@@ -52,6 +52,12 @@ export interface RuleContext {
|
||||
settings: RuleSettings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Authors held to the agent rules. A sync job writes as `sync` and may do
|
||||
* nothing an agent cannot: the same contact, publish, edit and batch limits.
|
||||
*/
|
||||
export const isLimited = (a: Author) => a === "agent" || a === "sync";
|
||||
|
||||
export type Verdict = { decision: "accept" } | { decision: "hold"; reasons: HeldReason[] };
|
||||
|
||||
/** Strings that look like credentials. Matching is on new text only. */
|
||||
@@ -125,26 +131,28 @@ export function evaluate(p: Proposed, ctx: RuleContext): Verdict {
|
||||
for (const [what, re] of SECRET_PATTERNS) {
|
||||
if (newMatches(re, p.text, before).length) reasons.push({ code: "secret", message: `The note now contains what looks like ${what}` });
|
||||
}
|
||||
if (p.author === "agent") {
|
||||
const who = p.author === "sync" ? "A sync" : "An agent";
|
||||
if (isLimited(p.author)) {
|
||||
const allowed = new Set(settings.allowedEmails.map((e) => e.toLowerCase()));
|
||||
const emails = newMatches(EMAIL, p.text, before).filter((e) => !allowed.has(e.toLowerCase()));
|
||||
if (emails.length) reasons.push({ code: "contact", message: `An agent added an email address: ${emails.join(", ")}` });
|
||||
if (newMatches(PHONE, p.text, before).length) reasons.push({ code: "contact", message: "An agent added a phone number" });
|
||||
if (emails.length) reasons.push({ code: "contact", message: `${who} added an email address: ${emails.join(", ")}` });
|
||||
if (newMatches(PHONE, p.text, before).length) reasons.push({ code: "contact", message: `${who} added a phone number` });
|
||||
}
|
||||
|
||||
// 6. Agents stay inside their lane.
|
||||
if (p.author === "agent") {
|
||||
if (live && live.author !== "agent" && live.data.agentEdits !== true) {
|
||||
reasons.push({ code: "agent-edit", message: "An agent changed a note you wrote, which needs your review" });
|
||||
if (isLimited(p.author)) {
|
||||
// A sync may change notes it wrote itself; anything else needs agentEdits.
|
||||
if (live && live.author !== p.author && live.data.agentEdits !== true) {
|
||||
reasons.push({ code: "agent-edit", message: `${who} changed a note you wrote, which needs your review` });
|
||||
}
|
||||
const publishing = data.publish === true && !(live?.publish ?? false);
|
||||
if (publishing && !settings.agentAutoPublish.includes(p.checked.type)) {
|
||||
reasons.push({ code: "agent-publish", message: `An agent wants to publish a ${p.checked.type}, which needs your approval` });
|
||||
reasons.push({ code: "agent-publish", message: `${who} wants to publish a ${p.checked.type}, which needs your approval` });
|
||||
}
|
||||
if (ctx.recentAgentChanges >= settings.agentBatchLimit) {
|
||||
reasons.push({
|
||||
code: "batch",
|
||||
message: `More than ${settings.agentBatchLimit} agent changes in ${settings.agentBatchWindowMinutes} minutes`,
|
||||
message: `More than ${settings.agentBatchLimit} ${p.author} changes in ${settings.agentBatchWindowMinutes} minutes`,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user