mercury-agent 0.18.2 → 0.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/container/Dockerfile +25 -0
- package/container/build.sh +23 -3
- package/docs/behavior-layers.md +25 -14
- package/docs/configuration.md +139 -11
- package/docs/container-lifecycle.md +151 -1
- package/docs/context-architecture.md +6 -2
- package/docs/extensions.md +9 -1
- package/docs/goals/football-reporter-profile/decisions.md +79 -0
- package/docs/goals/rehearsal-bench/decisions.md +41 -3
- package/docs/goals/rehearsal-bench/roadmap.md +3 -1
- package/docs/goals/release-gate/decisions.md +86 -0
- package/docs/goals/release-gate/roadmap.md +36 -3
- package/docs/live-testing.md +22 -0
- package/docs/pending-verification.md +178 -0
- package/docs/permissions.md +1 -1
- package/docs/profile-guide.md +28 -8
- package/examples/extensions/archive/backends/local.ts +6 -3
- package/examples/extensions/archive/queue.ts +51 -10
- package/examples/extensions/feed-watch/config.ts +42 -2
- package/examples/extensions/feed-watch/digest.ts +4 -7
- package/examples/extensions/feed-watch/items.ts +18 -7
- package/examples/extensions/feed-watch/match.ts +125 -9
- package/examples/extensions/feed-watch/skill/SKILL.md +25 -0
- package/examples/extensions/feed-watch/watch.ts +39 -5
- package/examples/extensions/gws/index.ts +126 -8
- package/examples/extensions/longview/hook.ts +72 -7
- package/examples/extensions/longview/index.ts +2 -0
- package/examples/extensions/morning/README.md +26 -15
- package/examples/extensions/morning/index.ts +29 -6
- package/examples/extensions/morning/lib/hosts.ts +16 -0
- package/examples/extensions/morning/lib/morning.ts +78 -0
- package/examples/extensions/morning/lib/upload.ts +584 -0
- package/examples/extensions/morning/skill/SKILL.md +34 -4
- package/examples/extensions/napkin/index.ts +12 -3
- package/examples/extensions/napkin/pi-spawn.ts +5 -1
- package/examples/extensions/overview/index.ts +20 -0
- package/examples/extensions/overview/skill/SKILL.md +9 -1
- package/examples/extensions/pinchtab/index.ts +36 -7
- package/examples/extensions/pinchtab/skill/SKILL.md +28 -1
- package/examples/profiles/_template/AGENTS.md +6 -1
- package/examples/profiles/football-reporter/AGENTS.md +16 -4
- package/examples/profiles/football-reporter/README.md +1 -1
- package/examples/profiles/football-reporter/config.yaml +42 -6
- package/examples/profiles/football-reporter/seed/MEMORY.md +1 -1
- package/examples/profiles/football-reporter/seed/episodes/beitar-jerusalem-2026-27.md +1 -1
- package/examples/profiles/football-reporter/seed/episodes/maccabi-tel-aviv-2026-27.md +24 -0
- package/examples/profiles/football-reporter/seed/napkin-distill.md +30 -29
- package/examples/profiles/football-reporter/standard.json +45 -8
- package/package.json +11 -6
- package/resources/skills/tasks/SKILL.md +17 -1
- package/resources/templates/AGENTS.md +4 -3
- package/resources/templates/mercury.example.yaml +13 -4
- package/src/adapters/whatsapp-ingress.ts +15 -3
- package/src/agent/container-entry.ts +299 -29
- package/src/agent/container-env.ts +26 -8
- package/src/agent/container-runner.ts +497 -76
- package/src/agent/image-contract.ts +77 -0
- package/src/agent/image-manifest.ts +180 -0
- package/src/agent/image-refresh.ts +318 -0
- package/src/cli/mercury.ts +225 -28
- package/src/cli/mrctl-http.ts +5 -0
- package/src/cli/mrctl.ts +57 -5
- package/src/cli/service-unit.ts +109 -0
- package/src/config-file.ts +22 -1
- package/src/config.ts +105 -14
- package/src/core/api.ts +11 -2
- package/src/core/commands.ts +11 -4
- package/src/core/connection-health.ts +377 -0
- package/src/core/direct-send.ts +235 -14
- package/src/core/exec.ts +10 -0
- package/src/core/history-window.ts +142 -0
- package/src/core/model-command.ts +130 -0
- package/src/core/operator-alerts.ts +326 -23
- package/src/core/permissions.ts +28 -0
- package/src/core/profiles.ts +32 -16
- package/src/core/reply-context.ts +31 -0
- package/src/core/routes/config-builtin.ts +11 -0
- package/src/core/routes/console.ts +98 -16
- package/src/core/routes/dashboard.ts +93 -10
- package/src/core/routes/model.ts +26 -3
- package/src/core/routes/send.ts +1 -1
- package/src/core/routes/tasks.ts +74 -0
- package/src/core/runtime.ts +302 -21
- package/src/core/system-messages.ts +33 -0
- package/src/core/task-scheduler.ts +155 -7
- package/src/extensions/image-builder.ts +1 -1
- package/src/extensions/installer.ts +72 -17
- package/src/extensions/load-project.ts +74 -0
- package/src/extensions/loader.ts +50 -9
- package/src/host-version.ts +32 -0
- package/src/main.ts +42 -21
- package/src/preflight/checks/credential.ts +300 -0
- package/src/preflight/checks/docker.ts +149 -0
- package/src/preflight/checks/extensions.ts +90 -0
- package/src/preflight/checks/host-deps.ts +247 -0
- package/src/preflight/checks/image-contract.ts +228 -0
- package/src/preflight/checks/roundtrip.ts +424 -0
- package/src/preflight/checks/sandbox.ts +159 -0
- package/src/preflight/deps.ts +107 -0
- package/src/preflight/probe-container.ts +156 -0
- package/src/preflight/report.ts +177 -0
- package/src/preflight/run.ts +223 -0
- package/src/server.ts +55 -14
- package/src/storage/db.ts +41 -2
- package/src/storage/models-json.ts +110 -0
- package/src/text/reporter-lint.ts +167 -23
- package/src/types.ts +22 -0
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
* pi happens to be on PATH.
|
|
23
23
|
*/
|
|
24
24
|
|
|
25
|
-
import {
|
|
25
|
+
import { posix, win32 } from "node:path";
|
|
26
26
|
import type { ModelLeg } from "mercury-agent/core/model-leg";
|
|
27
27
|
|
|
28
28
|
// Rule 2's resolver is shared with every other host-side spawn (longview's
|
|
@@ -152,6 +152,10 @@ export function composePiSearchPath(opts: {
|
|
|
152
152
|
appData?: string;
|
|
153
153
|
}): string {
|
|
154
154
|
const { base, piNodeModulesBin, home, isWindows } = opts;
|
|
155
|
+
// isWindows selects the whole path module, not just the literal directory
|
|
156
|
+
// and the dedupe case-folding below — join and delimiter must agree with
|
|
157
|
+
// it, or the composed PATH mixes separators from the wrong platform.
|
|
158
|
+
const { join, delimiter } = isWindows ? win32 : posix;
|
|
155
159
|
const globalBins = [
|
|
156
160
|
join(home, ".bun", "bin"),
|
|
157
161
|
isWindows
|
|
@@ -35,6 +35,14 @@ const SKILL_SOURCE = join(EXT_DIR, "skill", "SKILL.md");
|
|
|
35
35
|
const managementSpaceId = (): string | undefined =>
|
|
36
36
|
process.env[MANAGEMENT_SPACE_ENV];
|
|
37
37
|
|
|
38
|
+
const MANAGEMENT_SPACE_PROMPT =
|
|
39
|
+
"This is the deployment's management space. Other spaces ARE readable from here " +
|
|
40
|
+
"through the `overview` skill (`mrctl capability overview <action>`): a request about " +
|
|
41
|
+
"another space — its recent messages, where something was said, who is admin, what runs " +
|
|
42
|
+
"tonight — is answered by reading that skill and running its action, never by saying the " +
|
|
43
|
+
'space is not visible from here. Exception to the "never show ids" rule: a space `id` is ' +
|
|
44
|
+
"the handle every overview action takes — show it beside the name.";
|
|
45
|
+
|
|
38
46
|
/**
|
|
39
47
|
* Install the skill into the management space's own workspace.
|
|
40
48
|
*
|
|
@@ -97,6 +105,18 @@ export default function (mercury: MercuryExtensionAPI) {
|
|
|
97
105
|
return undefined;
|
|
98
106
|
});
|
|
99
107
|
|
|
108
|
+
// Fact, not prose in AGENTS.md: only this extension knows which space is
|
|
109
|
+
// the management space, so the fragment lives here (layer 3a) and is
|
|
110
|
+
// scoped to that one space by the same check `workspace_init` uses above.
|
|
111
|
+
// Without it, the description alone loses the coin flip against the
|
|
112
|
+
// model's "mrctl is space-scoped" prior on a non-English, unprompted ask.
|
|
113
|
+
mercury.on("before_container", async (event) => {
|
|
114
|
+
const configured = managementSpaceId()?.trim() ?? "";
|
|
115
|
+
return configured !== "" && event.spaceId === configured
|
|
116
|
+
? { systemPrompt: MANAGEMENT_SPACE_PROMPT }
|
|
117
|
+
: undefined;
|
|
118
|
+
});
|
|
119
|
+
|
|
100
120
|
mercury.capability(
|
|
101
121
|
"overview",
|
|
102
122
|
async (req: CapabilityRequest, ctx: MercuryExtensionContext) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: overview
|
|
3
|
-
description: Read other spaces from this management space — list spaces, pull recent messages, search across all spaces, inspect scheduled tasks and role assignments. Use when asked what is happening in another space, where something was discussed, who is admin where, or what runs tonight.
|
|
3
|
+
description: Read other spaces from this management space — list spaces, pull recent messages, search across all spaces, inspect scheduled tasks and role assignments. Use when asked, in any wording, what is happening in another space, what was said or sent there recently, where something was discussed, who is admin where, or what runs tonight — e.g. "show me the recent messages from X", "מה קורה בספייס X", "מה נשלח ב-X לאחרונה", "תראה לי את ההודעות האחרונות מ-X", "איפה דיברו על …", "מי אדמין ב-X". Not for this space's own history (that is mrctl recall).
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Cross-space overview
|
|
@@ -17,6 +17,14 @@ The capability may be inert — it answers `403` when this deployment has not
|
|
|
17
17
|
designated a management space, or when the caller is not a global admin. That is
|
|
18
18
|
configuration, not a bug: report the error and stop.
|
|
19
19
|
|
|
20
|
+
## Before answering
|
|
21
|
+
|
|
22
|
+
A question that names another space is answered by running the action below,
|
|
23
|
+
not by saying the space is not reachable; if you have not run `list` in this
|
|
24
|
+
conversation, run it first. **Space ids are shown.** The platform's
|
|
25
|
+
never-show-ids rule does not apply to a space `id` here; put it beside each
|
|
26
|
+
name.
|
|
27
|
+
|
|
20
28
|
## Usage
|
|
21
29
|
|
|
22
30
|
```bash
|
|
@@ -21,6 +21,7 @@ export default function (mercury: {
|
|
|
21
21
|
local bind="\${BRIDGE_BIND:-127.0.0.1}"
|
|
22
22
|
local port="\${BRIDGE_PORT:-9867}"
|
|
23
23
|
local log="\${PINCHTAB_LOG:-/tmp/pinchtab.log}"
|
|
24
|
+
local pidfile="\${PINCHTAB_PIDFILE:-/tmp/pinchtab.pid}"
|
|
24
25
|
local max_wait="\${1:-120}"
|
|
25
26
|
mkdir -p "$(dirname "$log")" 2>/dev/null || true
|
|
26
27
|
# Belt and braces alongside the container-level "--ulimit core=0": Chromium
|
|
@@ -52,7 +53,27 @@ export default function (mercury: {
|
|
|
52
53
|
if command -v pinchtab >/dev/null 2>&1 && _pinchtab_port_open; then
|
|
53
54
|
return 0
|
|
54
55
|
fi
|
|
55
|
-
|
|
56
|
+
# Kill only the daemon THIS function started (and its Chromium children).
|
|
57
|
+
# This used to be a pkill sweep over the whole command line of every process,
|
|
58
|
+
# matching a bare "pinchtab" substring: the caller's own shell, a grep, an
|
|
59
|
+
# editor -- anything whose argv merely mentions the tool -- was killed with a
|
|
60
|
+
# bare "Terminated" and no explanation. The bracket trick in that old pattern
|
|
61
|
+
# only excluded pkill's own argv, never the caller's. Record the pid instead.
|
|
62
|
+
# grep -qa on /proc/PID/cmdline (NUL-separated) avoids writing a NUL escape
|
|
63
|
+
# inside this TS template literal, where it would collapse before reaching
|
|
64
|
+
# disk -- the same collapse that produced the multiPartTld wildcard bug.
|
|
65
|
+
_pinchtab_kill_stale() {
|
|
66
|
+
local old
|
|
67
|
+
old="$(cat "$pidfile" 2>/dev/null)" || return 0
|
|
68
|
+
[ -n "$old" ] || return 0
|
|
69
|
+
# PIDs are reused: only kill if it is still a pinchtab.
|
|
70
|
+
if grep -qa pinchtab "/proc/$old/cmdline" 2>/dev/null; then
|
|
71
|
+
pkill -TERM -P "$old" 2>/dev/null || true
|
|
72
|
+
kill -TERM "$old" 2>/dev/null || true
|
|
73
|
+
fi
|
|
74
|
+
rm -f "$pidfile"
|
|
75
|
+
}
|
|
76
|
+
_pinchtab_kill_stale
|
|
56
77
|
# pinchtab >=0.13 ships IDPI enforcing with a loopback-only website
|
|
57
78
|
# whitelist, so every public URL is refused with 403 idpi_domain_blocked --
|
|
58
79
|
# including the Brave search this skill tells the agent to run. Widen the
|
|
@@ -89,6 +110,7 @@ export default function (mercury: {
|
|
|
89
110
|
fi
|
|
90
111
|
nohup pinchtab server >>"$log" 2>&1 &
|
|
91
112
|
local pid=$!
|
|
113
|
+
echo "$pid" >"$pidfile"
|
|
92
114
|
sleep 2
|
|
93
115
|
if ! kill -0 "$pid" 2>/dev/null; then
|
|
94
116
|
echo "pinchtab exited immediately (pid $pid). Log:" >&2
|
|
@@ -119,6 +141,17 @@ export default function (mercury: {
|
|
|
119
141
|
let sessionPromptFragment = "";
|
|
120
142
|
|
|
121
143
|
if (process.env.MERCURY_BROWSER_SESSIONS) {
|
|
144
|
+
// The `multiPartTld` regex below writes both of its dots as `\\.`, and
|
|
145
|
+
// that doubling is load-bearing: this is a TS template literal, so one
|
|
146
|
+
// backslash collapses on evaluation and a single `\.` would reach disk as
|
|
147
|
+
// a bare dot — a wildcard where a literal dot is meant. That was the bug
|
|
148
|
+
// in `pinchtab-multipart-tld-regex-dots-are-wildcards`; Biome's
|
|
149
|
+
// noUselessEscapeInString does not flag a doubled backslash, so the
|
|
150
|
+
// autofix that erased the original escapes cannot recur. This note lives
|
|
151
|
+
// out here because everything inside the backticks is shipped to the
|
|
152
|
+
// container, where "TS template literal" means nothing.
|
|
153
|
+
// tests/pinchtab-prompt.test.ts pins the EMITTED form, not this source.
|
|
154
|
+
//
|
|
122
155
|
// Node.js injection script — pure ES5-style, no backticks or ${} so no TS escaping needed.
|
|
123
156
|
// Reads MERCURY_BROWSER_SESSIONS from env, looks up the domain, injects cookies +
|
|
124
157
|
// localStorage via the pinchtab HTTP bridge, then reloads. Exits 0 on success (session
|
|
@@ -131,12 +164,8 @@ var sessions;
|
|
|
131
164
|
try { sessions = JSON.parse(Buffer.from(raw, "base64").toString()); } catch (e) { process.exit(1); }
|
|
132
165
|
var hostname = (new URL(url)).hostname;
|
|
133
166
|
var parts = hostname.split(".");
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
// is evaluated, long before the script reaches disk. Spelled out in words here
|
|
137
|
-
// because writing the escape itself would be stripped the same way. Left as-is:
|
|
138
|
-
// restoring the intent would change emitted behaviour, so it is filed, not fixed.
|
|
139
|
-
var multiPartTld = /.(co|com|org|net|gov|ac|edu|or|ne|gr|gen|plc|ltd|me).[a-z]{2}$/i;
|
|
167
|
+
// eTLD+1: the dots are literal, so only a genuine multi-part TLD takes slice(-3).
|
|
168
|
+
var multiPartTld = /\\.(co|com|org|net|gov|ac|edu|or|ne|gr|gen|plc|ltd|me)\\.[a-z]{2}$/i;
|
|
140
169
|
var domain = parts.length <= 2 ? hostname : (multiPartTld.test(hostname) ? parts.slice(-3).join(".") : parts.slice(-2).join("."));
|
|
141
170
|
var b64 = sessions[domain];
|
|
142
171
|
if (!b64) process.exit(1);
|
|
@@ -38,6 +38,7 @@ pinchtab_ensure() {
|
|
|
38
38
|
local bind="${BRIDGE_BIND:-127.0.0.1}"
|
|
39
39
|
local port="${BRIDGE_PORT:-9867}"
|
|
40
40
|
local log="${PINCHTAB_LOG:-/tmp/pinchtab.log}"
|
|
41
|
+
local pidfile="${PINCHTAB_PIDFILE:-/tmp/pinchtab.pid}"
|
|
41
42
|
local max_wait="${1:-120}"
|
|
42
43
|
mkdir -p "$(dirname "$log")" 2>/dev/null || true
|
|
43
44
|
# Chromium helper processes segfault under the container sandbox; each dump is
|
|
@@ -66,7 +67,24 @@ pinchtab_ensure() {
|
|
|
66
67
|
if command -v pinchtab >/dev/null 2>&1 && _pinchtab_port_open; then
|
|
67
68
|
return 0
|
|
68
69
|
fi
|
|
69
|
-
|
|
70
|
+
# Kill only the daemon THIS function started (and its Chromium children).
|
|
71
|
+
# This used to be a pkill sweep over the whole command line of every process,
|
|
72
|
+
# matching a bare "pinchtab" substring: the caller's own shell, a grep, an
|
|
73
|
+
# editor -- anything whose argv merely mentions the tool -- was killed with a
|
|
74
|
+
# bare "Terminated" and no explanation. The bracket trick in that old pattern
|
|
75
|
+
# only excluded pkill's own argv, never the caller's. Record the pid instead.
|
|
76
|
+
_pinchtab_kill_stale() {
|
|
77
|
+
local old
|
|
78
|
+
old="$(cat "$pidfile" 2>/dev/null)" || return 0
|
|
79
|
+
[ -n "$old" ] || return 0
|
|
80
|
+
# PIDs are reused: only kill if it is still a pinchtab.
|
|
81
|
+
if grep -qa pinchtab "/proc/$old/cmdline" 2>/dev/null; then
|
|
82
|
+
pkill -TERM -P "$old" 2>/dev/null || true
|
|
83
|
+
kill -TERM "$old" 2>/dev/null || true
|
|
84
|
+
fi
|
|
85
|
+
rm -f "$pidfile"
|
|
86
|
+
}
|
|
87
|
+
_pinchtab_kill_stale
|
|
70
88
|
# pinchtab >=0.13 ships IDPI enforcing with a loopback-only website whitelist,
|
|
71
89
|
# so every public URL is refused with 403 idpi_domain_blocked -- including the
|
|
72
90
|
# Brave search this skill tells the agent to run. Widen the allowlist but keep
|
|
@@ -98,6 +116,7 @@ pinchtab_ensure() {
|
|
|
98
116
|
fi
|
|
99
117
|
nohup pinchtab server >>"$log" 2>&1 &
|
|
100
118
|
local pid=$!
|
|
119
|
+
echo "$pid" >"$pidfile"
|
|
101
120
|
sleep 2
|
|
102
121
|
if ! kill -0 "$pid" 2>/dev/null; then
|
|
103
122
|
echo "pinchtab exited immediately (pid $pid). Log:" >&2
|
|
@@ -134,6 +153,14 @@ pinchtab text
|
|
|
134
153
|
|
|
135
154
|
If `pinchtab_ensure` fails, show the user the tail of `/tmp/pinchtab.log`; do not only increase `sleep` and retry blindly.
|
|
136
155
|
|
|
156
|
+
**Inside the container, start the daemon only through `pinchtab_ensure`.** It
|
|
157
|
+
records the daemon's pid in `$PINCHTAB_PIDFILE` (default `/tmp/pinchtab.pid`)
|
|
158
|
+
and that record is the only thing a later call uses to clear a stale daemon. A
|
|
159
|
+
daemon started as a bare `pinchtab server &` — the quick-start above and the
|
|
160
|
+
"Advanced" options below both show that form, which is correct outside Mercury —
|
|
161
|
+
writes no pidfile, so it is never cleaned up and will hold the port against the
|
|
162
|
+
next `pinchtab_ensure`.
|
|
163
|
+
|
|
137
164
|
### Recommended Secure Setup
|
|
138
165
|
|
|
139
166
|
```bash
|
|
@@ -70,7 +70,12 @@ the ones that apply, delete the rest:>
|
|
|
70
70
|
"users here are developers; show the command you ran when asked">.
|
|
71
71
|
- Standing instructions from members: <what you do with "from now on…" from
|
|
72
72
|
a non-admin — relay to the admin in one line / decline once / treat as
|
|
73
|
-
banter
|
|
73
|
+
banter>. Know what you are overriding: a personality, tone, greeting or
|
|
74
|
+
character request already gets a one-line "the owner sets it" decline from
|
|
75
|
+
the platform text, which every caller receives. Any *other* standing request
|
|
76
|
+
(a language, a length, a format) has **no** platform default for a member —
|
|
77
|
+
the procedure that would turn it into a preference is gated on `prefs.set`,
|
|
78
|
+
so if you do not say what happens here, nothing does.
|
|
74
79
|
- Concision / clarification: <"a factual question gets a full answer, not a
|
|
75
80
|
teaser" | "act on a reasonable reading; do not ask before acting">.
|
|
76
81
|
|
|
@@ -6,11 +6,17 @@
|
|
|
6
6
|
## תפקיד
|
|
7
7
|
|
|
8
8
|
כתב הכדורגל של הקבוצה. הסיקור: ישראלים בחו"ל, הפועל תל אביב, בית"ר ירושלים,
|
|
9
|
-
מכבי חיפה, מנצ'סטר יונייטד, ברצלונה, ריאל מדריד, וקבוצות
|
|
9
|
+
מכבי חיפה, מכבי תל אביב, מנצ'סטר יונייטד, ברצלונה, ריאל מדריד, וקבוצות
|
|
10
|
+
ישראליות באירופה.
|
|
10
11
|
לשלושת המועדונים הגדולים, יונייטד וברצלונה וריאל, משקל שווה בדיוק: אף אחד לא
|
|
11
12
|
מקבל יותר מקום מהאחרים. שאלה עובדתית מקבלת תשובה מלאה, לא טיזר. שטות מקבלת
|
|
12
13
|
שטות.
|
|
13
14
|
|
|
15
|
+
כדורגל נשים וכדורגל נוער הם מחוץ לסיקור, בכל שפה ובכל תחרות — גם כשמדובר
|
|
16
|
+
באחד הנושאים שכן מסוקרים, וגם כשהפריט הגיע אליך כי סינון הכותרות פספס
|
|
17
|
+
אותו. פריט כזה לא נכנס לסריקה ולא לכתבה. אם חבר שואל עליו במפורש, עונים
|
|
18
|
+
כרגיל אבל בלי לפתוח לזה פנקס; פשוט לא מדווחים עליו ביוזמתך.
|
|
19
|
+
|
|
14
20
|
## עדיפויות
|
|
15
21
|
|
|
16
22
|
כששני כללים כאן מושכים לכיוונים שונים, זה הסדר:
|
|
@@ -162,9 +168,10 @@
|
|
|
162
168
|
- תאריך בסוגריים: יום וחודש בלבד (למשל 25/08), בלי שנה. השנה עדיין חובה
|
|
163
169
|
לוודא במקור לפני הכתיבה — היא פשוט לא מוצגת.
|
|
164
170
|
- אימוג'י מועדון קבוע, בתחילת השורה, רק בסריקה (לא בכתבה, לא בצ'אט):
|
|
165
|
-
מנצ'סטר יונייטד
|
|
166
|
-
בית"ר ירושלים
|
|
167
|
-
העברות כללית, או ישראלי במועדון אחר) בלי אימוג'י בכלל —
|
|
171
|
+
מנצ'סטר יונייטד 👹, ברצלונה ❤️💙, ריאל מדריד 🤍, הפועל תל אביב ❤️,
|
|
172
|
+
בית"ר ירושלים 💛🖤, מכבי חיפה 💚, מכבי תל אביב 💛💙. פריט שלא נוגע לאף אחד
|
|
173
|
+
מהם (למשל סאגת העברות כללית, או ישראלי במועדון אחר) בלי אימוג'י בכלל —
|
|
174
|
+
לא ממציאים אחד.
|
|
168
175
|
- קיבוץ: כשכמה פריטים באותה סריקה נוגעים לאותו מועדון, הם נכתבים ברצף עם
|
|
169
176
|
שורת כותרת אחת לשם המועדון (בלי אימוג'י כפול על כל שורה בתוך הקבוצה,
|
|
170
177
|
האימוג'י יושב פעם אחת ליד שם הכותרת). מועדון עם פריט בודד לא מקבל כותרת,
|
|
@@ -196,6 +203,11 @@
|
|
|
196
203
|
או הערה באנגלית (למשל "Good, already up to date. Now the chat reply.")
|
|
197
204
|
לא נכנס להודעה בשום צורה, גם לא כשורה ראשונה. אם יש צורך לחשוב בקול, זה
|
|
198
205
|
קורה מחוץ להודעה שנשלחת, לא בתוכה.
|
|
206
|
+
- שורה נכתבת פעם אחת. אם באמצע הכתיבה מתברר שהפרט שגוי, מוחקים את השורה
|
|
207
|
+
וכותבים אותה מחדש נכון: התיקון מחליף את השורה, אף פעם לא נוסף אחריה.
|
|
208
|
+
בהודעה שנשלחת אין "רגע,", אין "סליחה," ואין "תיקון:". הקורא בקבוצה רואה
|
|
209
|
+
בוט שמתקן את עצמו בקול, והפרט השגוי נשאר מול העיניים גם אחרי התיקון. זה
|
|
210
|
+
אותו כלל כמו הסעיף שמעל, בעברית במקום באנגלית.
|
|
199
211
|
|
|
200
212
|
## שתיקה
|
|
201
213
|
|
|
@@ -17,7 +17,7 @@ ambient traffic is therefore **0**, member-facing checks in
|
|
|
17
17
|
member rows from the space's earlier life are kept on purpose (owner's
|
|
18
18
|
decision D7, 2026-09-02): the real group is the same people, so the rows
|
|
19
19
|
become correct again at the link. Posting budget is the real-group setting
|
|
20
|
-
already (`feed-watch.max_per_hour:
|
|
20
|
+
already (`feed-watch.max_per_hour: 3`, `batch_minutes: 15`; D-024). Task 24
|
|
21
21
|
(the 09:00 article) runs on demand here; the harness runs with
|
|
22
22
|
`--allow-linked` and rewrites history.
|
|
23
23
|
|
|
@@ -117,10 +117,11 @@ extension_config:
|
|
|
117
117
|
# setter of any profile-owned key whose live value a person wrote.
|
|
118
118
|
#
|
|
119
119
|
# The list a fresh space starts from, for the record. Maccabi Haifa was
|
|
120
|
-
# missing until M2.3 — it is one of the
|
|
121
|
-
#
|
|
122
|
-
#
|
|
123
|
-
#
|
|
120
|
+
# missing until M2.3 — it is one of the coverage topics in AGENTS.md and one
|
|
121
|
+
# of the seeded notebooks. Maccabi Tel Aviv joined the standing coverage on
|
|
122
|
+
# 2026-09-03 (the owner, from chat; D-023) and has a seeded notebook too.
|
|
123
|
+
# Hapoel Be'er Sheva is not a standing coverage topic; it is watched because
|
|
124
|
+
# "Israeli clubs in Europe" is one.
|
|
124
125
|
# feed-watch.terms: |
|
|
125
126
|
# ["מנצ'סטר יונייטד","מאן יונייטד","Manchester United","Man Utd",
|
|
126
127
|
# "ברצלונה","Barcelona","ריאל מדריד","Real Madrid",
|
|
@@ -131,7 +132,35 @@ extension_config:
|
|
|
131
132
|
# stripped, so `מנצ'סטר יונייטד` also catches `למנצ'סטר יונייטד`. The bare
|
|
132
133
|
# word `יונייטד` is deliberately absent: it would match Newcastle and Leeds
|
|
133
134
|
# every match day.
|
|
134
|
-
|
|
135
|
+
# The exclude list is matched over title plus summary like the terms, but
|
|
136
|
+
# anchored at the **start of a word** since 2026-09-06 (Hebrew prefixes
|
|
137
|
+
# looked through, the end of the word still open — see
|
|
138
|
+
# `docs/debug/minor/2026-09-06-feed-watch-hebrew-exclude-term-over-matches-a-longer-word.md`,
|
|
139
|
+
# where `נשים` was dropping every headline containing `אנשים`, "people").
|
|
140
|
+
# An exclusion still only catches headlines in the language it was written
|
|
141
|
+
# in. `נשים` and `WSL` said "women's football is out of scope" and let three
|
|
142
|
+
# English items through in two days on 2026-09-04/05
|
|
143
|
+
# (`docs/debug/minor/2026-09-06-football-womens-football-slips-past-feed-watch-exclude.md`),
|
|
144
|
+
# because `Arsenal to face Barca & Lyon in Women's Champions League` carries
|
|
145
|
+
# neither. Every added form is a title the live feeds actually publish:
|
|
146
|
+
# `Women` still covers `Women's` and `Womens` (the apostrophe is stripped,
|
|
147
|
+
# and only the front of the word is anchored). `NWSL` is listed in its own
|
|
148
|
+
# right — under the anchor `WSL` no longer reaches inside it.
|
|
149
|
+
#
|
|
150
|
+
# The Catalan `Femení` is deliberately NOT here, and neither is the shorter
|
|
151
|
+
# `Femen` that would have covered it. **Kiko Femenía** is a men's La Liga
|
|
152
|
+
# right-back, the two Marca feeds above are Spanish-language, and `normalize`
|
|
153
|
+
# does not strip Latin diacritics — so both `Femen` and `Femení` open the
|
|
154
|
+
# word `femenía` and would drop a men's item naming him, silently and with no
|
|
155
|
+
# trace. The front anchor does not help here: the surname *starts* with those
|
|
156
|
+
# letters. It is the same silent-drop failure the terms comment warns about
|
|
157
|
+
# (`City` inside *Capacity*), in the direction that loses a story instead of
|
|
158
|
+
# posting a bad one. `Femenino`/`Femenina` are safe (the `í` and the second
|
|
159
|
+
# `n` both differ), so Spanish is filtered and Catalan is left to the prose.
|
|
160
|
+
#
|
|
161
|
+
# The list is still only as good as its substrings — the backstop for what it
|
|
162
|
+
# misses is the coverage rule in `AGENTS.md § תפקיד`, not another substring.
|
|
163
|
+
feed-watch.exclude: '["נוער","נשים","fantasy","WSL","NWSL","U21","U19","טוטו","הימור","Women","UWCL","Lionesses","Femenino","Femenina"]'
|
|
135
164
|
# Nothing is opened between 00:30 and 07:30 local; matched items still reach
|
|
136
165
|
# the 09:00 article through the digest, which is the whole point of buffering
|
|
137
166
|
# separately from reporting.
|
|
@@ -144,11 +173,14 @@ extension_config:
|
|
|
144
173
|
# which answered NO_UPDATE. Lowered 2026-08-31 to 1/hour and a 15-minute
|
|
145
174
|
# batch: a wider batch also merges more outlets carrying one story into a
|
|
146
175
|
# single run, which is what the verify prompt asks the model to do anyway.
|
|
176
|
+
# Back to 3/hour on 2026-09-03 (owner's call, set from the dashboard and then
|
|
177
|
+
# confirmed in writing; D-024). The batch stays at 15 minutes, so at most four
|
|
178
|
+
# batches an hour can open and the cap only bites on a burst.
|
|
147
179
|
#
|
|
148
180
|
# These reduce the *number* of runs. They are not the digest fix — see
|
|
149
181
|
# `docs/debug/major/2026-08-31-feed-watch-digest-persisted-and-replayed.md` for the prefix size,
|
|
150
182
|
# which is the other factor in the same product.
|
|
151
|
-
feed-watch.max_per_hour: "
|
|
183
|
+
feed-watch.max_per_hour: "3"
|
|
152
184
|
feed-watch.batch_minutes: "15"
|
|
153
185
|
|
|
154
186
|
# The other factor in the same product: how big each run's prompt is. The
|
|
@@ -216,3 +248,7 @@ workspace_seed:
|
|
|
216
248
|
knowledge/episodes/real-madrid-2026-27.md: ./seed/episodes/real-madrid-2026-27.md
|
|
217
249
|
knowledge/episodes/beitar-jerusalem-2026-27.md: ./seed/episodes/beitar-jerusalem-2026-27.md
|
|
218
250
|
knowledge/episodes/maccabi-haifa-2026-27.md: ./seed/episodes/maccabi-haifa-2026-27.md
|
|
251
|
+
# Added 2026-09-03 with the club (D-023). The live space already had this
|
|
252
|
+
# notebook — napkin opened it on 2026-08-31 — so `apply` there writes nothing;
|
|
253
|
+
# the seed is for a space that starts from this profile.
|
|
254
|
+
knowledge/episodes/maccabi-tel-aviv-2026-27.md: ./seed/episodes/maccabi-tel-aviv-2026-27.md
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"מחברת". כאן רק הרשימה, כדי שלא אצטרך לחפש:
|
|
14
14
|
|
|
15
15
|
`man-united-2026-27`, `barcelona-2026-27`, `real-madrid-2026-27`,
|
|
16
|
-
`beitar-jerusalem-2026-27`, `maccabi-haifa-2026-27`,
|
|
16
|
+
`beitar-jerusalem-2026-27`, `maccabi-haifa-2026-27`, `maccabi-tel-aviv-2026-27`,
|
|
17
17
|
`israeli-clubs-europe-2026-qualifiers` (וגם הפועל ת"א נמצאת שם, אין לה
|
|
18
18
|
פנקס נפרד), `summer-2026-transfer-window`, `toto-cup-2026`.
|
|
19
19
|
|
|
@@ -4,7 +4,7 @@ status: active
|
|
|
4
4
|
started: 2026-08-21
|
|
5
5
|
last_mentioned: 2026-08-21
|
|
6
6
|
mentions: 1
|
|
7
|
-
keywords: ["ביתר", "
|
|
7
|
+
keywords: ["ביתר", "ירושלים", "beitar", "jerusalem", "גדראני", "טוטו"]
|
|
8
8
|
summary: בית"ר ירושלים 2026-27 — בלי אירופה אחרי ההדחה בווינה; העונה היא ליגה וגביע הטוטו.
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
type: episode
|
|
3
|
+
status: active
|
|
4
|
+
started: 2026-09-03
|
|
5
|
+
last_mentioned: 2026-09-03
|
|
6
|
+
mentions: 1
|
|
7
|
+
keywords: ["מכבי", "תל", "אביב", "maccabi", "tel", "aviv", "בלומפילד"]
|
|
8
|
+
summary: מכבי תל אביב 2026-27 — הפנקס נפתח כמעט ריק ביום שהמועדון נכנס לסיקור הקבוע (03/09); מה שאני מוסר עליו נכתב כאן, עם מקור ותאריך, לפני שהוא נשלח.
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# מכבי תל אביב 2026-27
|
|
12
|
+
|
|
13
|
+
הפנקס הקבוע של המועדון בליגת העל ובחלון ההעברות. מכבי תל אביב נכנסה לסיקור
|
|
14
|
+
הקבוע ב-03/09 (הכרעת המנהל בצ'אט), ולכן הפנקס קיים גם כשאין בו כמעט כלום:
|
|
15
|
+
מה שאני מוסר עליה נכתב כאן, עם מקור ותאריך, לפני שהוא נשלח. המסע האירופי
|
|
16
|
+
של העונה יושב ב-[[israeli-clubs-europe-2026-qualifiers]] ולא כאן.
|
|
17
|
+
|
|
18
|
+
## Current State
|
|
19
|
+
<!-- נכון ל-2026-09-03. הכותרת חייבת להיות בדיוק "## Current State" — סיומת בסוגריים מפילה את ההזרקה. -->
|
|
20
|
+
- (אין עובדה) אין עדיין פריט מאומת על הליגה או על סגל העונה.
|
|
21
|
+
|
|
22
|
+
## History
|
|
23
|
+
<!-- append-only; newest first -->
|
|
24
|
+
- 2026-09-03: הפנקס נפתח על ידי הפרופיל ביום שהמועדון נוסף לסיקור הקבוע. נפתח כמעט ריק בכוונה — עדיף פנקס שאומר "אין לי כלום" על פני השלמה מהזיכרון.
|
|
@@ -1,55 +1,56 @@
|
|
|
1
1
|
# מה לזקק במרחב הזה
|
|
2
2
|
|
|
3
|
-
המרחב הזה הוא קבוצת חברים שמדברת כדורגל, והבוט בה הוא כתב.
|
|
4
|
-
|
|
3
|
+
המרחב הזה הוא קבוצת חברים שמדברת כדורגל, והבוט בה הוא כתב. מה שנשמר צריך
|
|
4
|
+
להיות שימושי בתשובה עובדתית למחרת.
|
|
5
5
|
|
|
6
6
|
## ישויות
|
|
7
7
|
|
|
8
|
-
- **מועדון** → פנקס קבוע אחד,
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
כשהיא נסגרת.
|
|
15
|
-
- שיחות על עבודת פיתוח, על הבוט עצמו, ומשחקי חברה בקבוצה — לא נכנסים
|
|
16
|
-
לפנקסי המועדונים. פנקס נפרד, אם בכלל.
|
|
8
|
+
- **מועדון** → פנקס קבוע אחד, `<club>-2026-27.md` (`barcelona-2026-27.md`).
|
|
9
|
+
אל תפתח פנקס שני לאותו מועדון — עדכן את הקיים.
|
|
10
|
+
- **מפעל** (ליגה, גביע, מוקדמות) → פנקס אחד למפעל ולעונה, `toto-cup-2026.md`.
|
|
11
|
+
- **סאגה** (העברה מתמשכת, פציעה, סכסוך) → פנקס משלה, `status: resolved` בסגירה.
|
|
12
|
+
- שיחות על פיתוח, על הבוט עצמו ומשחקי חברה — לא נכנסים לפנקסי המועדונים.
|
|
13
|
+
פנקס נפרד, אם בכלל.
|
|
17
14
|
|
|
18
15
|
## מילות מפתח
|
|
19
16
|
|
|
20
17
|
`keywords` הן מה שמחבר הודעה בצ'אט לפנקס, ולכן:
|
|
21
18
|
|
|
22
|
-
- **עברית ואנגלית לאותו דבר**: `["יונייטד", "united"
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
19
|
+
- **עברית ואנגלית לאותו דבר**: `["יונייטד", "united"]` — כותבים בשתי השפות.
|
|
20
|
+
- **מילה אחת, בלי פיסוק ובלי מקף.** גרש וגרשיים בתוך מילה בהודעה מוסרים
|
|
21
|
+
(`לבית"ר` מוצא את `ביתר`), אבל מילת מפתח לא עוברת ניקוי — `מנצ'סטר`
|
|
22
|
+
ו-`ת"א` לא יתאימו. במקומן: `יונייטד`, `ביתר`, `ירושלים`, `חיפה`.
|
|
23
|
+
- **המילה הבסיסית, פעם אחת.** אותיות שימוש (ו, ה, ב, ל, מ, ש, כ) בתחילת
|
|
24
|
+
המילה בהודעה מתאימות מעצמן — `ליונייטד` ו-`וכשיונייטד` מוצאים את
|
|
25
|
+
`יונייטד` — כל עוד נשארות ארבע אותיות, וחמש אחרי מ'. אל תוסיף צורות כמו
|
|
26
|
+
`ליונייטד` כמילות מפתח: כל מילת מפתח נוספת מורידה את ציון הפנקס. במילה
|
|
27
|
+
קצרה בדוק ו/ה/ב/ל/ש/כ + המילה (מ' מטופלת כבר): אם יוצאת מילה אחרת
|
|
28
|
+
קיימת, בחר אחרת.
|
|
28
29
|
|
|
29
30
|
## עובדות
|
|
30
31
|
|
|
31
32
|
- הרכב, תוצאה, פציעה, תאריך משחק ומעבר הם עובדות. כל שורה נושאת **מקור
|
|
32
33
|
ותאריך** בסוגריים בסופה: `(ONE, 20/08)`. שורה בלי מקור ותאריך לא נכתבת.
|
|
33
34
|
- שתי שורות מותרות בלי מקור, ורק הן, ושתיהן נפתחות בסימון: `(אין עובדה)`
|
|
34
|
-
לשורה שאומרת שאין עדיין מה לדעת, ו-`(מצביע)` לשורה
|
|
35
|
-
|
|
36
|
-
- כותרת הסעיף היא בדיוק `## Current State`, בלי שום סיומת.
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
35
|
+
לשורה שאומרת שאין עדיין מה לדעת, ו-`(מצביע)` לשורה שכולה הפניה לקובץ
|
|
36
|
+
אחר. אל תמחק סימונים ואל תמציא חדשים.
|
|
37
|
+
- כותרת הסעיף היא בדיוק `## Current State`, בלי שום סיומת. תאריך העדכון
|
|
38
|
+
נכתב בשורה נפרדת מתחת לכותרת.
|
|
39
|
+
- `## Current State` מחזיק **רק את מה שנכון עכשיו, ולא יותר מ-12 שורות**.
|
|
40
|
+
שורה שהוחלפה (הרכב משוער שהוחלף ברשמי, תוצאה שהתעדכנה, פציעה שהחלימה)
|
|
41
|
+
ושורה שהתאריך בסוגריים שלה ישן מ-14 יום — גם אם היא עדיין נכונה — יורדות
|
|
42
|
+
ל-`## History` עם התאריך ועם הסיבה. אם אחרי זה נשארו יותר מ-12 שורות,
|
|
43
|
+
מורידים את הישנות ביותר עד שנשארות 12. לא מוחקים, רק מורידים.
|
|
43
44
|
- דרגת ודאות שהמקור נתן (רשמי / סגור / מתקדם / שמועה) נשמרת כמו שהיא.
|
|
44
45
|
אל תשדרג שמועה לעובדה ואל תוריד עובדה לשמועה.
|
|
45
46
|
- הפנקס בעברית, כמו הקבוצה.
|
|
46
47
|
|
|
47
48
|
## אנשים
|
|
48
49
|
|
|
49
|
-
בפנקסי `people/` נשמרות העדפות והרגלים, לא מזהים: בלי
|
|
50
|
-
|
|
50
|
+
בפנקסי `people/` נשמרות העדפות והרגלים, לא מזהים: בלי טלפונים, בלי מזהי
|
|
51
|
+
וואטסאפ ובלי כתובות.
|
|
51
52
|
|
|
52
53
|
## תיקיית `.napkin`
|
|
53
54
|
|
|
54
55
|
`.napkin/distill.md` — הקובץ הזה — הוא הנחיה, לא ידע. אל תערוך אותו, אל
|
|
55
|
-
תעביר ממנו תוכן לפנקסים ואל תכתוב
|
|
56
|
+
תעביר ממנו תוכן לפנקסים ואל תכתוב דבר אחר לתוך `.napkin/`.
|
|
@@ -14,13 +14,22 @@
|
|
|
14
14
|
"this file second, and let the test tell you if you missed one."
|
|
15
15
|
],
|
|
16
16
|
|
|
17
|
+
"$clubEmoji_comment": [
|
|
18
|
+
"The marker a scan item opens with. Since the owner's 2026-09-03 edit (D-023)",
|
|
19
|
+
"a marker may be TWO emoji; the lint compares the whole run at line start as",
|
|
20
|
+
"one unit, so ❤\uFE0F💙 is Barcelona and a bare ❤\uFE0F is Hapoel, never half of both.",
|
|
21
|
+
"The heart is written with an escaped U+FE0F because the bot writes it that",
|
|
22
|
+
"way and the selector is invisible in an editor; the lint ignores selectors",
|
|
23
|
+
"when it compares, so a phone that drops or adds one still matches."
|
|
24
|
+
],
|
|
17
25
|
"clubEmoji": [
|
|
18
|
-
{ "emoji": "
|
|
19
|
-
{ "emoji": "
|
|
20
|
-
{ "emoji": "
|
|
21
|
-
{ "emoji": "
|
|
22
|
-
{ "emoji": "
|
|
23
|
-
{ "emoji": "
|
|
26
|
+
{ "emoji": "👹", "names": ["מנצ'סטר יונייטד", "מאן יונייטד", "יונייטד", "Manchester United", "Man Utd"] },
|
|
27
|
+
{ "emoji": "❤\uFE0F💙", "names": ["ברצלונה", "Barcelona", "ברסה"] },
|
|
28
|
+
{ "emoji": "🤍", "names": ["ריאל מדריד", "ריאל", "Real Madrid"] },
|
|
29
|
+
{ "emoji": "❤\uFE0F", "names": ["הפועל תל אביב", "הפועל ת\"א", "Hapoel Tel Aviv"] },
|
|
30
|
+
{ "emoji": "💛🖤", "names": ["בית\"ר ירושלים", "ביתר ירושלים", "בית\"ר", "Beitar Jerusalem"] },
|
|
31
|
+
{ "emoji": "💚", "names": ["מכבי חיפה", "Maccabi Haifa"] },
|
|
32
|
+
{ "emoji": "💛💙", "names": ["מכבי תל אביב", "מכבי ת\"א", "Maccabi Tel Aviv"] }
|
|
24
33
|
],
|
|
25
34
|
|
|
26
35
|
"caps": {
|
|
@@ -107,6 +116,33 @@
|
|
|
107
116
|
|
|
108
117
|
"fillerAcks": ["בוצע", "Done", "סיימתי", "בדקתי", "מקובל."],
|
|
109
118
|
|
|
119
|
+
"$selfCorrectionMarkers_comment": [
|
|
120
|
+
"N-4: the markers a published mid-sentence self-correction is written with.",
|
|
121
|
+
"Read by the no-self-correction lint rule. Message #4107 (2026-09-02) is the",
|
|
122
|
+
"case: `… ובית\"ר... רגע, על פיינורד-ברצלונה …`.",
|
|
123
|
+
"",
|
|
124
|
+
"Two lists, because each of these is also an ordinary Hebrew word and the",
|
|
125
|
+
"shape is what distinguishes a correction from prose:",
|
|
126
|
+
"",
|
|
127
|
+
" afterBreak - counts only behind a sentence break (… ... . ! ? — –) AND in",
|
|
128
|
+
" front of a comma. Either half alone has a counter-example in",
|
|
129
|
+
" football copy: 'ביקש סליחה, ואז' is the comma with no break,",
|
|
130
|
+
" 'הוא הבקיע. רגע קסם' is the break with no comma.",
|
|
131
|
+
" always - a correction marker wherever it stands.",
|
|
132
|
+
"",
|
|
133
|
+
"AGENTS.md § פורמט owns the rule and quotes three of these verbatim; the",
|
|
134
|
+
"lint's list is wider, the same trade writeClaimPhrases makes -- the prose",
|
|
135
|
+
"teaches the model the shape, the lint has to catch it however it is",
|
|
136
|
+
"written. `לא -` with an ASCII hyphen is deliberately absent: the hyphen is",
|
|
137
|
+
"a working connector in Hebrew (ל-3.5 שנים) and the long dash is already",
|
|
138
|
+
"ruled out by § פורמט's punctuation bullet."
|
|
139
|
+
],
|
|
140
|
+
"selfCorrectionMarkers": {
|
|
141
|
+
"afterBreak": ["רגע", "סליחה"],
|
|
142
|
+
"always": ["תיקון:", "כלומר לא", "לא —", "לא –"]
|
|
143
|
+
},
|
|
144
|
+
"$selfCorrectionMarkersFromProse": ["רגע,", "סליחה,", "תיקון:"],
|
|
145
|
+
|
|
110
146
|
"escalationPhrases": {
|
|
111
147
|
"$comment": "`fromStandard` is quoted in AGENTS.md as the wrong answer; `fromDecision` is the phrasing D-016 recorded from the live failure. The lint flags either.",
|
|
112
148
|
"fromStandard": ["אין לך הרשאה", "זה לא בסמכות שלי", "המנהל צריך לאשר"],
|
|
@@ -118,7 +154,7 @@
|
|
|
118
154
|
"lineupSectionLabels": ["שוער", "הגנה", "קישור", "חוליה התקפית", "חלוץ", "חלוצים"],
|
|
119
155
|
|
|
120
156
|
"$sources": {
|
|
121
|
-
"clubEmoji": "AGENTS.md § פורמט",
|
|
157
|
+
"clubEmoji": "AGENTS.md § פורמט — seven clubs since 2026-09-03; a marker is the whole emoji run at line start",
|
|
122
158
|
"caps.itemMaxChars": "AGENTS.md § פורמט — 'עד 200 תווים'",
|
|
123
159
|
"caps.summaryMaxChars": "tasks/daily-article.md § בלוק הסיכום — 'עד 900 תווים'; must equal config.yaml longview.summary_max_chars",
|
|
124
160
|
"caps.articleMinChars": "tasks/daily-article.md § אורך — '2,500–4,500 תווים'",
|
|
@@ -132,6 +168,7 @@
|
|
|
132
168
|
"hedgePhrases": "AGENTS.md § ייחוס — 'בלי מילוי מהוסס'",
|
|
133
169
|
"clickbaitWords": "tasks/daily-article.md § אסור",
|
|
134
170
|
"escalationPhrases": "AGENTS.md § היקף + § סגנון (D-016)",
|
|
135
|
-
"relativeDateWords": "AGENTS.md § טריות + D-004"
|
|
171
|
+
"relativeDateWords": "AGENTS.md § טריות + D-004",
|
|
172
|
+
"selfCorrectionMarkers": "AGENTS.md § פורמט — the 'a line is written once' bullet, which quotes רגע, / סליחה, / תיקון: as the words that never reach a sent message (N-4)"
|
|
136
173
|
}
|
|
137
174
|
}
|