@lmzhen/dsh-evolution-core 0.4.0 → 0.5.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.
@@ -0,0 +1,109 @@
1
+ /**
2
+ * Citation resolution for skill bodies and support files (design §5.2).
3
+ *
4
+ * WHY this exists beside `supportRefs` (skill-store.ts): that scanner answers
5
+ * "does this text contain a path-shaped token", which is the right question
6
+ * when a package is being ARCHIVED — every such path may dangle — and the wrong
7
+ * one when a section is only being MOVED, where nothing leaves and the only
8
+ * thing that changes is the directory a citation is read from. Measured false
9
+ * positives of the token scan: a URL tail (`https://host/references/x.md`), a
10
+ * category path the original Hermes documents as legitimate
11
+ * (`skills/scripts/foo.py`), and a prose command line
12
+ * (`npm run scripts/build.mjs`).
13
+ *
14
+ * CONTRACT: a token whose path STARTS WITH a support directory is a citation of
15
+ * this skill and is resolved from the SKILL ROOT, in whichever file it is
16
+ * written. A token that merely contains a support directory further along its
17
+ * path belongs to something else: it is reported as `foreign` and never
18
+ * resolved.
19
+ *
20
+ * PURE: existence is decided against the caller's file list, so identical
21
+ * inputs always answer the same report.
22
+ */
23
+ /** Support directories that make a path a citation of the owning skill. */
24
+ export declare const CITATION_SUPPORT_DIRS: readonly string[];
25
+ /** How one path-shaped token was classified. */
26
+ export type CitationKind =
27
+ /** Starts with a support directory: a citation of this skill. */
28
+ 'citation'
29
+ /** Inside a fenced code block: illustrative, never resolved. */
30
+ | 'fence'
31
+ /** Tail of a URL. */
32
+ | 'url'
33
+ /** Contains a support directory further along its path (`skills/scripts/foo.py`). */
34
+ | 'foreign'
35
+ /** A command line naming a path (`npm run scripts/build.mjs`). */
36
+ | 'prose';
37
+ /** One scanned token with its classification and resolution. */
38
+ export interface CitationRef {
39
+ /** The matched token, verbatim, after trailing sentence punctuation is stripped. */
40
+ raw: string;
41
+ /** 1-based line number in the scanned content. */
42
+ line: number;
43
+ /** Skill-root-relative target, or null when the token is not a citation of this skill. */
44
+ target: string | null;
45
+ /** The base a citation is read from; this scanner resolves the skill root only. */
46
+ base: 'root';
47
+ kind: CitationKind;
48
+ /** Whether `target` names a file in the caller's file list. */
49
+ exists: boolean;
50
+ /** `#fragment` carried by the token, when present. */
51
+ fragment?: string | undefined;
52
+ }
53
+ /** One scan of a body or support file. */
54
+ export interface CitationReport {
55
+ refs: readonly CitationRef[];
56
+ /** Citations whose target is provably absent from the file list. */
57
+ dangling: readonly CitationRef[];
58
+ /** Citations a non-recursive listing cannot decide (target sits under a listed directory). */
59
+ unverified: readonly CitationRef[];
60
+ /** Path-shaped tokens that are not citations of this skill (foreign/url/prose/fence). */
61
+ foreign: readonly CitationRef[];
62
+ /** True when the scan stopped at the budget: a partial report never reads as clean. */
63
+ truncated: boolean;
64
+ }
65
+ /** Scan budget: bounded so a pathological body cannot stall a maintenance run. */
66
+ export declare const DEFAULT_CITATION_REF_BUDGET = 500;
67
+ /**
68
+ * Resolve every path-shaped token in `content`.
69
+ * @param input - content, the skill-root-relative path of its owner, the skill's
70
+ * file list, and an optional scan budget.
71
+ * @returns the refs plus the dangling and foreign subsets; `truncated` marks a
72
+ * report that stopped at the budget.
73
+ */
74
+ export declare function resolveCitations(input: {
75
+ content: string;
76
+ file: string;
77
+ files: readonly string[];
78
+ budget?: number | undefined;
79
+ }): CitationReport;
80
+ /** The sanctioned body hook (design §5.6): a list item whose payload is
81
+ * exactly one support-file path, so the file stays discoverable in the body. */
82
+ export declare const HOOK_LINE_RE: RegExp;
83
+ /** The retirement escape hatch (design §5.6): a standalone body comment that
84
+ * names the support file it exempts and the reason it must survive. The path
85
+ * is part of the marker because the proposal list is per FILE, and a reason is
86
+ * required — an unexplained exemption is what this hook exists to prevent. */
87
+ export declare const KEEP_LINE_RE: RegExp;
88
+ /** Whether a skill-relative path names a FILE rather than a directory: the same
89
+ * rule the scanner applies to a token's final segment (`name.ext`). The support
90
+ * listing is one level deep and includes directory entries (a real library has
91
+ * `references/archive`), which no pointer or retirement list may treat as a file.
92
+ * @param path - a skill-root-relative support path.
93
+ * @returns true when the final segment is file-shaped.
94
+ */
95
+ export declare function isFileShapedPath(path: string): boolean;
96
+ /** Result of one hook scan over a body. */
97
+ export interface BodyHookScan {
98
+ /** Targets named by a sanctioned hook line, in file order, deduplicated. */
99
+ targets: readonly string[];
100
+ /** Target -> the reason its `keep` marker records. */
101
+ kept: ReadonlyMap<string, string>;
102
+ }
103
+ /**
104
+ * Scan a body for sanctioned hooks and `keep` markers.
105
+ * @param content - the SKILL.md body (frontmatter included).
106
+ * @returns hook targets plus the `keep` reasons keyed by target.
107
+ */
108
+ export declare function scanBodyHooks(content: string): BodyHookScan;
109
+ //# sourceMappingURL=citations.d.ts.map
@@ -52,6 +52,26 @@ export declare const PROTECTED_BUILTIN_SKILLS: ReadonlySet<string>;
52
52
  export declare const MAX_SKILL_NAME_LENGTH = 64;
53
53
  export declare const MAX_DESCRIPTION_LENGTH = 1024;
54
54
  export declare const MAX_SKILL_CONTENT_CHARS = 100000;
55
+ /** The authoring DISCIPLINE band, taken from the upstream standard (archive §5):
56
+ * peer skills sit at 8-14k characters and a body pushing past 20k belongs in
57
+ * `references/*.md`. Deliberately separate from `MAX_SKILL_CONTENT_CHARS`: the
58
+ * hard ceiling is a deployment-tunable limit, this band is the authoring
59
+ * standard — deriving the band from the ceiling is exactly what let a 40k
60
+ * ceiling hide a 99k body without a single signal saying "split me" (V3). */
61
+ export declare const AUTHORING_SPLIT_LINE_CHARS = 20000;
62
+ /** Upstream's conversion basis for CHARACTER LIMITS: 2.75 chars/token, labelled
63
+ * model-independent in the config template (\`cli-config.yaml.example:538\`), and the
64
+ * basis behind every quoted token figure there — memory 2200 chars ≈ 800 tokens,
65
+ * user 1375 ≈ 500, SKILL.md 100_000 ≈ 36k (\`tools/skill_manager_tool.py:455\`).
66
+ * Limits are deliberately conservative, so this is the basis a BORROWED LIMIT must
67
+ * be converted with. */
68
+ export declare const UPSTREAM_LIMIT_CHARS_PER_TOKEN = 2.75;
69
+ /** The platform's own estimate basis: \`CHARS_PER_TOKEN = 4\` in
70
+ * \`@deepseek-ai/dsh-token-meter/estimate.ts\` (its comment reads "used until exact
71
+ * tokenization is needed"), matching upstream's ESTIMATE-side heuristic — "~4
72
+ * chars/token is the usual English heuristic" (\`agent/prompt_builder.py:1179\`).
73
+ * Estimates use this; limits use the constant above. */
74
+ export declare const PLATFORM_ESTIMATE_CHARS_PER_TOKEN = 4;
55
75
  export declare const MAX_SKILL_FILE_BYTES = 1048576;
56
76
  export declare const DEFAULT_REVIEW_MEMORY_INTERVAL = 10;
57
77
  export declare const DEFAULT_REVIEW_SKILL_INTERVAL = 10;
@@ -102,6 +122,11 @@ export declare const EVOLUTION_WRITE_TOOLS: readonly ["memory", "skill_manage"];
102
122
  * 0.3.16 (T-4): moved here from skill-store.ts so drift-signals (pure, no IO)
103
123
  * can reference it without importing the skill-store module. */
104
124
  export declare const AUTHORING_DESCRIPTION_BAR = 60;
125
+ /** The split hint both size refusals share (0.5.0 V1). The same sentence used to
126
+ * be copied into validateFrontmatter AND the patch path, and neither copy named
127
+ * where the content should go — the upstream cap message names the destination
128
+ * directories, and that is the part a model actually acts on. */
129
+ export declare const CONTENT_SPLIT_HINT = "Consider splitting into a smaller SKILL.md with supporting files in references/ or templates.";
105
130
  /** V27 G2.4: the largest millisecond delay a timer accepts. `AbortSignal.timeout`
106
131
  * (and `setTimeout`) coerce anything larger to 1ms after a Node warning, so a
107
132
  * timeout configured above this ceiling silently collapses to "immediately
@@ -0,0 +1,63 @@
1
+ /**
2
+ * Context-cost accounting for skill bodies (design §5.2).
3
+ *
4
+ * A raw character count is a poor budget: the same 100k characters cost very
5
+ * different amounts of context in Chinese-heavy prose and in English. The
6
+ * weighted unit makes the two comparable, and the token range exists only to
7
+ * make the load cost visible next to the character count — it is an ESTIMATE,
8
+ * never a measurement.
9
+ *
10
+ * Accounting basis: the ON-DISK form (`skillMdOnDisk()`, the same view the
11
+ * write limit uses), so a body that is exactly at the limit cannot read as
12
+ * over-limit here and pass there (the v37 P2-1 deadlock class).
13
+ */
14
+ /** Token weight of one CJK / kana / full-width code unit on the LIMIT basis —
15
+ * upstream's model-independent conversion is 2.75 chars/token for prose, and CJK
16
+ * prose is ~1 token per character (the conservative end of the 0.6–1.0 range the
17
+ * estimate side reports). Thresholds are compared on THIS basis so a borrowed
18
+ * character line keeps its meaning; the estimate range below reports the spread. */
19
+ export declare const TOKEN_CJK_WEIGHT = 1;
20
+ /** Token weight of one non-CJK code unit on the LIMIT basis (1 / 2.75 ≈ 0.364). */
21
+ export declare const TOKEN_ASCII_WEIGHT: number;
22
+ /** Token-per-unit bounds of the estimate range (CJK: 0.6–1.0, non-CJK: 1/4–1/3).
23
+ * The range is the 4-chars/token estimate family, so on ASCII-heavy bodies the
24
+ * LIMIT-basis `tokens` point can sit above `tokensHigh` (1/2.75 > 1/3): the two
25
+ * answer different questions and are never nested by construction. */
26
+ export declare const COST_CJK_TOKEN_LOW = 0.6;
27
+ export declare const COST_CJK_TOKEN_HIGH = 1;
28
+ export declare const COST_ASCII_TOKEN_LOW = 0.25;
29
+ export declare const COST_ASCII_TOKEN_HIGH: number;
30
+ /** The token line a borrowed CHARACTER threshold draws for ONE body: 20k characters
31
+ * of THIS composition, expressed in the same tokens `bodyCost` counts. Comparing
32
+ * `tokens` against this line is deliberately equivalent to "chars >= line" — that
33
+ * equivalence is what keeps a borrowed line's textual effect identical — while the
34
+ * judgment itself, and every number reported, stays on the token scale.
35
+ * @param lineChars - the borrowed character line (whole-body characters).
36
+ * @param cost - the body's own cost breakdown.
37
+ * @returns the equivalent token line (0 when the body is empty). */
38
+ export declare function tokenLineFor(lineChars: number, cost: BodyCost): number;
39
+ /** Cost of one body: raw counts, the weighted total, and the estimate range. */
40
+ export interface BodyCost {
41
+ /** Code units of the on-disk form — the same measure `maxSkillContentChars` bounds. */
42
+ chars: number;
43
+ /** Code units matched by the CJK ranges. */
44
+ cjk: number;
45
+ /** Code units that are not CJK (includes surrogate halves and syntax). */
46
+ ascii: number;
47
+ /** Single token count on the LIMIT basis: `cjk * TOKEN_CJK_WEIGHT + ascii *
48
+ * TOKEN_ASCII_WEIGHT`, rounded. This is the number every threshold compares
49
+ * against, so a threshold borrowed as a character line converts faithfully. */
50
+ tokens: number;
51
+ /** Lower bound of the token estimate. */
52
+ tokensLow: number;
53
+ /** Upper bound of the token estimate. */
54
+ tokensHigh: number;
55
+ }
56
+ /**
57
+ * Cost of one skill body.
58
+ * @param content - the body text as written (trailing whitespace is normalized
59
+ * away by the on-disk accounting, so callers need not pre-trim).
60
+ * @returns the cost breakdown; an empty body answers all-zero.
61
+ */
62
+ export declare function bodyCost(content: string): BodyCost;
63
+ //# sourceMappingURL=cost.d.ts.map
@@ -81,6 +81,12 @@ export interface CuratorRunReport {
81
81
  llmReviewEnabled?: boolean;
82
82
  /** V6-35 (0.3.36): lenient-parse shape notes from the LLM nomination block. */
83
83
  nominationsWarnings?: string[];
84
+ /** 0.5.0 V1 (design §16.6-④): archived entries past the retention window that
85
+ * the CURRENT policy keeps rather than deletes. Present (even empty) only when
86
+ * the retention policy was `report`, so a report cannot read as "nothing
87
+ * expired" for a run that pruned under a different policy. `null` means the
88
+ * listing could not be read — unknown, never "nothing expired". */
89
+ wouldPrune?: string[] | null;
84
90
  }
85
91
  export interface CuratorReportInput {
86
92
  runId: string;
@@ -99,6 +105,7 @@ export interface CuratorReportInput {
99
105
  snapshotPath?: string;
100
106
  llmReviewEnabled?: boolean;
101
107
  nominationsWarnings?: readonly string[];
108
+ wouldPrune?: readonly string[] | null;
102
109
  }
103
110
  export declare function buildCuratorRunReport(input: CuratorReportInput): CuratorRunReport;
104
111
  /**
@@ -10,6 +10,8 @@
10
10
  *
11
11
  * Distinct from `signals.ts` — the session-level review signal gate.
12
12
  */
13
+ import { type CitationReport } from './citations.ts';
14
+ import { type BodyCost } from './cost.ts';
13
15
  /** One skill's library state; the assembler (not this module) reads IO. */
14
16
  export interface DriftSkillSnapshot {
15
17
  name: string;
@@ -27,6 +29,23 @@ export interface DriftSkillSnapshot {
27
29
  protected?: string | null | undefined;
28
30
  /** Frontmatter values the strict-YAML platform catalog cannot load (0.3.11). */
29
31
  catalogInvalid?: boolean | undefined;
32
+ /** Weighted context cost of the body (design §5.2); undefined = not measured. */
33
+ cost?: BodyCost | undefined;
34
+ /** Citation scan of the body (design §5.2); undefined = not scanned. */
35
+ citations?: CitationReport | undefined;
36
+ /** Per-support-file read counts (design §5.5); undefined = no evidence. */
37
+ demand?: Readonly<Record<string, number>> | undefined;
38
+ /** Idle age of the owning skill (design §5.6); undefined = no record to age. */
39
+ liveness?: SkillLiveness | undefined;
40
+ /** Character counts of support files that can possibly exceed the content cap
41
+ * (design §16.6, V4); undefined = not measured. The assembler pre-filters by
42
+ * byte size, which is complete for the oversize question. */
43
+ supportChars?: Readonly<Record<string, number>> | undefined;
44
+ }
45
+ /** Retirement-proposal input for one skill (design §5.6). */
46
+ export interface SkillLiveness {
47
+ /** Idle days since the lifecycle age anchor (`last activity ?? created_at`). */
48
+ idleDays: number;
30
49
  }
31
50
  /** verdict=over means "relatively positioned above the threshold", never a violation. */
32
51
  type DriftVerdict = 'pass' | 'over' | 'unknown';
@@ -56,11 +75,39 @@ export interface DriftReport {
56
75
  /** Physical line length at/above which a body line is reported overlong (011 §4). */
57
76
  export declare const DRIFT_MAX_LINE_CHARS = 1500;
58
77
  /** Signal-set version: bump whenever ids/thresholds change (011 §7 version coupling). */
59
- export declare const DRIFT_SIGNALS_VERSION = "1";
78
+ export declare const DRIFT_SIGNALS_VERSION = "3";
60
79
  /** Render-time nouns for the MAINTAIN_PROMPT placeholders (single vocabulary with the facts block). */
61
80
  export declare const DRIFT_SIGNAL_NOUNS: Readonly<Record<string, string>>;
62
81
  /** Detect support files the body never references (by basename or relative path). */
63
82
  export declare function missingSupportPointers(body: string, supportFiles: readonly string[]): string[];
83
+ /** Support files the body mentions WITHOUT the sanctioned hook form (design
84
+ * §5.6). Such a mention still counts as a pointer for `pointer_missing`, but
85
+ * only the hook form keeps the file discoverable after a move — detail only.
86
+ * A file carrying a `keep` marker is exempt: its mention IS the marker. */
87
+ export declare function unhookedSupportPointers(body: string, supportFiles: readonly string[]): string[];
88
+ /** Why a retirement report lists nothing (design §5.6). */
89
+ export type RetirementStatus = 'listed' | 'none' | 'no-age' | 'unscanned';
90
+ /** One support file proposed for retirement review. */
91
+ export interface RetirementCandidate {
92
+ path: string;
93
+ /** Whole idle days of the owning skill at scan time. */
94
+ idleDays: number;
95
+ }
96
+ /** Retirement proposal for one skill: candidates plus the reason when empty. */
97
+ export interface RetirementReport {
98
+ candidates: readonly RetirementCandidate[];
99
+ status: RetirementStatus;
100
+ }
101
+ /** Support files with no readers, no citations and no `keep` marker whose owning
102
+ * skill has been idle for at least the lifecycle stale window. PROPOSAL INPUT
103
+ * only — nothing retires a file on its own — and an unmeasurable input (no age
104
+ * evidence, no citation scan) yields an empty list WITH its reason, never a
105
+ * silent "nothing qualifies".
106
+ * @param snapshot - the skill's drift snapshot.
107
+ * @param supportFiles - its enumerated support files, in listing order.
108
+ * @returns the candidates plus the status that explains an empty list.
109
+ */
110
+ export declare function retirementReport(snapshot: DriftSkillSnapshot, supportFiles: readonly string[]): RetirementReport;
64
111
  /** Duplicate `## heading` occurrences: singleton results default to head of the file. */
65
112
  export declare function duplicateHeadings(body: string): Array<{
66
113
  heading: string;
@@ -134,6 +134,14 @@ export declare function normalizeFrontmatter(content: string): FrontmatterNormal
134
134
  * excluded. Pure and deduplicated.
135
135
  */
136
136
  export declare function relatedSkillNames(content: string, exclude?: string): string[];
137
+ /** S1.2 (v37 P2-1): the content limit applies to the bytes that LAND ON DISK.
138
+ * Every write normalizes with `trimEnd() + '\n'`, so judging the raw argument let
139
+ * a 100_000-character body with no trailing newline land as 100_001 bytes — and
140
+ * every later patch/update of that skill was then refused, which made it
141
+ * unmaintainable through `skill_manage` with no repair path at all. */
142
+ /** The bytes that land on disk for a SKILL.md write — the ONE accounting basis
143
+ * shared by the content limit and the cost estimate (design §5.2). */
144
+ export declare function skillMdOnDisk(content: string): string;
137
145
  /** Whether `content` would exceed `limit` once written. */
138
146
  export declare function exceedsContentLimit(content: string, limit: number): boolean;
139
147
  /** S1.2: the repair path — a write that makes an already-over-limit file smaller.
@@ -25,6 +25,9 @@
25
25
  * `evolution-events.ts`, `io.ts` (the ctx.evolutionIo seam itself).
26
26
  * @module @lmzhen/dsh-evolution-core
27
27
  */
28
+ export * from './citations.ts';
29
+ export * from './reference-rewrite.ts';
30
+ export * from './cost.ts';
28
31
  export * from './curator.ts';
29
32
  export * from './evolution-events.ts';
30
33
  export * from './gates.ts';
package/lib/types/io.d.ts CHANGED
@@ -173,7 +173,10 @@ export declare const LOCK_BODY_RE: RegExp;
173
173
  /** Parse a writer-lock body into its holder pid. `null` when the body does
174
174
  * not have the `pid:token` shape at all (e.g. a user support file named
175
175
  * `*.lock`) — callers leave such files alone. A shape-matching body always
176
- * yields a number (possibly `0`, which `isProcessAlive` treats as dead). */
176
+ * yields a number, possibly `0` (state corruption / hand edit): there is no
177
+ * pid 0, so a `0` holder must be treated as DEAD by the caller —
178
+ * `isProcessAlive(0)` signals the caller's own process group on POSIX and
179
+ * answers true, so probe sites must guard `holder > 0` before probing. */
177
180
  export declare function parseLockBody(body: string): number | null;
178
181
  /**
179
182
  * V27 G0.2 (EVO-IO-01): the write lock named by this claim is no longer ours
@@ -199,6 +202,14 @@ export declare const EMPTY_LOCK_TAKEOVER_MS = 30000;
199
202
  /** A body with no parseable pid (crash mid-write): 1h, far above any legal hold
200
203
  * and far below "forever". */
201
204
  export declare const LOCK_TEAR_TAKEOVER_MS = 3600000;
205
+ /** A2 (audit P1-2): even a lock whose holder pid probes ALIVE is reclaimable
206
+ * past this age. Liveness-by-pid cannot distinguish the original holder from
207
+ * an unrelated process the OS later assigned the same pid, so the plain alive
208
+ * probe let one recycled pid brick every writer of one state file forever.
209
+ * No write in this family holds a lock for more than minutes (the longest is
210
+ * the ~120s review window), so a day-old "alive" lock is a recycled pid, not
211
+ * a live writer. */
212
+ export declare const ALIVE_LOCK_TAKEOVER_MS = 86400000;
202
213
  /**
203
214
  * V27 G1.3: the error `commitTmp` throws when the rename landed but the parent
204
215
  * directory fsync failed — the bytes ARE visible, only their durability is
@@ -224,13 +235,17 @@ interface TakeoverProbe {
224
235
  deadAfterMs?: number;
225
236
  emptyAfterMs?: number;
226
237
  corruptAfterMs?: number;
238
+ aliveAfterMs?: number;
227
239
  }
228
240
  /**
229
241
  * V27 G1.1: the lock-takeover decision as ONE pure function, so the protocol is
230
242
  * testable and exhaustive instead of being an inline expression inside the
231
243
  * acquisition loop:
232
- * - `none` the lock is fresh, or its holder is alive wait, never steal;
233
- * - `dead` a named holder that is gone, past the dead threshold;
244
+ * - `none` the lock is fresh, or its holder is alive within the alive
245
+ * window wait, never steal;
246
+ * - `dead` a named holder that is gone past the dead threshold, OR whose
247
+ * pid still probes alive but whose lock is older than the alive
248
+ * window (A2: a recycled pid must not hold the file forever);
234
249
  * - `empty` no body at all: nothing attributes it to a holder, so only the
235
250
  * wide `emptyAfterMs` window may reclaim it;
236
251
  * - `corrupt` a body with no parseable pid (a crash mid-write), past the 1h
@@ -5,11 +5,79 @@
5
5
  * store share one declaration site. Re-exported by skill-store.ts: the package
6
6
  * export surface is unchanged.
7
7
  */
8
+ /** How a restructure treats a section carrying support-file citations (design §2.2). */
9
+ export type CitationPolicy = 'verify' | 'refuse';
10
+ /** `verify` checks that every cited target exists and otherwise allows the move;
11
+ * `refuse` restores the pre-0.5 behaviour of refusing ANY citation-carrying
12
+ * section. Resolved at the call site, so every existing limits object keeps
13
+ * working (unknown policy never silently changes a write path). */
14
+ export declare const DEFAULT_CITATION_POLICY: CitationPolicy;
15
+ /** How a consolidation treats the source's support files (design §16.7).
16
+ * `off` refuses as before; `plan` keeps refusing but reports what a re-home
17
+ * would have to rewrite; `apply` (V2) performs the re-home and the rewrites, but
18
+ * only when the plan proves it leaves NOTHING dangling — otherwise it refuses
19
+ * exactly like `plan`. */
20
+ export type ReferenceRewritePolicy = 'off' | 'plan' | 'apply';
21
+ /** Default: report the plan on refusal, never write (behaviour unchanged). */
22
+ export declare const DEFAULT_REFERENCE_REWRITE_POLICY: ReferenceRewritePolicy;
23
+ /** What happens to `.archive` entries past the retention window (design §16.6-④).
24
+ * `report` (the default) names them and deletes nothing; `prune` restores the
25
+ * pre-0.5 deletion, which upstream never does. */
26
+ export type ArchiveRetentionPolicy = 'report' | 'prune';
27
+ /** Default: report-only, because upstream's hard invariant is never to delete. */
28
+ export declare const DEFAULT_ARCHIVE_RETENTION_POLICY: ArchiveRetentionPolicy;
29
+ /** How the 100k-character cap treats SUPPORT files (design §16.6, V4). Upstream
30
+ * applies the cap to every written file; we land it in `report` mode first (the
31
+ * write goes through with an advisory) and `enforce` refuses — with the same
32
+ * net-shrink repair path SKILL.md already has, so an over-cap legacy file can
33
+ * always be brought back under the cap instead of becoming unmaintainable. */
34
+ export type SupportFileCharPolicy = 'report' | 'enforce';
35
+ /** Default: report, so the cap cannot brick an existing oversize file on upgrade
36
+ * (the live library carries a 189k-character release log today). */
37
+ export declare const DEFAULT_SUPPORT_FILE_CHAR_POLICY: SupportFileCharPolicy;
38
+ /** The four stage defaults in ONE object, so the policy schema's `z.default(...)`
39
+ * calls and the store's fallbacks cannot drift apart. */
40
+ export declare const POLICY_STAGE_DEFAULTS: Readonly<{
41
+ citationPolicy: "verify";
42
+ referenceRewrite: "plan";
43
+ archiveRetention: "report";
44
+ supportFileCharPolicy: "report";
45
+ }>;
46
+ /** The policy-snapshot fields that select a write-behaviour STAGE (design §16).
47
+ * Structural, not imported from evolution-policy, so core stays a leaf. */
48
+ export interface PolicyStageFields {
49
+ citationPolicy?: CitationPolicy | undefined;
50
+ referenceRewrite?: ReferenceRewritePolicy | undefined;
51
+ archiveRetention?: ArchiveRetentionPolicy | undefined;
52
+ supportFileCharPolicy?: SupportFileCharPolicy | undefined;
53
+ }
54
+ /**
55
+ * The ONE conversion from the deployment policy snapshot to library limits
56
+ * (design §16.7): every plugin that owns a writable SkillLibrary spreads this into
57
+ * its limits, so a stage selected in cordis.yml reaches every write path. A
58
+ * per-plugin copy would be the third home for the same threshold.
59
+ *
60
+ * Only PRESENT fields are copied: an absent policy field must fall through to the
61
+ * library default rather than pinning `undefined` onto an optional limit (which
62
+ * `exactOptionalPropertyTypes` forbids and which would defeat the `?? DEFAULT`
63
+ * resolution inside the store).
64
+ * @param snapshot - the evolutionPolicy snapshot, or undefined when unmounted.
65
+ * @returns the stage fields the snapshot actually carries.
66
+ */
67
+ export declare function policyStageLimits(snapshot: PolicyStageFields | undefined): PolicyStageFields;
8
68
  export interface SkillLimits {
9
69
  maxNameLength: number;
10
70
  maxDescriptionLength: number;
11
71
  maxSkillContentChars: number;
12
72
  maxSkillFileBytes: number;
73
+ /** See CitationPolicy. Optional so existing limits objects stay valid. */
74
+ citationPolicy?: CitationPolicy | undefined;
75
+ /** See ReferenceRewritePolicy; absent means the default (`plan`). */
76
+ referenceRewrite?: ReferenceRewritePolicy | undefined;
77
+ /** See ArchiveRetentionPolicy; absent means the default (`report`). */
78
+ archiveRetention?: ArchiveRetentionPolicy | undefined;
79
+ /** See SupportFileCharPolicy; absent means the default (`report`). */
80
+ supportFileCharPolicy?: SupportFileCharPolicy | undefined;
13
81
  }
14
82
  export declare const DEFAULT_SKILL_LIMITS: SkillLimits;
15
83
  //# sourceMappingURL=limits.d.ts.map
@@ -3,8 +3,8 @@
3
3
  * changes semantically: the bundle digest is the fail-closed signal for
4
4
  * review workers, so a stale id across deployments must be distinguishable.
5
5
  */
6
- export declare const PROMPT_BUNDLE_VERSION = 17;
7
- export declare const PROMPT_BUNDLE_ID = "dsh-evolution@17";
6
+ export declare const PROMPT_BUNDLE_VERSION = 20;
7
+ export declare const PROMPT_BUNDLE_ID = "dsh-evolution@20";
8
8
  export declare const MEMORY_REVIEW_PROMPT = "[Auto-review \u2014 Memory]\nReview the conversation above and consider saving to memory if appropriate.\n\nFocus on:\n1. Has the user revealed things about themselves \u2014 persona, desires, preferences, or personal details worth remembering?\n2. Has the user expressed expectations about how you should behave, their work style, or ways they want you to operate?\n\nIf something stands out, save it using the memory tool.\nIf nothing is worth saving, just say \"Nothing to save.\" and stop.";
9
9
  export declare const SKILL_REVIEW_PROMPT = "[Auto-review \u2014 Skills]\nReview the conversation above and update the skill library. Be ACTIVE \u2014 most sessions produce at least one skill update, even if small. A pass that does nothing is a missed learning opportunity, not a neutral outcome.\n\nTarget shape of the library: CLASS-LEVEL skills, each with a rich SKILL.md and a references/ directory for session-specific detail. Not a long flat list of narrow one-session-one-skill entries. This shapes HOW you update, not WHETHER you update.\n\nSignals to look for (any one of these warrants action):\n \u2022 User corrected your style, tone, format, legibility, or verbosity. Frustration signals like 'stop doing X', 'this is too verbose', 'don't format like this', 'why are you explaining', 'just give me the answer', 'you always do Y and I hate it', or an explicit 'remember this' are FIRST-CLASS skill signals, not just memory signals. Update the relevant skill(s) to embed the preference so the next session starts already knowing.\n \u2022 User corrected your workflow, approach, or sequence of steps. Encode the correction as a pitfall or explicit step in the skill that governs that class of task.\n \u2022 Non-trivial technique, fix, workaround, debugging path, or tool-usage pattern emerged that a future session would benefit from. Capture it.\n \u2022 A skill that got loaded or consulted this session turned out to be wrong, missing a step, or outdated. Patch it NOW.\n\nRead-before-write: update, patch, delete, or write support files ONLY into skills you loaded or read in THIS session. On the plan channel ops on unread skills are rejected; direct writes have no such guard, so treat the rule as binding. CREATE of a brand-new umbrella is the only exception.\n\nPreference order \u2014 prefer the earliest action that fits, but do pick one when a signal above fired:\n 1. UPDATE A CURRENTLY-LOADED SKILL. Look back through the conversation for skills the user loaded or you read. If any of them covers the territory of the new learning, PATCH that one first. It is the skill that was in play, so it's the right one to extend.\n 2. UPDATE AN EXISTING UMBRELLA. If no loaded skill fits but an existing class-level skill does, patch it. Add a subsection, a pitfall, or broaden a trigger.\n 3. ADD A SUPPORT FILE under an existing umbrella. Skills can be packaged with three kinds of support files \u2014 use the right directory per kind:\n \u2022 references/<topic>.md \u2014 session-specific detail (error transcripts, reproduction recipes, provider quirks) AND condensed knowledge banks: quoted research, API docs, external authoritative excerpts, or domain notes you found while working on the problem. Write it concise and for the value of the task, not as a full mirror of upstream docs.\n \u2022 templates/<name>.<ext> \u2014 starter files meant to be copied and modified (boilerplate configs, scaffolding, a known-good example the agent can reproduce with modifications).\n \u2022 scripts/<name>.<ext> \u2014 statically re-runnable actions the skill can invoke directly (verification scripts, fixture generators, deterministic probes, anything the agent should run rather than hand-type each time).\n Add support files via skill_manage action=write_file with file_path starting 'references/', 'templates/', or 'scripts/'. The umbrella's SKILL.md should gain a one-line pointer to any new support file so future agents know it exists.\n 4. RESTRUCTURE a loaded skill whose body grew log-like \u2014 rc/sha/date-dense sections, session-detail spirals, or a fat body with no support files. Use skill_manage action=restructure with restructure: [{\"heading\": \"<the exact ## heading text>\", \"to_file\": \"references/<topic>.md\"}] \u2014 the ENTIRE ## section (from that heading to the next heading) moves into the support file and its position becomes a pointer line. The skill's name and directory never change. Only propose headings that exist verbatim in the body; never invent one, and never restructure a healthy small skill.\n 5. CREATE A NEW CLASS-LEVEL UMBRELLA SKILL when no existing skill covers the class. The name MUST be at the class level. The name MUST NOT be a specific PR number, error string, feature codename, library-alone name, or 'fix-X / debug-Y / audit-Z-today' session artifact. If the proposed name only makes sense for today's task, it's wrong \u2014 fall back to (1), (2), or (3).\n\nUser-preference embedding (important): when the user expressed a style/format/workflow preference, the update belongs in the SKILL.md body, not just in memory. Memory captures 'who the user is and what the current situation and state of your operations are'; skills capture 'how to do this class of task for this user'. When they complain about how you handled a task, the skill that governs that task needs to carry the lesson.\n\nIf you notice two existing skills that overlap, note it in your reply \u2014 the background curator handles consolidation at scale.\n\nTwo-tier deposition discipline (DSH addition, same spirit as the umbrella rule): before writing, classify the knowledge:\n \u2022 PATTERN (reusable \u2014 symptom \u2192 mechanism \u2192 fix \u2192 verification, still valuable next session) belongs in the SKILL.md body.\n \u2022 LOG (one-off \u2014 commit SHAs, npm/profile states, what this release changed, this session's process narrative) belongs in a references/ file, never the body. Body density IS reuse rate. Keep new entries tight: a pattern fits in 2-8 physical lines; prefer changing the current-state pointer over appending history.\n\nProtected skills (DO NOT edit these):\n \u2022 Bundled skills (shipped with the platform).\n \u2022 Hub-installed skills (installed from a hub).\nPinned skills are read-only to THIS background review pass \u2014 the pinned write guard refuses background changes, so this pass may not update them. They also cannot be archived by any writer (the foreground included): remove the .pinned marker first. Foreground and delegated-subagent update/patch writes to pinned skills remain allowed.\nIf the only skills that need updating are protected, say 'Nothing to save.' and stop.\n\nDo NOT capture (these become persistent self-imposed constraints that bite you later when the environment changes):\n \u2022 Environment-dependent failures: missing binaries, fresh-install errors, post-migration path mismatches, 'command not found', unconfigured credentials, uninstalled packages. The user can fix these \u2014 they are not durable rules.\n \u2022 Negative claims about tools or features ('browser tools do not work', 'X tool is broken', 'cannot use Y'). These harden into refusals the agent cites against itself for months after the actual problem was fixed.\n \u2022 Session-specific transient errors that resolved before the conversation ended. If retrying worked, the lesson is the retry pattern, not the original failure.\n \u2022 One-off task narratives. A user asking 'summarize today's market' or 'analyze this PR' is not a class of work that warrants a skill.\n\nIf a tool failed because of setup state, capture the FIX (install command, config step, env var to set) under an existing setup or troubleshooting skill \u2014 never 'this tool does not work' as a standalone constraint.\n\n'Nothing to save.' is a real option but should NOT be the default. If the session ran smoothly with no corrections and produced no new technique, just say 'Nothing to save.' and stop. Otherwise, act.";
10
10
  export declare const COMBINED_REVIEW_PROMPT = "[Auto-review]\nReview the conversation above and update two things:\n\n**Memory**: who the user is. Did the user reveal persona, desires, preferences, personal details, or expectations about how you should behave? Save facts about the user and durable preferences with the memory tool.\n\n**Skills**: how to do this class of task. Be ACTIVE \u2014 most sessions produce at least one skill update. A pass that does nothing is a missed learning opportunity, not a neutral outcome.\n\nTarget shape of the skill library: CLASS-LEVEL skills with a rich SKILL.md and a references/ directory for session-specific detail. Not a long flat list of narrow one-session-one-skill entries.\n\nSignals that warrant a skill update (any one is enough):\n \u2022 User corrected your style, tone, format, legibility, verbosity, or approach. Frustration is a FIRST-CLASS skill signal, not just a memory signal. 'stop doing X', 'don't format like this', 'I hate when you Y' \u2014 embed the lesson in the skill that governs that task so the next session starts fixed.\n \u2022 Non-trivial technique, fix, workaround, or debugging path emerged.\n \u2022 A skill that was loaded or consulted turned out wrong, missing, or outdated \u2014 patch it now.\n\nRead-before-write: update, patch, delete, or write support files ONLY into skills you loaded or read in THIS session. On the plan channel ops on unread skills are rejected; direct writes have no such guard, so treat the rule as binding. CREATE of a brand-new umbrella is the only exception.\n\nPreference order for skills \u2014 pick the earliest that fits:\n 1. UPDATE A CURRENTLY-LOADED SKILL. Check what skills were loaded or read in the conversation. If one of them covers the learning, PATCH it first. It was in play; it's the right place.\n 2. UPDATE AN EXISTING UMBRELLA. Patch it.\n 3. ADD A SUPPORT FILE under an existing umbrella via skill_manage action=write_file. Three kinds: references/<topic>.md for session-specific detail OR condensed knowledge banks (quoted research, API docs excerpts, domain notes) written concise and task-focused; templates/<name>.<ext> for starter files meant to be copied and modified; scripts/<name>.<ext> for statically re-runnable actions (verification, fixture generators, probes). Add a one-line pointer in SKILL.md so future agents find them.\n 4. RESTRUCTURE a loaded skill whose body grew log-like (rc/sha/date-dense sections, session-detail spirals, fat body with no support files) via skill_manage action=restructure with restructure: [{\"heading\": \"<the exact ## heading text>\", \"to_file\": \"references/<topic>.md\"}] \u2014 the ENTIRE ## section moves into the support file and its position becomes a pointer line; the skill's name and directory never change. Only propose headings that exist verbatim in the body.\n 5. CREATE A NEW CLASS-LEVEL UMBRELLA when nothing exists. Name at the class level \u2014 NOT a PR number, error string, codename, library-alone name, or 'fix-X / debug-Y' session artifact. If the name only fits today's task, fall back to (1), (2), or (3).\n\nTwo-tier deposition discipline (DSH addition): classify before writing \u2014 PATTERN (symptom \u2192 mechanism \u2192 fix \u2192 verification) goes in the SKILL.md body; LOG (commit SHAs, npm/profile states, this release's change list, this session's narrative) goes in a references/ file. Body density IS reuse rate; a pattern fits in 2-8 physical lines.\n\nUser-preference embedding: when the user complains about how you handled a task, update the skill that governs that task \u2014 memory alone isn't enough. Memory says 'who the user is and what the current situation and state of your operations are'; skills say 'how to do this class of task for this user'. Both should carry user-preference lessons when relevant.\n\nIf you notice overlapping existing skills, mention it \u2014 the background curator handles consolidation.\n\nProtected skills (DO NOT edit these):\n \u2022 Bundled skills (shipped with the platform).\n \u2022 Hub-installed skills (installed from a hub).\nPinned skills are read-only to THIS background review pass \u2014 the pinned write guard refuses background changes, so this pass may not update them. They also cannot be archived by any writer (the foreground included): remove the .pinned marker first. Foreground and delegated-subagent update/patch writes to pinned skills remain allowed.\nIf the only skills that need updating are protected, say 'Nothing to save.' and stop.\n\nDo NOT capture as skills (these become persistent self-imposed constraints that bite you later when the environment changes):\n \u2022 Environment-dependent failures: missing binaries, fresh-install errors, post-migration path mismatches, 'command not found', unconfigured credentials, uninstalled packages. The user can fix these \u2014 they are not durable rules.\n \u2022 Negative claims about tools or features ('browser tools do not work', 'X tool is broken', 'cannot use Y'). These harden into refusals the agent cites against itself for months after the actual problem was fixed.\n \u2022 Session-specific transient errors that resolved before the conversation ended. If retrying worked, the lesson is the retry pattern, not the original failure.\n \u2022 One-off task narratives. A user asking 'summarize today's market' or 'analyze this PR' is not a class of work that warrants a skill.\n\nIf a tool failed because of setup state, capture the FIX (install command, config step, env var to set) under an existing setup or troubleshooting skill \u2014 never 'this tool does not work' as a standalone constraint.\n\nAct on whichever of the two dimensions has real signal. If genuinely nothing stands out on either, say 'Nothing to save.' and stop \u2014 but don't reach for that conclusion as a default.";
@@ -18,7 +18,7 @@ export declare const COMPLETION_SKILL_REVIEW_PROMPT = "[Auto-review \u2014 Skill
18
18
  * persona + the mechanical-facts block; the signature head lets the model
19
19
  * compare the two heads (011 mismatch protocol).
20
20
  */
21
- export declare const MAINTAIN_PROMPT = "<<<MAINTAIN_PROMPT v={bundle_version} sig={joint_signature}>>>\n\n## \u89D2\u8272\n\u4F60\u662F\u6280\u80FD\u5E93\u7684**\u5916\u90E8\u5BA1\u8BA1\u8005**\uFF1A\u53EA\u8BFB\u3001\u53EA\u8F93\u51FA\u8BA1\u5212\u3001\u4ECE\u4E0D\u6267\u884C\uFF08\u6267\u884C\u7531\u7528\u6237\u547D\u4EE4\u4E0E\u5BA1\u6279\u5B8C\u6210\uFF09\u3002\n\n## 1. \u8F93\u5165\u5951\u7EA6\uFF08\u51B2\u7A81\u65F6\u4EE5\u6B64\u4E3A\u51C6\uFF09\n\u673A\u68B0\u4E8B\u5B9E\u5757 <<<MECHANICAL_FACTS v={signals_version} sig={joint_signature}>>>\uFF08\u4E0B\u65B9\uFF0C\u4EE5 <<<END FACTS>>> \u95ED\u5408\uFF09\u662F\u552F\u4E00\u8BC1\u636E\u6765\u6E90\u3002\n- verdict \u4EC5\u4E09\u503C\uFF1Apass=\u672A\u8D8A\u9608 / over=\u8D8A\u9608 / unknown=\u672A\u68C0\u6D4B\u3002\n- over \u662F\u4E8B\u5B9E\u4F4D\u7F6E\uFF0C\u4E0D\u662F\u8FDD\u89C4\u7ED3\u8BBA\uFF1B\u6CA1\u6709\u6761\u6B3E\u5BF9\u5E94\u7684\u4E8B\u5B9E\uFF0C\u4E0D\u4EA7\u751F\u5EFA\u8BAE\u3002\n- unknown \u2260 pass\uFF1B\u5F15\u7528 unknown \u4FE1\u53F7\u7684\u6761\u76EE\u5FC5\u987B needs_human:true\u3002\n- \u4E8B\u5B9E\u53EA\u8BFB\uFF1A\u4E0D\u6539\u5199\u3001\u4E0D\u8865\u5199\u3001\u4E0D\u628A\u4E8B\u5B9E\"\u7FFB\u8BD1\"\u6210\u88C1\u51B3\u3002\n- \u4E24\u5904 sig \u4E0D\u4E00\u81F4\u6216\u4EFB\u4E00\u7F3A\u5931 \u2192 \u53EA\u8F93\u51FA MISMATCH + \u4E24\u4FA7\u7248\u672C\u53F7\uFF0C\u7981\u6B62\u8F93\u51FA\u8BA1\u5212\u3002\n\n## 2. \u4FE1\u53F7\u2192\u6761\u6B3E\u6620\u5C04\uFF08\u6BCF\u6761 over \u5FC5\u987B\u843D\u5230\u6761\u6B3E\uFF1B\u65E0\u4E00\u9057\u6F0F\uFF09\n{signal:dedup_group}\u2192A1 \u00B7 {signal:narrow_name}\u2192A2 \u00B7 {signal:prefix_cluster}\u2192A3 \u00B7 {signal:stamp_density}\u4E0E{signal:body_size}\u2192B1 \u00B7 {signal:pointer_missing}\u2192B2 \u00B7 {signal:dup_heading}\u2192B3 \u00B7 {signal:overlong_line}\u2192B4 \u00B7 {signal:description_chars}\u2192B5 \u00B7 {signal:usage_observed}/{signal:quality_low}\u2192\u95E8\u63A7\uFF08\u6821\u9A8C\u5668\u5BF9 quality_low=unknown \u7684\u6280\u80FD\u5F3A\u5236 needs_human\uFF0C\u6A21\u677F\u4FA7\u4E0D\u91CD\u590D\uFF09\n\n## 3. \u5B8C\u6574\u6027\u5951\u7EA6\uFF08\u6821\u9A8C\u5668\u673A\u68B0\u6267\u884C\uFF09\n\u4E8B\u5B9E\u5757\u4E2D\u6BCF\u6761 over \u4FE1\u53F7\u5FC5\u987B\u6EE1\u8DB3\u5176\u4E00\uFF1A\u6210\u4E3A\u67D0\u6761\u5EFA\u8BAE\u7684 evidence\uFF0C\u6216\u5728 notes \u4E2D\u8BF4\u660E\"\u5DF2\u5BA1\u00B7\u65E0\u6761\u6B3E\u5BF9\u5E94\u00B7\u4E0D\u52A8\u4F5C\"\u3002\u7981\u6B62\u9759\u9ED8\u7701\u7565\uFF1B\u5148\u9010\u4FE1\u53F7\u6838\u5BF9\u518D\u8F93\u51FA\u3002\n\n## 4. \u5DE5\u4F5C\u6D41\u7A0B\uFF08\u6309\u5E8F\u6267\u884C\uFF0C\u4E0D\u5F97\u8DF3\u6B65\uFF09\n\u2460 \u901A\u8BFB\u4E8B\u5B9E\u5757 \u2192 \u2461 \u5BF9\u6BCF\u4E2A\u5019\u9009\u6280\u80FD\u7528 skill \u8BFB\u6B63\u6587\uFF08B1/B2/B4 \u5FC5\u8BFB\uFF1B**\u8BFB\u53D6\u5931\u8D25\u5FC5\u987B\u62A5\u544A\u5DE5\u5177\u8FD4\u56DE\u7684\u4E8B\u5B9E**\uFF08\u9519\u8BEF\u4FE1\u606F/\u65E0\u5BF9\u5E94\u6761\u76EE\uFF09\uFF0C\u7981\u6B62\u7528\"\u65E0\u6CD5\u8BFB\u53D6\"\u542B\u7CCA\u7ED5\u8FC7\uFF09\u2192 \u2462 maintenance_probe \u6309\u9700\u6DF1\u6316 \u2192 \u2463 \u9010\u4FE1\u53F7\u8FC7 \u00A73 \u5B8C\u6574\u6027 \u2192 \u2464 \u8F93\u51FA\u8BA1\u5212\u3002\n\n## 5. \u68C0\u67E5\u6E05\u5355\uFF08\u4FE1\u53F7 \u2192 \u8BED\u4E49\u5224\u5B9A \u2192 \u8F93\u51FA\u5F62\u6001\uFF09\nA. \u57DF\u00B7\u788E\u7247\u5316\n- A1 {signal:dedup_group}=over\uFF1A\u5224\u8FD1\u91CD\u590D\u7EC4\u662F\u5426\u540C\u4F1E\u53EF\u5408\u5E76\uFF1B\u662F\u2192relationship-level consolidate\uFF1B\u5426\u2192\u4E0D\u8F93\u51FA\u3002\n- A2 {signal:narrow_name}=over\uFF1A\u5224\u5426\"\u4EC5\u5BF9\u4ECA\u65E5\u4EFB\u52A1\u6210\u7ACB\"\uFF1B\u6210\u7ACB\u2192\u6539\u540D/\u5F52\u6863\u5EFA\u8BAE\uFF1B\u5185\u90E8\u4EE3\u53F7\uFF08\u683C\u5F0F\u5408\u89C4\u8BED\u4E49\u7A84\uFF09\u2192conf\u22640.4+needs_human\u3002\n- A3 {signal:prefix_cluster}=over\uFF1A\u5224\u7C07\u5185\u662F\u5426\u540C\u4F1E\uFF1B\u975E\u540C\u4F1E\u2192notes \u63D0\u57DF\u5212\u5206\u89C2\u5BDF\uFF0C\u4E0D\u5F3A\u5236\u5EFA\u4F1E\u3002\n\nB. \u5C42\u00B7\u5206\u5C42\u9519\u4F4D\n- B1 {signal:stamp_density}\uFF08\u9608\u503C {signal:stamp_density.threshold}\uFF09\u6216 {signal:body_size}\uFF08\u9608\u503C {signal:body_size.threshold}\uFF09=over\uFF1A\u6309**\u4E09\u95EE\u5224\u636E**\u5224\u951A/\u6B8B\u7559\u2014\u2014\u2460 \u8BE5\u7F16\u53F7/\u65F6\u95F4\u6233\u662F\u5426\u88AB\u5E93\u5185\u5176\u4ED6\u6587\u4EF6\u5F15\u7528\uFF1F\u2461 \u9664\"\u4F55\u65F6\u4EA7\u751F/\u4E3A\u4F55\u5B58\u5728\"\u5916\u662F\u5426\u8FD8\u627F\u8F7D\u4FE1\u606F\uFF1F\u2462 \u5220\u9664\u662F\u5426\u5F71\u54CD\u4EFB\u4F55\u8DE8\u6587\u6863\u68C0\u7D22\uFF1F\uFF08\u2460\u662F\u4E14\u2462\u662F\u2192\u951A\uFF1B\u5426\u5219\u2192\u6B8B\u7559\u5019\u9009\uFF0C\u4EBA\u5BA1\uFF09\u3002\u951A\u2192\u5141\u8BB8\u4FDD\u7559 + needs_human + semantic_reasoning \u5199\u4E09\u95EE\u7ED3\u679C\uFF1B**\u951A\u4E0D\u4F7F\u7528 is_override**\uFF08is_override \u4EC5\u7528\u4E8E \u00A77 \u7533\u8BC9\uFF1B\u951A\u662F B1 \u7684\u6B63\u5E38\u88C1\u51B3\u8DEF\u5F84\uFF09\uFF1B\u6B8B\u7559\u2192restructure \u5EFA\u8BAE\uFF08movable headings \u9010\u5B57\u5F15\u7528\uFF09\u3002**\u951A\u2260\u53EF\u8BFB\uFF1A\u5355\u884C >4000 \u5B57\u7B26\u5373\u4F7F\u5728\u951A\u7C7B\u4E5F\u5FC5\u987B\u62C6\u5206\u3002**\n- B2 {signal:pointer_missing}=over\uFF1A\u8BFB\u652F\u6301\u6587\u4EF6\u540E\u5224\u6027\u8D28\u2014\u2014\u53EF\u590D\u7528\u6A21\u5F0F\u2192\u4E0A\u79FB\u6B63\u6587\uFF1B\u4F1A\u8BDD\u4E13\u5C5E\u5B9E\u5F55\u2192\u4FDD\u7559+\u8865\u6307\u9488\uFF1B\u5F62\u6001=patch \u6307\u5F15\u3002**\u672A\u8BFB\u5185\u5BB9\u4EC5\u51ED\u6587\u4EF6\u540D \u2192 conf\u22640.4 \u4E14\u63AA\u8F9E\"\u5148\u4EBA\u5DE5\u786E\u8BA4\u518D\u6267\u884C\"\u3002** **\u7F3A\u5931\u6307\u9488=\u652F\u6301\u6587\u4EF6\u5B58\u5728\u3001\u6B63\u6587\u65E0\u5F15\u7528\uFF08\u5355\u5411\u8BED\u4E49\uFF09\uFF0Cfinding \u8868\u8FF0\u52FF\u53CD\u5411\u3002**\n- B3 {signal:dup_heading}=over\uFF1A\u5220\u9664\u591A\u4F59\u6807\u9898\u884C\uFF08\u4FDD\u7559\u4E00\u4EFD\uFF09\uFF0Cpatch \u6307\u5F15\u3002\n- B4 {signal:overlong_line}=over\uFF1A>1500 \u62C6\u884C\uFF1B>4000 \u5224\u5B9A\u53EF\u8BFB\u6027\u5371\u673A\uFF08\u5185\u5BB9\u5408\u6CD5\u4E5F\u62C6\uFF09\uFF1Bpatch \u6307\u5F15\u3002**finding \u5FC5\u987B\u7ED9\u5168\u91CF\u53E3\u5F84\uFF1A\u5171 N \u884C\u8D85\u9650\uFF0C\u5176\u4E2D >4000 \u7684\u9010\u884C\u5217\u51FA\u3002**\n- B5 {signal:description_chars}=over\uFF1A\u5148\u5224**\u6027\u8D28**\u4E09\u5206\u7C7B\u2014\u2014\u4E8B\u4EF6\u6027\u627F\u8BFA\uFF08\u5355\u6B21\u6545\u969C/incident \u5199\u5165\u5143\u6570\u636E\uFF09\u2192\u88C1\u526A\u5EFA\u8BAE\uFF1B\u53D9\u4E8B\u6027\u81EA\u6211\u63CF\u8FF0\u2192\u538B\u7F29\u5EFA\u8BAE\uFF1B\u4E30\u5BCC\u4F46\u5408\u89C4\uFF08\u5B8C\u6574\u7528\u4F8B\u8FB9\u754C\uFF09\u2192\u4FDD\u7559 + is_override + override_reason=\"\u5408\u6CD5\u5BC6\u5EA6\"\u3002**\u5206\u7C7B\u7279\u5F81**\uFF1A\u542B\"\u6062\u590D/\u4FEE\u590D\u67D0\u6B21\u4E8B\u6545\u3001\u65E5\u671F\u5FEB\u7167\"\u7C7B\u4E00\u6B21\u6027\u63AA\u8F9E\u2192\u4E8B\u4EF6\u6027\u627F\u8BFA\uFF1B\"\u52A8\u8BCD+\u5BF9\u8C61\"\u5F0F\u4EFB\u52A1\u8BF4\u660E\u2192\u53D9\u4E8B\u6027\uFF1B\u679A\u4E3E\u5B8C\u6574\u7528\u4F8B\u8FB9\u754C\u4E14\u4E0D\u53EF\u62C6\u5206\u2192\u4E30\u5BCC\u5408\u89C4\u3002**\u7B2C\u4E09\u7C7B\u95E8\u69DB\uFF08\u9ED8\u8BA4\u4ECE\u4E25\uFF0C\u534A\u673A\u68B0\uFF09**\uFF1A\u5148\u81EA\u884C\u8BD5\u5199\u4E00\u4E2A \u226460 \u5B57\u538B\u7F29\u65B9\u6848\u2014\u2014\u80FD\u4FDD\u7559\u5168\u90E8\u8DEF\u7531\u5173\u952E\u9879\uFF08\u89E6\u53D1\u8BCD+\u57DF\uFF09\u2192 \u4E0D\u53EF\u5224\u7B2C\u4E09\u7C7B\uFF08\u6309\u538B\u7F29\u5EFA\u8BAE\uFF09\uFF1B\u53EA\u6709\u8BD5\u5199\u5931\u8D25\uFF08\u5728 semantic_reasoning \u5217\u51FA\u8BD5\u5199\u65B9\u6848\u4E0E\u5177\u4F53\u5931\u8D25\u70B9\uFF09\u624D\u53EF\u5224\u4E30\u5BCC\u5408\u89C4\u3002\u63CF\u8FF0\u6587\u672C\u53EF\u89C1\uFF08probe desc-text \u6216\u6B63\u6587 frontmatter\uFF09\u65F6\u4ECD\u987B\u4E09\u5206\u7C7B\uFF1B\u4EC5\u957F\u5EA6\u53EF\u89C1 \u2192 conf\u22640.4\u3002semantic_reasoning \u5FC5\u5199\u4E09\u5206\u7C7B\u4E4B\u4E00\u3002\n\nD. \u5E93\u00B7\u6574\u5408\u7EAA\u5F8B\uFF08\u8BA1\u5212\u5F62\u6001\u7EA6\u675F\uFF09\n- D1 \u540C\u7C7B\u95EE\u9898\u591A\u5904\u51FA\u73B0\u2192\u5408\u6210\u4E00\u6761 relationship-level \u5EFA\u8BAE\uFF0C\u4E0D\u9010\u9879\u8F93\u51FA\u3002\n- D2 \u7ED3\u6784\u7C7B\u4F18\u5148\u7EA7\u9AD8\u4E8E\u5185\u5BB9\u7C7B\uFF1B\u5F71\u54CD\u9762 library-level > relationship-level > skill-level\u3002\n\n## 6. \u8F93\u51FA\u5951\u7EA6\uFF08\u6821\u9A8C\u5668\u673A\u68B0\u6267\u884C\uFF09\n{verdict: \"issues\" | \"no_issues\",\n plan: [{ kind: \"skill-level\"|\"relationship-level\"|\"library-level\", names: [str],\n rule: \"A1\"|\"B2\"|..., evidence: [{signal, value}],\n finding: \"<\u4E00\u53E5\u4E8B\u5B9E\u63CF\u8FF0\uFF1A\u5F15\u7528\u4FE1\u53F7 id \u4E0E\u503C\uFF1B\u96F6\u88C1\u51B3\u52A8\u8BCD>\",\n recommendation: \"<\u552F\u4E00\u5141\u8BB8\u7684'\u5E94'\u53E5\uFF1A\u5EFA\u8BAE\u52A8\u4F5C+\u7406\u7531+\u6267\u884C\u5F62\u6001\uFF08\u547D\u4EE4/patch \u6307\u5F15\uFF09>\",\n semantic_reasoning: \"<\u8BED\u4E49\u5224\u636E\uFF1B\u542B LLM \u63A8\u65AD\u65F6 confidence\u22640.4>\",\n impact: \"better|worse|neutral\", impact_reason: \"<\u76F8\u5BF9'\u4E0D\u52A8'\u7684\u51C0\u5F71\u54CD>\",\n reversibility: \"archive|restructure|patch|rename|none\", undo_path: \"<\u4E00\u6B65\u64A4\u9500\u65B9\u5F0F>\",\n confidence: float, needs_human: bool, is_override: bool,\n override_reason: \"<\u4EC5 is_override>\" }],\n notes: [str]}\n- verdict=no_issues \u21D2 plan=[]\uFF08\u4E0D\u5141\u8BB8\u7A7A plan \u4E4B\u5916\u7684\"\u65E0\u95EE\u9898\"\u8868\u8FF0\uFF09\u3002\n- **confidence \u964D\u6863\u89C4\u5219\uFF08\u673A\u68B0\uFF09**\uFF1A\u6761\u6B3E\u5168\u90E8\u7531\u673A\u68B0\u8BC1\u636E\u652F\u6491 \u2192 0.6\u20130.9\uFF1B\u6BCF\u542B\u4E00\u9879\u8BED\u4E49\u63A8\u65AD\uFF08\u662F\u5426\u951A/\u662F\u5426\u540C\u4F1E/\u6027\u8D28\u5F52\u7C7B\uFF09\u2192 \u4E0A\u9650 0.4\u3002\n- needs_human = (confidence < 0.6) OR (\u4E0D\u53EF\u9006) OR (is_override) OR (\u5F15\u7528 unknown \u4FE1\u53F7)\u3002\n- \u8BED\u8A00\uFF1Afinding/recommendation/notes \u4E0E\u5E93\u6B63\u6587\u8BED\u8A00\u4E00\u81F4\uFF08\u4E0D\u81EA\u8BA2\u8BED\u8A00\uFF09\uFF1B\u5B57\u6BB5\u540D/\u4FE1\u53F7 id/\u679A\u4E3E\u4FDD\u7559\u82F1\u6587\u3002\n- **\u63D0\u4EA4\u524D\u81EA\u67E5\uFF08\u9010\u9879\u5BF9\u7167\uFF0C\u4E0D\u8BB8\u8DF3\u8FC7\uFF09**\uFF1A\u2460 verdict \u4E0E plan \u4E00\u81F4 \u2461 \u6BCF\u6761 evidence \u5728\u4E8B\u5B9E\u5757 \u2462 undo_path \u975E\u7A7A\uFF08\u4E0D\u53EF\u9006=n/a\uFF09\u2463 confidence \u542B\u63A8\u65AD\u22640.4 \u2464 finding \u65E0\"\u5E94\"\u5B57 \u2465 \u00A73 \u5B8C\u6574\u6027\u5951\u7EA6\u6EE1\u8DB3\u3002\n\n## 7. \u88C1\u51B3\u7EAA\u5F8B\n- finding \u7981\u6B62\"\u5E94\u5F53\"\u53E5\u5F0F\uFF1Brecommendation \u662F\u552F\u4E00\"\u5E94\"\u53E5\uFF0C\u53E5\u677F\uFF1A\u5EFA\u8BAE\u5BF9 {names} \u6267\u884C {\u52A8\u4F5C}\uFF08\u5F62\u6001\uFF1A{\u547D\u4EE4/patch \u6307\u5F15}\uFF09\uFF0C\u7406\u7531\uFF1A{\u7406\u7531}\u3002\n- **\u5BA1\u67E5\u8005\u89C6\u89D2**\uFF1A\u5148\u5BF9\u6BCF\u4E2A\u4FE1\u53F7\u72EC\u7ACB\u521D\u5224\uFF0C\u518D\u4E0E\u6B63\u6587\u5BF9\u7167\uFF1B\u88AB\u5BA1\u5BF9\u8C61\u7684\u81EA\u6211\u58F0\u660E\u53EA\u4F5C\u7EBF\u7D22\u4E0D\u4F5C\u4F9D\u636E\uFF1B**\u81EA\u5C5E/\u7EF4\u62A4\u8005\u6280\u80FD\u4E00\u5F8B\u4ECE\u4E25\u53E3\u5F84**\uFF08\u4F5C\u8005\u58F0\u660E\"\u8FD9\u662F\u951A\"\u4E0D\u6784\u6210\u8C41\u514D\uFF09\u3002\n- \u7533\u8BC9\uFF1A\u673A\u68B0\u9608\u503C\u4E0E\u8BED\u4E49\u5224\u65AD\u51B2\u7A81\u2192is_override:true + override_reason + needs_human:true\uFF0C\u4E0D\u5F97\u9759\u9ED8\u7ED5\u8FC7\u3002\n- \u4E0D\u52A8\u4F5C\u5408\u6CD5\uFF1Averdict=no_issues \u662F\u5408\u6CD5\u8F93\u51FA\uFF1B\u8FDE\u7EED\u7A7A\u62A5\u544A=\u4FE1\u53F7\u5B9A\u4E49\u95EE\u9898\uFF0C\u4E0D\u662F\"\u66F4\u79EF\u6781\"\u7684\u7406\u7531\u3002\n- \u9519\u8BEF\u6210\u672C\uFF1Arename \u5FC5\u987B needs_human:true\uFF1B\u53EF\u9006\u52A8\u4F5C\uFF08archive/restructure \u4E24\u9636\u6BB5\uFF09\u53EF needs_human:false \u4F46 undo_path \u5FC5\u586B\u3002\n- \u4E0D\u505A\uFF1A\u4E0D\u5EFA\u8BAE\u5220\u9664\uFF08\u53EA\u5EFA\u8BAE archive\uFF09\uFF1B\u4E0D\u63D0\u5347\u5185\u5BB9\u8D28\u91CF\uFF08\u7ED3\u6784\u5BA1\u67E5\u53EA flag \u4F4D\u7F6E/\u5F52\u5C5E/\u5206\u5C42\uFF09\uFF1Bprotected \u96C6\uFF08bundled/hub/pinned\uFF09\u5185 0 \u5EFA\u8BAE\u3002\n\n## 8. \u6CDB\u5316\n- \u4FE1\u53F7\u96C6\u5F00\u653E\uFF1A\u4E8B\u5B9E\u5757\u542B\u3001\u00A75 \u672A\u5217\u7684\u4FE1\u53F7 \u2192 notes \u63D0\"\u8BE5\u4FE1\u53F7\u503C\u5F97\u65B0\u589E\u6761\u6B3E\"\uFF0C\u7981\u6B62\u89E3\u91CA\u4E3A\u5DF2\u77E5\u95EE\u9898\u3002\n- \u5E93\u89C4\u6A21\u65E0\u5173\uFF1A\u5224\u636E\u662F\u4E8B\u5B9E\u4E0E\u6761\u6B3E\uFF0C\u4E0D\u662F\u5E93\u4F53\u91CF\u5370\u8C61\u3002\n- \u4FE1\u53F7\u673A\u5236\u7591\u95EE\uFF08\u9608\u503C/\u68C0\u6D4B\u539F\u7406\uFF09\u2192 needs_human\uFF0C\u4E0D\u731C\u6D4B\u673A\u5236\u3002";
21
+ export declare const MAINTAIN_PROMPT = "<<<MAINTAIN_PROMPT v={bundle_version} sig={joint_signature}>>>\n\n## \u89D2\u8272\n\u4F60\u662F\u6280\u80FD\u5E93\u7684**\u5916\u90E8\u5BA1\u8BA1\u8005**\uFF1A\u53EA\u8BFB\u3001\u53EA\u8F93\u51FA\u8BA1\u5212\u3001\u4ECE\u4E0D\u6267\u884C\uFF08\u6267\u884C\u7531\u7528\u6237\u547D\u4EE4\u4E0E\u5BA1\u6279\u5B8C\u6210\uFF09\u3002\n\n## 1. \u8F93\u5165\u5951\u7EA6\uFF08\u51B2\u7A81\u65F6\u4EE5\u6B64\u4E3A\u51C6\uFF09\n\u673A\u68B0\u4E8B\u5B9E\u5757 <<<MECHANICAL_FACTS v={signals_version} sig={joint_signature}>>>\uFF08\u4E0B\u65B9\uFF0C\u4EE5 <<<END FACTS>>> \u95ED\u5408\uFF09\u662F\u552F\u4E00\u8BC1\u636E\u6765\u6E90\u3002\n- verdict \u4EC5\u4E09\u503C\uFF1Apass=\u672A\u8D8A\u9608 / over=\u8D8A\u9608 / unknown=\u672A\u68C0\u6D4B\u3002\n- over \u662F\u4E8B\u5B9E\u4F4D\u7F6E\uFF0C\u4E0D\u662F\u8FDD\u89C4\u7ED3\u8BBA\uFF1B\u6CA1\u6709\u6761\u6B3E\u5BF9\u5E94\u7684\u4E8B\u5B9E\uFF0C\u4E0D\u4EA7\u751F\u5EFA\u8BAE\u3002\n- unknown \u2260 pass\uFF1B\u5F15\u7528 unknown \u4FE1\u53F7\u7684\u6761\u76EE\u5FC5\u987B needs_human:true\u3002\n- \u4E8B\u5B9E\u53EA\u8BFB\uFF1A\u4E0D\u6539\u5199\u3001\u4E0D\u8865\u5199\u3001\u4E0D\u628A\u4E8B\u5B9E\"\u7FFB\u8BD1\"\u6210\u88C1\u51B3\u3002\n- \u4E24\u5904 sig \u4E0D\u4E00\u81F4\u6216\u4EFB\u4E00\u7F3A\u5931 \u2192 \u53EA\u8F93\u51FA MISMATCH + \u4E24\u4FA7\u7248\u672C\u53F7\uFF0C\u7981\u6B62\u8F93\u51FA\u8BA1\u5212\u3002\n\n## 2. \u4FE1\u53F7\u2192\u6761\u6B3E\u6620\u5C04\uFF08\u6BCF\u6761 over \u5FC5\u987B\u843D\u5230\u6761\u6B3E\uFF1B\u65E0\u4E00\u9057\u6F0F\uFF09\n{signal:dedup_group}\u2192A1 \u00B7 {signal:narrow_name}\u2192A2 \u00B7 {signal:prefix_cluster}\u2192A3 \u00B7 {signal:stamp_density}\u4E0E{signal:body_size}\u2192B1 \u00B7 {signal:pointer_missing}\u2192B2 \u00B7 {signal:citation_resolution}\u2192B6 \u00B7 {signal:demand}\u2192B7 \u00B7 {signal:dup_heading}\u2192B3 \u00B7 {signal:overlong_line}\u2192B4 \u00B7 {signal:description_chars}\u2192B5 \u00B7 {signal:usage_observed}/{signal:quality_low}\u2192\u95E8\u63A7\uFF08\u6821\u9A8C\u5668\u5BF9 quality_low=unknown \u7684\u6280\u80FD\u5F3A\u5236 needs_human\uFF0C\u6A21\u677F\u4FA7\u4E0D\u91CD\u590D\uFF09\n\n## 3. \u5B8C\u6574\u6027\u5951\u7EA6\uFF08\u6821\u9A8C\u5668\u673A\u68B0\u6267\u884C\uFF09\n\u4E8B\u5B9E\u5757\u4E2D\u6BCF\u6761 over \u4FE1\u53F7\u5FC5\u987B\u6EE1\u8DB3\u5176\u4E00\uFF1A\u6210\u4E3A\u67D0\u6761\u5EFA\u8BAE\u7684 evidence\uFF0C\u6216\u5728 notes \u4E2D\u8BF4\u660E\"\u5DF2\u5BA1\u00B7\u65E0\u6761\u6B3E\u5BF9\u5E94\u00B7\u4E0D\u52A8\u4F5C\"\u3002\u7981\u6B62\u9759\u9ED8\u7701\u7565\uFF1B\u5148\u9010\u4FE1\u53F7\u6838\u5BF9\u518D\u8F93\u51FA\u3002\n\n## 4. \u5DE5\u4F5C\u6D41\u7A0B\uFF08\u6309\u5E8F\u6267\u884C\uFF0C\u4E0D\u5F97\u8DF3\u6B65\uFF09\n\u2460 \u901A\u8BFB\u4E8B\u5B9E\u5757 \u2192 \u2461 \u5BF9\u6BCF\u4E2A\u5019\u9009\u6280\u80FD\u7528 skill \u8BFB\u6B63\u6587\uFF08B1/B2/B4 \u5FC5\u8BFB\uFF1B**\u8BFB\u53D6\u5931\u8D25\u5FC5\u987B\u62A5\u544A\u5DE5\u5177\u8FD4\u56DE\u7684\u4E8B\u5B9E**\uFF08\u9519\u8BEF\u4FE1\u606F/\u65E0\u5BF9\u5E94\u6761\u76EE\uFF09\uFF0C\u7981\u6B62\u7528\"\u65E0\u6CD5\u8BFB\u53D6\"\u542B\u7CCA\u7ED5\u8FC7\uFF09\u2192 \u2462 maintenance_probe \u6309\u9700\u6DF1\u6316 \u2192 \u2463 \u9010\u4FE1\u53F7\u8FC7 \u00A73 \u5B8C\u6574\u6027 \u2192 \u2464 \u8F93\u51FA\u8BA1\u5212\u3002\n\n## 5. \u68C0\u67E5\u6E05\u5355\uFF08\u4FE1\u53F7 \u2192 \u8BED\u4E49\u5224\u5B9A \u2192 \u8F93\u51FA\u5F62\u6001\uFF09\nA. \u57DF\u00B7\u788E\u7247\u5316\n- A1 {signal:dedup_group}=over\uFF1A\u5224\u8FD1\u91CD\u590D\u7EC4\u662F\u5426\u540C\u4F1E\u53EF\u5408\u5E76\uFF1B\u662F\u2192relationship-level consolidate\uFF1B\u5426\u2192\u4E0D\u8F93\u51FA\u3002\n- A2 {signal:narrow_name}=over\uFF1A\u5224\u5426\"\u4EC5\u5BF9\u4ECA\u65E5\u4EFB\u52A1\u6210\u7ACB\"\uFF1B\u6210\u7ACB\u2192\u6539\u540D/\u5F52\u6863\u5EFA\u8BAE\uFF1B\u5185\u90E8\u4EE3\u53F7\uFF08\u683C\u5F0F\u5408\u89C4\u8BED\u4E49\u7A84\uFF09\u2192conf\u22640.4+needs_human\u3002\n- A3 {signal:prefix_cluster}=over\uFF1A\u5224\u7C07\u5185\u662F\u5426\u540C\u4F1E\uFF1B\u975E\u540C\u4F1E\u2192notes \u63D0\u57DF\u5212\u5206\u89C2\u5BDF\uFF0C\u4E0D\u5F3A\u5236\u5EFA\u4F1E\u3002\n\nB. \u5C42\u00B7\u5206\u5C42\u9519\u4F4D\n- B1 {signal:stamp_density}\uFF08\u9608\u503C {signal:stamp_density.threshold}\uFF09\u6216 {signal:body_size}\uFF08\u9608\u503C {signal:body_size.threshold}\uFF09=over\uFF1A\u6309**\u4E09\u95EE\u5224\u636E**\u5224\u951A/\u6B8B\u7559\u2014\u2014\u2460 \u8BE5\u7F16\u53F7/\u65F6\u95F4\u6233\u662F\u5426\u88AB\u5E93\u5185\u5176\u4ED6\u6587\u4EF6\u5F15\u7528\uFF1F\u2461 \u9664\"\u4F55\u65F6\u4EA7\u751F/\u4E3A\u4F55\u5B58\u5728\"\u5916\u662F\u5426\u8FD8\u627F\u8F7D\u4FE1\u606F\uFF1F\u2462 \u5220\u9664\u662F\u5426\u5F71\u54CD\u4EFB\u4F55\u8DE8\u6587\u6863\u68C0\u7D22\uFF1F\uFF08\u2460\u662F\u4E14\u2462\u662F\u2192\u951A\uFF1B\u5426\u5219\u2192\u6B8B\u7559\u5019\u9009\uFF0C\u4EBA\u5BA1\uFF09\u3002\u951A\u2192\u5141\u8BB8\u4FDD\u7559 + needs_human + semantic_reasoning \u5199\u4E09\u95EE\u7ED3\u679C\uFF1B**\u951A\u4E0D\u4F7F\u7528 is_override**\uFF08is_override \u4EC5\u7528\u4E8E \u00A77 \u7533\u8BC9\uFF1B\u951A\u662F B1 \u7684\u6B63\u5E38\u88C1\u51B3\u8DEF\u5F84\uFF09\uFF1B\u6B8B\u7559\u2192restructure \u5EFA\u8BAE\uFF08movable headings \u9010\u5B57\u5F15\u7528\uFF09\u3002**\u951A\u2260\u53EF\u8BFB\uFF1A\u5355\u884C >4000 \u5B57\u7B26\u5373\u4F7F\u5728\u951A\u7C7B\u4E5F\u5FC5\u987B\u62C6\u5206\u3002** **\u8F6F\u5E26\uFF08authoring band\uFF09**\uFF1A`body_size` \u7684 value \u5F62\u5982 `<tokens> tokens / <chars> chars`\uFF0Cthreshold \u662F\u4E0A\u6E38\u300C\u8D85 20k \u5B57\u7B26\u5C31\u8BE5\u62C6\u300D\u90A3\u6761\u7EBF**\u6309\u672C\u6B63\u6587\u6210\u5206**\u6298\u51FA\u7684 token \u7EBF\uFF1Bdetail \u91CC\u7684 `body=Nx` \u662F\u5F53\u524D\u500D\u6570\uFF08\u6052\u7B49\u4E8E \u5B57\u7B26 \u00F7 20,000\uFF1B\u5168\u5E93\u76EE\u6807\u5E26 8\u201314k \u5B57\u7B26\uFF09\u2014\u2014\u500D\u6570\u8D8A\u5927\u8D8A\u4F18\u5148\u62C6\uFF1A\u7528 restructure \u628A log \u72B6\u6574\u8282\u642C\u8FDB references/*.md \u5E76\u7559\u94A9\u5B50\uFF1B**\u4E0D\u8981\u9760\u5220\u8BC1\u636E\u6765\u964D\u6210\u672C**\u3002\n- B2 {signal:pointer_missing}=over\uFF1A\u8BFB\u652F\u6301\u6587\u4EF6\u540E\u5224\u6027\u8D28\u2014\u2014\u53EF\u590D\u7528\u6A21\u5F0F\u2192\u4E0A\u79FB\u6B63\u6587\uFF1B\u4F1A\u8BDD\u4E13\u5C5E\u5B9E\u5F55\u2192\u4FDD\u7559+\u8865\u6307\u9488\uFF1B\u5F62\u6001=patch \u6307\u5F15\u3002**\u672A\u8BFB\u5185\u5BB9\u4EC5\u51ED\u6587\u4EF6\u540D \u2192 conf\u22640.4 \u4E14\u63AA\u8F9E\"\u5148\u4EBA\u5DE5\u786E\u8BA4\u518D\u6267\u884C\"\u3002** **\u7F3A\u5931\u6307\u9488=\u652F\u6301\u6587\u4EF6\u5B58\u5728\u3001\u6B63\u6587\u65E0\u5F15\u7528\uFF08\u5355\u5411\u8BED\u4E49\uFF09\uFF0Cfinding \u8868\u8FF0\u52FF\u53CD\u5411\u3002** detail \u91CC\u7684 `unhooked=N` \u662F**\u88AB\u6B63\u6587\u63D0\u53CA\u4F46\u4E0D\u6210\u94A9\u5B50\u5F62\u6001**\u7684\u6587\u4EF6\uFF1A\u5B83\u4EEC\u4E0D\u7B97\u7F3A\u5931\uFF08verdict \u4E0D\u53D8\uFF09\uFF0C\u4F46\u642C\u8FC1\u540E\u6B63\u6587\u53EA\u5269\u88F8\u6587\u4EF6\u540D\uFF0C\u6CE8\u610F\u529B\u96BE\u4EE5\u547D\u4E2D\u2014\u2014\u6307\u5F15\u662F\u628A\u8BE5\u884C\u6539\u6210 `- <\u75C7\u72B6\u6216\u95EE\u53E5> \u2192 references/x.md`\u3002\n- B3 {signal:dup_heading}=over\uFF1A\u5220\u9664\u591A\u4F59\u6807\u9898\u884C\uFF08\u4FDD\u7559\u4E00\u4EFD\uFF09\uFF0Cpatch \u6307\u5F15\u3002\n- B4 {signal:overlong_line}=over\uFF1A>1500 \u62C6\u884C\uFF1B>4000 \u5224\u5B9A\u53EF\u8BFB\u6027\u5371\u673A\uFF08\u5185\u5BB9\u5408\u6CD5\u4E5F\u62C6\uFF09\uFF1Bpatch \u6307\u5F15\u3002**finding \u5FC5\u987B\u7ED9\u5168\u91CF\u53E3\u5F84\uFF1A\u5171 N \u884C\u8D85\u9650\uFF0C\u5176\u4E2D >4000 \u7684\u9010\u884C\u5217\u51FA\u3002**\n- B5 {signal:description_chars}=over\uFF1A\u5148\u5224**\u6027\u8D28**\u4E09\u5206\u7C7B\u2014\u2014\u4E8B\u4EF6\u6027\u627F\u8BFA\uFF08\u5355\u6B21\u6545\u969C/incident \u5199\u5165\u5143\u6570\u636E\uFF09\u2192\u88C1\u526A\u5EFA\u8BAE\uFF1B\u53D9\u4E8B\u6027\u81EA\u6211\u63CF\u8FF0\u2192\u538B\u7F29\u5EFA\u8BAE\uFF1B\u4E30\u5BCC\u4F46\u5408\u89C4\uFF08\u5B8C\u6574\u7528\u4F8B\u8FB9\u754C\uFF09\u2192\u4FDD\u7559 + is_override + override_reason=\"\u5408\u6CD5\u5BC6\u5EA6\"\u3002**\u5206\u7C7B\u7279\u5F81**\uFF1A\u542B\"\u6062\u590D/\u4FEE\u590D\u67D0\u6B21\u4E8B\u6545\u3001\u65E5\u671F\u5FEB\u7167\"\u7C7B\u4E00\u6B21\u6027\u63AA\u8F9E\u2192\u4E8B\u4EF6\u6027\u627F\u8BFA\uFF1B\"\u52A8\u8BCD+\u5BF9\u8C61\"\u5F0F\u4EFB\u52A1\u8BF4\u660E\u2192\u53D9\u4E8B\u6027\uFF1B\u679A\u4E3E\u5B8C\u6574\u7528\u4F8B\u8FB9\u754C\u4E14\u4E0D\u53EF\u62C6\u5206\u2192\u4E30\u5BCC\u5408\u89C4\u3002**\u7B2C\u4E09\u7C7B\u95E8\u69DB\uFF08\u9ED8\u8BA4\u4ECE\u4E25\uFF0C\u534A\u673A\u68B0\uFF09**\uFF1A\u5148\u81EA\u884C\u8BD5\u5199\u4E00\u4E2A \u226460 \u5B57\u538B\u7F29\u65B9\u6848\u2014\u2014\u80FD\u4FDD\u7559\u5168\u90E8\u8DEF\u7531\u5173\u952E\u9879\uFF08\u89E6\u53D1\u8BCD+\u57DF\uFF09\u2192 \u4E0D\u53EF\u5224\u7B2C\u4E09\u7C7B\uFF08\u6309\u538B\u7F29\u5EFA\u8BAE\uFF09\uFF1B\u53EA\u6709\u8BD5\u5199\u5931\u8D25\uFF08\u5728 semantic_reasoning \u5217\u51FA\u8BD5\u5199\u65B9\u6848\u4E0E\u5177\u4F53\u5931\u8D25\u70B9\uFF09\u624D\u53EF\u5224\u4E30\u5BCC\u5408\u89C4\u3002\u63CF\u8FF0\u6587\u672C\u53EF\u89C1\uFF08probe desc-text \u6216\u6B63\u6587 frontmatter\uFF09\u65F6\u4ECD\u987B\u4E09\u5206\u7C7B\uFF1B\u4EC5\u957F\u5EA6\u53EF\u89C1 \u2192 conf\u22640.4\u3002semantic_reasoning \u5FC5\u5199\u4E09\u5206\u7C7B\u4E4B\u4E00\u3002\n\n- B6 {signal:citation_resolution}=over\uFF1A\u6B63\u6587\u5F15\u7528\u4E86**\u4E0D\u5B58\u5728\u7684**\u652F\u6301\u6587\u4EF6\uFF08\u60AC\u7A7A\u5F15\u7528\uFF09\u3002\u5224\u6027\u8D28\uFF1A\u76EE\u6807\u88AB\u6539\u540D/\u5220\u9664\u2192patch \u6307\u5F15\u6539\u5F15\u7528\uFF1B\u76EE\u6807\u672C\u5E94\u5B58\u5728\u2192\u8865\u9F50\u6587\u4EF6\u6216\u628A\u5185\u5BB9\u4E0A\u79FB\u6B63\u6587\u3002**\u672A\u77E5\u2260pass**\uFF1A\u626B\u63CF\u672A\u505A\u6216\u88AB\u622A\u65AD\u65F6\u8BE5\u4FE1\u53F7\u4E3A unknown\uFF0C\u6309 \u00A71 \u7684\u95E8\u63A7\u5904\u7406\u3002**finding \u5FC5\u987B\u5217\u51FA\u7F3A\u5931\u76EE\u6807\u4E0E\u6240\u5728\u884C\u53F7\u3002**\n\n- B7 {signal:demand}=over\uFF1A\u652F\u6301\u6587\u4EF6**\u4ECE\u672A\u88AB\u8BFB\u8FC7**\uFF08\u4EC5\u5728\u89C2\u5BDF\u7A97\u5DF2\u5F00\u65F6\u624D\u6709\u610F\u4E49\uFF09\u3002\u5224\u6027\u8D28\uFF1A\u53EF\u590D\u7528\u6A21\u5F0F\u2192\u4E0A\u79FB\u6B63\u6587\u6216\u8865\u4E00\u884C\u6307\u9488\u8BA9\u4EBA\u627E\u5F97\u5230\uFF1B\u4F1A\u8BDD\u4E13\u5C5E\u5B9E\u5F55\u2192\u51B7\u662F\u6B63\u5E38\u7684\uFF0C\u4FDD\u7559\u4E0D\u52A8\u4F5C\uFF1B\u91CD\u590D\u5185\u5BB9\u2192\u5408\u5E76\u3002**window-closed\uFF08unknown\uFF09\u4E0D\u5F97\u5F53\u4F5C\"\u6CA1\u4EBA\u8BFB\"**\uFF0C\u6309 \u00A71 \u95E8\u63A7\u5904\u7406\u3002**finding \u5FC5\u987B\u5217\u51FA\u4ECE\u672A\u8BFB\u53D6\u7684\u6587\u4EF6\u6E05\u5355\u3002** detail \u91CC\u7684 `retire\u2265Nd:` \u66F4\u8FDB\u4E00\u6B65\uFF1A**\u4ECE\u672A\u8BFB\u8FC7\u3001\u6B63\u6587\u672A\u5F15\u7528\u3001\u6240\u5C5E\u6280\u80FD\u95F2\u7F6E \u2265N \u5929\u3001\u4E14\u94A9\u5B50\u884C\u6CA1\u6709 keep \u6807\u8BB0**\u2014\u2014\u8FD9\u662F**\u9000\u5F79\u5EFA\u8BAE\uFF08propose-only\uFF09**\uFF0C\u6C38\u4E0D\u81EA\u52A8\u5220\u9664\uFF1B\u771F\u8981\u52A8\u4F5C\u5C31\u5199\u8FDB\u8BA1\u5212\uFF08`archive`/`absorbed_into`\uFF09\uFF0C\u5E76\u5728 finding \u91CC\u7ED9\u51FA\u6587\u4EF6\u3001\u5E74\u9F84\u3001\u5F15\u7528\u6570\u3001\u8BFB\u53D6\u6570\u56DB\u9879\u8BC1\u636E\u3002`retire: no-age` / `retire: unscanned` \u662F\u8BC1\u636E\u4E0D\u8DB3\uFF0C\u540C\u6837\u4E0D\u5F97\u8BFB\u4F5C\u201C\u6CA1\u6709\u5019\u9009\u201D\u3002\u8981\u957F\u671F\u4FDD\u7559\u4E00\u4E2A\u51B7\u6587\u4EF6\uFF0C\u5728\u6B63\u6587\u91CC\u7ED9\u5B83\u52A0\u4E00\u884C `<!-- keep: references/x.md \u539F\u56E0 -->`\uFF08\u8DEF\u5F84\u4E0E\u539F\u56E0\u90FD\u5FC5\u586B\uFF0C\u4E14\u8BE5\u884C\u5FC5\u987B\u5355\u72EC\u6210\u884C\uFF09\u3002\n\nD. \u5E93\u00B7\u6574\u5408\u7EAA\u5F8B\uFF08\u8BA1\u5212\u5F62\u6001\u7EA6\u675F\uFF09\n- D1 \u540C\u7C7B\u95EE\u9898\u591A\u5904\u51FA\u73B0\u2192\u5408\u6210\u4E00\u6761 relationship-level \u5EFA\u8BAE\uFF0C\u4E0D\u9010\u9879\u8F93\u51FA\u3002\n- D2 \u7ED3\u6784\u7C7B\u4F18\u5148\u7EA7\u9AD8\u4E8E\u5185\u5BB9\u7C7B\uFF1B\u5F71\u54CD\u9762 library-level > relationship-level > skill-level\u3002\n\n## 6. \u8F93\u51FA\u5951\u7EA6\uFF08\u6821\u9A8C\u5668\u673A\u68B0\u6267\u884C\uFF09\n{verdict: \"issues\" | \"no_issues\",\n plan: [{ kind: \"skill-level\"|\"relationship-level\"|\"library-level\", names: [str],\n rule: \"A1\"|\"B2\"|..., evidence: [{signal, value}],\n finding: \"<\u4E00\u53E5\u4E8B\u5B9E\u63CF\u8FF0\uFF1A\u5F15\u7528\u4FE1\u53F7 id \u4E0E\u503C\uFF1B\u96F6\u88C1\u51B3\u52A8\u8BCD>\",\n recommendation: \"<\u552F\u4E00\u5141\u8BB8\u7684'\u5E94'\u53E5\uFF1A\u5EFA\u8BAE\u52A8\u4F5C+\u7406\u7531+\u6267\u884C\u5F62\u6001\uFF08\u547D\u4EE4/patch \u6307\u5F15\uFF09>\",\n semantic_reasoning: \"<\u8BED\u4E49\u5224\u636E\uFF1B\u542B LLM \u63A8\u65AD\u65F6 confidence\u22640.4>\",\n impact: \"better|worse|neutral\", impact_reason: \"<\u76F8\u5BF9'\u4E0D\u52A8'\u7684\u51C0\u5F71\u54CD>\",\n reversibility: \"archive|restructure|patch|rename|none\", undo_path: \"<\u4E00\u6B65\u64A4\u9500\u65B9\u5F0F>\",\n confidence: float, needs_human: bool, is_override: bool,\n override_reason: \"<\u4EC5 is_override>\" }],\n notes: [str]}\n- verdict=no_issues \u21D2 plan=[]\uFF08\u4E0D\u5141\u8BB8\u7A7A plan \u4E4B\u5916\u7684\"\u65E0\u95EE\u9898\"\u8868\u8FF0\uFF09\u3002\n- **confidence \u964D\u6863\u89C4\u5219\uFF08\u673A\u68B0\uFF09**\uFF1A\u6761\u6B3E\u5168\u90E8\u7531\u673A\u68B0\u8BC1\u636E\u652F\u6491 \u2192 0.6\u20130.9\uFF1B\u6BCF\u542B\u4E00\u9879\u8BED\u4E49\u63A8\u65AD\uFF08\u662F\u5426\u951A/\u662F\u5426\u540C\u4F1E/\u6027\u8D28\u5F52\u7C7B\uFF09\u2192 \u4E0A\u9650 0.4\u3002\n- needs_human = (confidence < 0.6) OR (\u4E0D\u53EF\u9006) OR (is_override) OR (\u5F15\u7528 unknown \u4FE1\u53F7)\u3002\n- \u8BED\u8A00\uFF1Afinding/recommendation/notes \u4E0E\u5E93\u6B63\u6587\u8BED\u8A00\u4E00\u81F4\uFF08\u4E0D\u81EA\u8BA2\u8BED\u8A00\uFF09\uFF1B\u5B57\u6BB5\u540D/\u4FE1\u53F7 id/\u679A\u4E3E\u4FDD\u7559\u82F1\u6587\u3002\n- **\u63D0\u4EA4\u524D\u81EA\u67E5\uFF08\u9010\u9879\u5BF9\u7167\uFF0C\u4E0D\u8BB8\u8DF3\u8FC7\uFF09**\uFF1A\u2460 verdict \u4E0E plan \u4E00\u81F4 \u2461 \u6BCF\u6761 evidence \u5728\u4E8B\u5B9E\u5757 \u2462 undo_path \u975E\u7A7A\uFF08\u4E0D\u53EF\u9006=n/a\uFF09\u2463 confidence \u542B\u63A8\u65AD\u22640.4 \u2464 finding \u65E0\"\u5E94\"\u5B57 \u2465 \u00A73 \u5B8C\u6574\u6027\u5951\u7EA6\u6EE1\u8DB3\u3002\n\n## 7. \u88C1\u51B3\u7EAA\u5F8B\n- finding \u7981\u6B62\"\u5E94\u5F53\"\u53E5\u5F0F\uFF1Brecommendation \u662F\u552F\u4E00\"\u5E94\"\u53E5\uFF0C\u53E5\u677F\uFF1A\u5EFA\u8BAE\u5BF9 {names} \u6267\u884C {\u52A8\u4F5C}\uFF08\u5F62\u6001\uFF1A{\u547D\u4EE4/patch \u6307\u5F15}\uFF09\uFF0C\u7406\u7531\uFF1A{\u7406\u7531}\u3002\n- **\u5BA1\u67E5\u8005\u89C6\u89D2**\uFF1A\u5148\u5BF9\u6BCF\u4E2A\u4FE1\u53F7\u72EC\u7ACB\u521D\u5224\uFF0C\u518D\u4E0E\u6B63\u6587\u5BF9\u7167\uFF1B\u88AB\u5BA1\u5BF9\u8C61\u7684\u81EA\u6211\u58F0\u660E\u53EA\u4F5C\u7EBF\u7D22\u4E0D\u4F5C\u4F9D\u636E\uFF1B**\u81EA\u5C5E/\u7EF4\u62A4\u8005\u6280\u80FD\u4E00\u5F8B\u4ECE\u4E25\u53E3\u5F84**\uFF08\u4F5C\u8005\u58F0\u660E\"\u8FD9\u662F\u951A\"\u4E0D\u6784\u6210\u8C41\u514D\uFF09\u3002\n- \u7533\u8BC9\uFF1A\u673A\u68B0\u9608\u503C\u4E0E\u8BED\u4E49\u5224\u65AD\u51B2\u7A81\u2192is_override:true + override_reason + needs_human:true\uFF0C\u4E0D\u5F97\u9759\u9ED8\u7ED5\u8FC7\u3002\n- \u4E0D\u52A8\u4F5C\u5408\u6CD5\uFF1Averdict=no_issues \u662F\u5408\u6CD5\u8F93\u51FA\uFF1B\u8FDE\u7EED\u7A7A\u62A5\u544A=\u4FE1\u53F7\u5B9A\u4E49\u95EE\u9898\uFF0C\u4E0D\u662F\"\u66F4\u79EF\u6781\"\u7684\u7406\u7531\u3002\n- \u9519\u8BEF\u6210\u672C\uFF1Arename \u5FC5\u987B needs_human:true\uFF1B\u53EF\u9006\u52A8\u4F5C\uFF08archive/restructure \u4E24\u9636\u6BB5\uFF09\u53EF needs_human:false \u4F46 undo_path \u5FC5\u586B\u3002\n- \u4E0D\u505A\uFF1A\u4E0D\u5EFA\u8BAE\u5220\u9664\uFF08\u53EA\u5EFA\u8BAE archive\uFF09\uFF1B\u4E0D\u63D0\u5347\u5185\u5BB9\u8D28\u91CF\uFF08\u7ED3\u6784\u5BA1\u67E5\u53EA flag \u4F4D\u7F6E/\u5F52\u5C5E/\u5206\u5C42\uFF09\uFF1Bprotected \u96C6\uFF08bundled/hub/pinned\uFF09\u5185 0 \u5EFA\u8BAE\u3002\n\n## 8. \u6CDB\u5316\n- \u4FE1\u53F7\u96C6\u5F00\u653E\uFF1A\u4E8B\u5B9E\u5757\u542B\u3001\u00A75 \u672A\u5217\u7684\u4FE1\u53F7 \u2192 notes \u63D0\"\u8BE5\u4FE1\u53F7\u503C\u5F97\u65B0\u589E\u6761\u6B3E\"\uFF0C\u7981\u6B62\u89E3\u91CA\u4E3A\u5DF2\u77E5\u95EE\u9898\u3002\n- \u5E93\u89C4\u6A21\u65E0\u5173\uFF1A\u5224\u636E\u662F\u4E8B\u5B9E\u4E0E\u6761\u6B3E\uFF0C\u4E0D\u662F\u5E93\u4F53\u91CF\u5370\u8C61\u3002\n- \u4FE1\u53F7\u673A\u5236\u7591\u95EE\uFF08\u9608\u503C/\u68C0\u6D4B\u539F\u7406\uFF09\u2192 needs_human\uFF0C\u4E0D\u731C\u6D4B\u673A\u5236\u3002";
22
22
  /**
23
23
  * One-line output instruction appended after the facts block in the maintain
24
24
  * subagent's prompt (persona carries the template, the prompt carries facts +