From 9bed4a426e1b8343e4f1377e11d7a0a2e135ca28 Mon Sep 17 00:00:00 2001 From: zizi Date: Mon, 24 Aug 2026 02:16:01 +0800 Subject: [PATCH] refactor: separate Muse business and agent framework layers --- .agent/_index.md | 9 +- .agent/docs/_index.md | 5 +- .agent/skills/_index.md | 106 +--- .../{ => diagnosis}/novel-diagnosis/SKILL.md | 0 .../novel-diagnosis/references/_coverage.md | 0 .../references/diagnosis-workflow.md | 0 .../references/dimension-frameworks.md | 0 .../references/fantasy-prophecy.md | 0 .../references/pattern-rhythm.md | 0 .../references/plot-character.md | 0 .../references/quack-scholar-scan.md | 0 .../references/quack-scholar.md | 0 .../novel-diagnosis/references/round-table.md | 0 .../novel-diagnosis/references/story-plot.md | 0 .../novel-diagnosis/references/time-value.md | 0 .../{ => planning}/concept-design/SKILL.md | 0 .../concept-design/references/_coverage.md | 0 .../references/concept-worksheet.md | 0 .../references/delivery-strategy.md | 0 .../references/four-questions.md | 0 .../concept-design/references/originality.md | 0 .../concept-design/references/story-engine.md | 0 .../concept-design/references/what-if.md | 0 .../{ => planning}/foreshadow-payoff/SKILL.md | 0 .../foreshadow-payoff/references/_coverage.md | 0 .../references/boundaries-and-pitfalls.md | 0 .../references/detail-driven-climax.md | 0 .../references/foreshadow-checklist.md | 0 .../references/foreshadow-ledger-template.md | 0 .../references/natural-staircase.md | 0 .../references/register-and-repay.md | 0 .../narrative-momentum/SKILL.md | 0 .../references/_coverage.md | 0 .../alternation-and-distinctions.md | 0 .../references/breakpoint-hooks.md | 0 .../references/build-momentum.md | 0 .../references/midway-rewards.md | 0 .../references/momentum-checklist.md | 0 .../{ => planning}/story-ending/SKILL.md | 0 .../story-ending/references/_coverage.md | 0 .../references/ending-strategies.md | 0 .../references/execution-chain.md | 0 .../references/expansion-completion.md | 0 .../references/fix-final-scene.md | 0 .../story-ending/references/natural-stop.md | 0 .../references/pitfalls-and-boundaries.md | 0 .../{ => planning}/story-planning/SKILL.md | 0 .../story-planning/references/_coverage.md | 0 .../story-planning/references/beat-sheet.md | 0 .../story-planning/references/draft-flow.md | 0 .../references/plan-vs-pantsing.md | 0 .../references/planning-workflow-checklist.md | 0 .../{ => planning}/story-structure/SKILL.md | 0 .../story-structure/references/_coverage.md | 0 .../references/first-plot-point.md | 0 .../story-structure/references/four-boxes.md | 0 .../references/inciting-incident.md | 0 .../references/inciting-vs-fpp.md | 0 .../references/length-system.md | 0 .../story-structure/references/midpoint.md | 0 .../story-structure/references/opening.md | 0 .../references/part2-wanderer.md | 0 .../story-structure/references/setup.md | 0 .../references/six-milestones.md | 0 .../references/structure-checklists.md | 0 .../{ => writing}/character-design/SKILL.md | 0 .../character-design/references/_coverage.md | 0 .../references/archetype-reversal.md | 0 .../references/character-diagnosis.md | 0 .../references/character-worksheet.md | 0 .../references/flat-vs-round.md | 0 .../references/inner-demon.md | 114 ++++ .../references/seven-variables.md | 0 .../references/three-dimensions.md | 0 .../character-presentation/SKILL.md | 0 .../references/_coverage.md | 0 .../references/abnormal-moment.md | 0 .../references/character-collision.md | 0 .../references/detail-mosaic.md | 0 .../references/presentation-checklist.md | 0 .../references/relationship-web.md | 0 .../references/visible-private-life.md | 0 .../references/voice-discovery-process.md | 0 .../{ => writing}/dialogue-craft/SKILL.md | 0 .../dialogue-craft/references/_coverage.md | 0 .../references/boundaries-and-pitfalls.md | 0 .../references/character-voice.md | 0 .../references/dialogue-does-things.md | 0 .../references/dialogue-revision-checklist.md | 0 .../references/execution-flow.md | 0 .../references/real-speech-texture.md | 0 .../references/rhythm-and-density.md | 0 .../references/tags-and-attribution.md | 0 .../references/when-to-use-dialogue.md | 0 .../{ => writing}/narration-pov/SKILL.md | 0 .../narration-pov/references/_coverage.md | 0 .../narration-pov/references/broken-line.md | 0 .../references/certainty-uncertainty.md | 0 .../references/narration-pov-checklist.md | 0 .../references/outsider-entry.md | 0 .../narration-pov/references/pov-camera.md | 0 .../narration-pov/references/pov-execution.md | 0 .../references/skeptical-stance.md | 0 .../skills/{ => writing}/prose-craft/SKILL.md | 0 .../prose-craft/references/_coverage.md | 0 .../references/abstraction-ladder.md | 0 .../references/base-temperature.md | 0 .../prose-craft/references/lyric-restraint.md | 0 .../references/pattern-and-break.md | 0 .../references/plain-description.md | 112 ++++ .../references/revision-checklist.md | 0 .../references/rhetoric-density.md | 0 .../prose-craft/references/sentence-rhythm.md | 0 .../prose-craft/references/voice-equalizer.md | 0 .../skills/{ => writing}/scene-craft/SKILL.md | 0 .../scene-craft/references/_coverage.md | 0 .../references/boundaries-and-pitfalls.md | 0 .../scene-craft/references/scene-camera.md | 0 .../scene-craft/references/scene-detail.md | 0 .../references/scene-entry-exit.md | 0 .../references/scene-ledger-template.md | 0 .../scene-craft/references/scene-mission.md | 0 .../references/scene-mystification.md | 0 .../references/scene-revision-checklist.md | 0 .../scene-craft/references/scene-rhythm.md | 0 .../{ => writing}/show-and-omission/SKILL.md | 0 .../show-and-omission/references/_coverage.md | 0 .../references/anti-logic.md | 0 .../references/extreme-emotion-body.md | 0 .../show-and-omission/references/iceberg.md | 0 .../references/imagination-anchor.md | 0 .../references/pov-knowledge-boundary.md | 0 .../references/reader-gap-diagnosis.md | 0 .../references/show-omission-checklist.md | 0 .../references/show-vs-tell.md | 0 .../{ => writing}/theme-and-stance/SKILL.md | 0 .../theme-and-stance/references/_coverage.md | 0 .../references/boundaries-and-pitfalls.md | 0 .../references/humor-as-stance.md | 0 .../theme-and-stance/references/mercy-ruth.md | 0 .../references/stance-by-logic.md | 0 .../references/theme-demonstration.md | 0 .../references/theme-stance-checklist.md | 0 AGENTS.md | 92 ++- README.md | 27 +- docs/2026-07-16-升格卡改造设计.md | 8 +- docs/2026-07-30-落库与看板设计.md | 44 +- docs/2026-08-19-craft-distillation-trace.md | 2 +- ...2026-08-20-skill-质量审查与复利改造清单.md | 4 +- docs/2026-08-20-质量收敛环运行手册.md | 2 +- docs/design/深渊机神-前期设计.md | 2 +- docs/plans/2026-08-23-目录分层改造.md | 563 ++++++++++++++++++ docs/plans/2026-08-24-双底座适配接缝.md | 304 ++++++++++ .../2026-08-24-dsh-local-runtime-baseline.md | 36 ++ framework/README.md | 15 + framework/__init__.py | 1 + framework/adapters/__init__.py | 1 + framework/adapters/dsh/README.md | 34 ++ framework/adapters/dsh/__init__.py | 39 ++ framework/adapters/dsh/normalization.py | 347 +++++++++++ framework/adapters/dsh/runner.py | 468 +++++++++++++++ framework/adapters/pi/__init__.py | 1 + .../adapters/pi/mcp_bridge.ts | 0 framework/adapters/pi/normalization.py | 102 ++++ .../adapters/pi/runner.py | 39 +- framework/catalog/catalog.json | 97 +++ .../dsh/skills/character-design/SKILL.md | 102 ++++ .../character-design/references/_coverage.md | 11 + .../references/archetype-reversal.md | 141 +++++ .../references/character-diagnosis.md | 96 +++ .../references/character-worksheet.md | 91 +++ .../references/flat-vs-round.md | 141 +++++ .../references/inner-demon.md | 0 .../references/seven-variables.md | 117 ++++ .../references/three-dimensions.md | 123 ++++ .../skills/character-presentation/SKILL.md | 110 ++++ .../references/_coverage.md | 13 + .../references/abnormal-moment.md | 178 ++++++ .../references/character-collision.md | 200 +++++++ .../references/detail-mosaic.md | 139 +++++ .../references/presentation-checklist.md | 124 ++++ .../references/relationship-web.md | 228 +++++++ .../references/visible-private-life.md | 143 +++++ .../references/voice-discovery-process.md | 67 +++ .../dsh/skills/concept-design/SKILL.md | 93 +++ .../concept-design/references/_coverage.md | 13 + .../references/concept-worksheet.md | 102 ++++ .../references/delivery-strategy.md | 99 +++ .../references/four-questions.md | 93 +++ .../concept-design/references/originality.md | 173 ++++++ .../concept-design/references/story-engine.md | 122 ++++ .../concept-design/references/what-if.md | 109 ++++ .../dsh/skills/dialogue-craft/SKILL.md | 115 ++++ .../dialogue-craft/references/_coverage.md | 22 + .../references/boundaries-and-pitfalls.md | 160 +++++ .../references/character-voice.md | 87 +++ .../references/dialogue-does-things.md | 69 +++ .../references/dialogue-revision-checklist.md | 96 +++ .../references/execution-flow.md | 96 +++ .../references/real-speech-texture.md | 59 ++ .../references/rhythm-and-density.md | 51 ++ .../references/tags-and-attribution.md | 72 +++ .../references/when-to-use-dialogue.md | 110 ++++ .../dsh/skills/foreshadow-payoff/SKILL.md | 78 +++ .../foreshadow-payoff/references/_coverage.md | 13 + .../references/boundaries-and-pitfalls.md | 107 ++++ .../references/detail-driven-climax.md | 112 ++++ .../references/foreshadow-checklist.md | 80 +++ .../references/foreshadow-ledger-template.md | 60 ++ .../references/natural-staircase.md | 120 ++++ .../references/register-and-repay.md | 132 ++++ .../catalog/dsh/skills/narration-pov/SKILL.md | 66 ++ .../narration-pov/references/_coverage.md | 14 + .../narration-pov/references/broken-line.md | 131 ++++ .../references/certainty-uncertainty.md | 128 ++++ .../references/narration-pov-checklist.md | 85 +++ .../references/outsider-entry.md | 130 ++++ .../narration-pov/references/pov-camera.md | 93 +++ .../narration-pov/references/pov-execution.md | 119 ++++ .../references/skeptical-stance.md | 139 +++++ .../dsh/skills/narrative-momentum/SKILL.md | 83 +++ .../references/_coverage.md | 12 + .../alternation-and-distinctions.md | 106 ++++ .../references/breakpoint-hooks.md | 105 ++++ .../references/build-momentum.md | 197 ++++++ .../references/midway-rewards.md | 114 ++++ .../references/momentum-checklist.md | 64 ++ .../dsh/skills/novel-diagnosis/SKILL.md | 115 ++++ .../novel-diagnosis/references/_coverage.md | 27 + .../references/diagnosis-workflow.md | 115 ++++ .../references/dimension-frameworks.md | 171 ++++++ .../references/fantasy-prophecy.md | 135 +++++ .../references/pattern-rhythm.md | 133 +++++ .../references/plot-character.md | 125 ++++ .../references/quack-scholar-scan.md | 61 ++ .../references/quack-scholar.md | 123 ++++ .../novel-diagnosis/references/round-table.md | 118 ++++ .../novel-diagnosis/references/story-plot.md | 123 ++++ .../novel-diagnosis/references/time-value.md | 122 ++++ .../catalog/dsh/skills/prose-craft/SKILL.md | 76 +++ .../prose-craft/references/_coverage.md | 15 + .../references/abstraction-ladder.md | 123 ++++ .../references/base-temperature.md | 174 ++++++ .../prose-craft/references/lyric-restraint.md | 199 +++++++ .../references/pattern-and-break.md | 94 +++ .../references/plain-description.md | 0 .../references/revision-checklist.md | 100 ++++ .../references/rhetoric-density.md | 106 ++++ .../prose-craft/references/sentence-rhythm.md | 138 +++++ .../prose-craft/references/voice-equalizer.md | 122 ++++ .../catalog/dsh/skills/scene-craft/SKILL.md | 95 +++ .../scene-craft/references/_coverage.md | 19 + .../references/boundaries-and-pitfalls.md | 160 +++++ .../scene-craft/references/scene-camera.md | 95 +++ .../scene-craft/references/scene-detail.md | 168 ++++++ .../references/scene-entry-exit.md | 126 ++++ .../references/scene-ledger-template.md | 23 + .../scene-craft/references/scene-mission.md | 125 ++++ .../references/scene-mystification.md | 121 ++++ .../references/scene-revision-checklist.md | 91 +++ .../scene-craft/references/scene-rhythm.md | 99 +++ .../dsh/skills/show-and-omission/SKILL.md | 84 +++ .../show-and-omission/references/_coverage.md | 17 + .../references/anti-logic.md | 191 ++++++ .../references/extreme-emotion-body.md | 138 +++++ .../show-and-omission/references/iceberg.md | 142 +++++ .../references/imagination-anchor.md | 144 +++++ .../references/pov-knowledge-boundary.md | 49 ++ .../references/reader-gap-diagnosis.md | 158 +++++ .../references/show-omission-checklist.md | 109 ++++ .../references/show-vs-tell.md | 201 +++++++ .../catalog/dsh/skills/story-ending/SKILL.md | 67 +++ .../story-ending/references/_coverage.md | 16 + .../references/ending-strategies.md | 41 ++ .../references/execution-chain.md | 49 ++ .../references/expansion-completion.md | 107 ++++ .../references/fix-final-scene.md | 59 ++ .../story-ending/references/natural-stop.md | 26 + .../references/pitfalls-and-boundaries.md | 107 ++++ .../dsh/skills/story-planning/SKILL.md | 93 +++ .../story-planning/references/_coverage.md | 10 + .../story-planning/references/beat-sheet.md | 181 ++++++ .../story-planning/references/draft-flow.md | 233 ++++++++ .../references/plan-vs-pantsing.md | 162 +++++ .../references/planning-workflow-checklist.md | 96 +++ .../dsh/skills/story-structure/SKILL.md | 81 +++ .../story-structure/references/_coverage.md | 17 + .../references/first-plot-point.md | 110 ++++ .../story-structure/references/four-boxes.md | 111 ++++ .../references/inciting-incident.md | 130 ++++ .../references/inciting-vs-fpp.md | 109 ++++ .../references/length-system.md | 130 ++++ .../story-structure/references/midpoint.md | 104 ++++ .../story-structure/references/opening.md | 188 ++++++ .../references/part2-wanderer.md | 110 ++++ .../story-structure/references/setup.md | 112 ++++ .../references/six-milestones.md | 126 ++++ .../references/structure-checklists.md | 162 +++++ .../dsh/skills/theme-and-stance/SKILL.md | 96 +++ .../theme-and-stance/references/_coverage.md | 15 + .../references/boundaries-and-pitfalls.md | 110 ++++ .../references/humor-as-stance.md | 125 ++++ .../theme-and-stance/references/mercy-ruth.md | 183 ++++++ .../references/stance-by-logic.md | 161 +++++ .../references/theme-demonstration.md | 130 ++++ .../references/theme-stance-checklist.md | 114 ++++ .../catalog/generate_skill_projections.py | 137 +++++ .../pi/skills/character-design/SKILL.md | 102 ++++ .../character-design/references/_coverage.md | 11 + .../references/archetype-reversal.md | 141 +++++ .../references/character-diagnosis.md | 96 +++ .../references/character-worksheet.md | 91 +++ .../references/flat-vs-round.md | 141 +++++ .../references/inner-demon.md | 114 ++++ .../references/seven-variables.md | 117 ++++ .../references/three-dimensions.md | 123 ++++ .../pi/skills/character-presentation/SKILL.md | 110 ++++ .../references/_coverage.md | 13 + .../references/abnormal-moment.md | 178 ++++++ .../references/character-collision.md | 200 +++++++ .../references/detail-mosaic.md | 139 +++++ .../references/presentation-checklist.md | 124 ++++ .../references/relationship-web.md | 228 +++++++ .../references/visible-private-life.md | 143 +++++ .../references/voice-discovery-process.md | 67 +++ .../catalog/pi/skills/concept-design/SKILL.md | 93 +++ .../concept-design/references/_coverage.md | 13 + .../references/concept-worksheet.md | 102 ++++ .../references/delivery-strategy.md | 99 +++ .../references/four-questions.md | 93 +++ .../concept-design/references/originality.md | 173 ++++++ .../concept-design/references/story-engine.md | 122 ++++ .../concept-design/references/what-if.md | 109 ++++ .../catalog/pi/skills/dialogue-craft/SKILL.md | 115 ++++ .../dialogue-craft/references/_coverage.md | 22 + .../references/boundaries-and-pitfalls.md | 160 +++++ .../references/character-voice.md | 87 +++ .../references/dialogue-does-things.md | 69 +++ .../references/dialogue-revision-checklist.md | 96 +++ .../references/execution-flow.md | 96 +++ .../references/real-speech-texture.md | 59 ++ .../references/rhythm-and-density.md | 51 ++ .../references/tags-and-attribution.md | 72 +++ .../references/when-to-use-dialogue.md | 110 ++++ .../pi/skills/foreshadow-payoff/SKILL.md | 78 +++ .../foreshadow-payoff/references/_coverage.md | 13 + .../references/boundaries-and-pitfalls.md | 107 ++++ .../references/detail-driven-climax.md | 112 ++++ .../references/foreshadow-checklist.md | 80 +++ .../references/foreshadow-ledger-template.md | 60 ++ .../references/natural-staircase.md | 120 ++++ .../references/register-and-repay.md | 132 ++++ .../catalog/pi/skills/narration-pov/SKILL.md | 66 ++ .../narration-pov/references/_coverage.md | 14 + .../narration-pov/references/broken-line.md | 131 ++++ .../references/certainty-uncertainty.md | 128 ++++ .../references/narration-pov-checklist.md | 85 +++ .../references/outsider-entry.md | 130 ++++ .../narration-pov/references/pov-camera.md | 93 +++ .../narration-pov/references/pov-execution.md | 119 ++++ .../references/skeptical-stance.md | 139 +++++ .../pi/skills/narrative-momentum/SKILL.md | 83 +++ .../references/_coverage.md | 12 + .../alternation-and-distinctions.md | 106 ++++ .../references/breakpoint-hooks.md | 105 ++++ .../references/build-momentum.md | 197 ++++++ .../references/midway-rewards.md | 114 ++++ .../references/momentum-checklist.md | 64 ++ .../pi/skills/novel-diagnosis/SKILL.md | 115 ++++ .../novel-diagnosis/references/_coverage.md | 27 + .../references/diagnosis-workflow.md | 115 ++++ .../references/dimension-frameworks.md | 171 ++++++ .../references/fantasy-prophecy.md | 135 +++++ .../references/pattern-rhythm.md | 133 +++++ .../references/plot-character.md | 125 ++++ .../references/quack-scholar-scan.md | 61 ++ .../references/quack-scholar.md | 123 ++++ .../novel-diagnosis/references/round-table.md | 118 ++++ .../novel-diagnosis/references/story-plot.md | 123 ++++ .../novel-diagnosis/references/time-value.md | 122 ++++ .../catalog/pi/skills/prose-craft/SKILL.md | 76 +++ .../prose-craft/references/_coverage.md | 15 + .../references/abstraction-ladder.md | 123 ++++ .../references/base-temperature.md | 174 ++++++ .../prose-craft/references/lyric-restraint.md | 199 +++++++ .../references/pattern-and-break.md | 94 +++ .../references/plain-description.md | 112 ++++ .../references/revision-checklist.md | 100 ++++ .../references/rhetoric-density.md | 106 ++++ .../prose-craft/references/sentence-rhythm.md | 138 +++++ .../prose-craft/references/voice-equalizer.md | 122 ++++ .../catalog/pi/skills/scene-craft/SKILL.md | 95 +++ .../scene-craft/references/_coverage.md | 19 + .../references/boundaries-and-pitfalls.md | 160 +++++ .../scene-craft/references/scene-camera.md | 95 +++ .../scene-craft/references/scene-detail.md | 168 ++++++ .../references/scene-entry-exit.md | 126 ++++ .../references/scene-ledger-template.md | 23 + .../scene-craft/references/scene-mission.md | 125 ++++ .../references/scene-mystification.md | 121 ++++ .../references/scene-revision-checklist.md | 91 +++ .../scene-craft/references/scene-rhythm.md | 99 +++ .../pi/skills/show-and-omission/SKILL.md | 84 +++ .../show-and-omission/references/_coverage.md | 17 + .../references/anti-logic.md | 191 ++++++ .../references/extreme-emotion-body.md | 138 +++++ .../show-and-omission/references/iceberg.md | 142 +++++ .../references/imagination-anchor.md | 144 +++++ .../references/pov-knowledge-boundary.md | 49 ++ .../references/reader-gap-diagnosis.md | 158 +++++ .../references/show-omission-checklist.md | 109 ++++ .../references/show-vs-tell.md | 201 +++++++ .../catalog/pi/skills/story-ending/SKILL.md | 67 +++ .../story-ending/references/_coverage.md | 16 + .../references/ending-strategies.md | 41 ++ .../references/execution-chain.md | 49 ++ .../references/expansion-completion.md | 107 ++++ .../references/fix-final-scene.md | 59 ++ .../story-ending/references/natural-stop.md | 26 + .../references/pitfalls-and-boundaries.md | 107 ++++ .../catalog/pi/skills/story-planning/SKILL.md | 93 +++ .../story-planning/references/_coverage.md | 10 + .../story-planning/references/beat-sheet.md | 181 ++++++ .../story-planning/references/draft-flow.md | 233 ++++++++ .../references/plan-vs-pantsing.md | 162 +++++ .../references/planning-workflow-checklist.md | 96 +++ .../pi/skills/story-structure/SKILL.md | 81 +++ .../story-structure/references/_coverage.md | 17 + .../references/first-plot-point.md | 110 ++++ .../story-structure/references/four-boxes.md | 111 ++++ .../references/inciting-incident.md | 130 ++++ .../references/inciting-vs-fpp.md | 109 ++++ .../references/length-system.md | 130 ++++ .../story-structure/references/midpoint.md | 104 ++++ .../story-structure/references/opening.md | 188 ++++++ .../references/part2-wanderer.md | 110 ++++ .../story-structure/references/setup.md | 112 ++++ .../references/six-milestones.md | 126 ++++ .../references/structure-checklists.md | 162 +++++ .../pi/skills/theme-and-stance/SKILL.md | 96 +++ .../theme-and-stance/references/_coverage.md | 15 + .../references/boundaries-and-pitfalls.md | 110 ++++ .../references/humor-as-stance.md | 125 ++++ .../theme-and-stance/references/mercy-ruth.md | 183 ++++++ .../references/stance-by-logic.md | 161 +++++ .../references/theme-demonstration.md | 130 ++++ .../references/theme-stance-checklist.md | 114 ++++ framework/primitives/__init__.py | 5 + framework/primitives/artifacts.py | 108 ++++ framework/primitives/execution.py | 124 ++++ .../schemas/framework_event.schema.json | 21 + .../framework_execution_request.schema.json | 20 + .../framework_execution_result.schema.json | 17 + harness/skills_index.py | 200 ------- muse/_skills_index.md | 95 +++ .../db}/ddl/100-example规划与冻结.sql | 0 .../authority/db}/ddl/101-example-raw.sql | 0 .../db}/ddl/102-example智能体技能登记.sql | 0 .../db}/ddl/103-example评测隔离引擎强制.sql | 0 .../db}/ddl/104-example-ai-flavor-cases.sql | 0 .../db}/ddl/105-example候选语义审查.sql | 0 .../authority/db}/ddl/106-example事实增量.sql | 0 .../authority/db}/ddl/107-example投影登记.sql | 0 .../authority/db}/ddl/108-example经验升格.sql | 0 .../db}/ddl/109-example候选状态CAS.sql | 0 .../db}/ddl/110-example-voice-baseline.sql | 0 .../111-example-humanization规则与样例.sql | 0 .../ddl/112-example角色模型策略与登记路径.sql | 2 +- .../db}/ddl/113-example代理事件账本.sql | 0 .../114-example冻结幂等键-清单加上下文对.sql | 0 .../db}/ddl/90-主仓ALTER摘录-V9V10V14V30.sql | 0 .../authority/db}/ddl/91-example实验私货.sql | 0 .../authority/db}/ddl/92-example清洗日志.sql | 0 .../authority/db}/ddl/93-example大纲聚合.sql | 0 .../db}/ddl/94-example作品面升格.sql | 0 .../authority/db}/ddl/95-example额度账本.sql | 0 .../db}/ddl/96-example参考作品授权快照.sql | 0 .../db}/ddl/97-example模型调用明细.sql | 0 .../ddl/98-example运行与回执与质量结果.sql | 0 .../db}/ddl/99-example候选与决策.sql | 0 .../db}/ddl/V1__init_content_schema.sql | 0 ...ix_content_softdelete_order_uk_partial.sql | 0 .../db}/ddl/V3__init_meta_schema.sql | 0 .../db}/ddl/V5__init_knowledge_schema.sql | 0 {db => muse/authority/db}/表映射.md | 4 +- {db => muse/authority/db}/连接信息.md | 0 .../evidence}/skills/access-database/SKILL.md | 27 +- .../skills/access-database/scripts/db.py | 0 .../access-database/scripts/seed_schemas.py | 0 .../scripts/sync_agent_registry.py | 24 +- .../skills/record-run-evidence/SKILL.md | 0 .../scripts/agent_trace.py | 0 .../record-run-evidence/scripts/file_cas.py | 0 .../scripts/invariant_checks.py | 2 +- .../scripts/lesson_registry.py | 0 .../scripts/persist_llm_call.py | 0 .../scripts/persist_raw.py | 0 .../record-run-evidence/scripts/raw_vault.py | 0 .../scripts/record_failed_run.py | 0 .../scripts/repair_receipt_evidence.py | 0 .../scripts/run_registry.py | 0 .../authority/studio/read}/fixtures/README.md | 0 .../backfill-inventory-2026-08-13.json | 0 .../fixtures/revalidation-2026-08-14.json | 0 .../authority/studio/read}/server.py | 6 +- .../studio/read}/test_server_display.py | 0 .../write/decision}/decision_channel.py | 0 .../studio/write/lesson}/lesson_confirm.py | 2 +- .../authority/tools/read}/read_tools.py | 0 .../extract-chapter-knowledge/SKILL.md | 0 .../scripts/dispatch_extraction_bridge.py | 15 +- .../scripts/extract_knowledge.py | 14 +- .../scripts/extract_via_dispatch.py | 2 +- .../ingest}/backup-work-extraction/SKILL.md | 6 +- .../scripts/backup_upgrade_work.py | 31 +- .../skills/ingest}/clean-book-text/SKILL.md | 15 +- .../clean-book-text/scripts/clean_apply.py | 0 .../clean-book-text/scripts/clean_batch.py | 0 .../clean-book-text/scripts/clean_detect.py | 0 .../clean-book-text/scripts/clean_prep.py | 0 .../clean-book-text/scripts/clean_sweep.py | 0 .../skills/ingest}/deconstruct-book/SKILL.md | 14 +- .../deconstruct-book/scripts/parse_ingest.py | 0 .../deconstruct-book/scripts/parse_llm.py | 0 .../deconstruct-book/scripts/parse_outline.py | 0 .../deconstruct-book/scripts/parse_salvage.py | 0 .../ingest}/extract-work-knowledge/SKILL.md | 6 +- .../extract-work-knowledge/scripts/upgrade.py | 15 +- .../scripts/upgrade_work_lock.py | 0 .../skills/ingest}/import-book/SKILL.md | 9 +- .../import-book/scripts/import_novel.py | 0 .../ingest}/inspect-parse-health/SKILL.md | 8 +- .../scripts/parse_export.py | 0 .../scripts/parse_health.py | 0 .../ingest}/repair-work-extraction/SKILL.md | 2 +- .../scripts/maintenance.py | 0 .../scripts/migrate_upgrade_windows.py | 0 .../scripts/parse_rewash.py | 0 .../ingest}/reset-work-extraction/SKILL.md | 4 +- .../scripts/reset_upgrade_work.py | 21 +- .../review}/review-knowledge-cards/SKILL.md | 5 +- .../golden/scores-cal002-m3旧尺子对照.json | 0 .../golden/scores-cal002.json | 0 .../review-knowledge-cards/golden/scores.json | 0 .../golden/金标准-主编-2026-07-13.md | 0 .../golden/金标准-番茄作家-2026-07-13.md | 0 .../golden/金标准-起点作家-2026-07-13.md | 0 .../scripts/review_cards.py | 0 .../confirm-knowledge-draft/SKILL.md | 7 +- .../scripts/confirm_knowledge.py | 0 .../content/entity/sources}/README.md | 0 .../entity/sources}/参考书/封神演义/档案.md | 0 .../sources}/参考书/封神演义/第12回.txt | 0 .../sources}/参考书/封神演义/第13回.txt | 0 .../sources}/参考书/封神演义/第14回.txt | 0 {meta => muse/content/meta}/schemas/README.md | 2 +- .../content/meta}/schemas/chapter.yaml | 0 .../content/meta}/schemas/character.yaml | 0 .../meta}/schemas/character_relation.yaml | 0 .../content/meta}/schemas/combat.yaml | 0 .../content/meta}/schemas/craft.yaml | 0 .../content/meta}/schemas/emotion.yaml | 0 .../content/meta}/schemas/event.yaml | 0 .../content/meta}/schemas/faction.yaml | 0 .../content/meta}/schemas/fine_outline.yaml | 0 .../meta}/schemas/generation_context.yaml | 2 +- {meta => muse/content/meta}/schemas/item.yaml | 0 .../content/meta}/schemas/location.yaml | 0 .../meta}/schemas/narrative_state.yaml | 0 .../content/meta}/schemas/novel_work.yaml | 0 .../content/meta}/schemas/outline.yaml | 0 .../content/meta}/schemas/pacing.yaml | 0 .../content/meta}/schemas/power_system.yaml | 0 .../content/meta}/schemas/reference_work.yaml | 0 .../content/meta}/schemas/scene.yaml | 0 .../content/meta}/schemas/scene_pattern.yaml | 0 .../content/meta}/schemas/style.yaml | 0 .../content/meta}/schemas/trope.yaml | 0 .../content/meta}/schemas/work_core.yaml | 0 .../content/meta}/schemas/world.yaml | 0 .../skills/generate}/expand-scene/SKILL.md | 0 .../skills/generate}/polish-prose/SKILL.md | 0 .../generate}/rewrite-selection/SKILL.md | 2 +- .../scripts/assert_expected_revision.py | 0 .../generate}/write-next-chapter/SKILL.md | 0 .../scripts/candidate_cas.py | 2 +- .../scripts/dispatch_writer_bridge.py | 14 +- .../scripts/persist_writer_run.py | 9 +- .../scripts/produce_next_chapter.py | 38 +- .../scripts/production_evidence_reassemble.py | 0 .../scripts/run_contrast_writer.py | 2 +- .../write-next-chapter/scripts/run_writer.py | 16 +- .../scripts/run_writer_pipeline.py | 10 +- .../scripts/two_phase_writer.py | 14 +- .../sovereignty}/decide-candidate/SKILL.md | 6 +- .../scripts/acceptance_state.py | 0 .../scripts/check_writer_acceptance.py | 0 .../decide-candidate/scripts/fact_delta.py | 8 +- .../scripts/projection_registry.py | 0 .../scripts/write_canonical.py | 7 +- .../context}/skills/assemble-context/SKILL.md | 2 +- .../scripts/assemble_writer_context.py | 0 .../scripts/persist_context_freeze.py | 0 .../scripts/retrieve_writer_sources.py | 0 .../scripts/writer_contract.py | 0 .../context}/skills/embed-knowledge/SKILL.md | 13 +- .../embed-knowledge/scripts/embed_drafts.py | 0 .../context}/skills/freeze-context/SKILL.md | 0 .../freeze-context/scripts/audit_leakage.py | 0 .../freeze-context/scripts/build_snapshot.py | 0 .../freeze-context/scripts/check_snapshot.py | 0 .../scripts/load_reference_work.py | 0 .../context}/skills/search-knowledge/SKILL.md | 7 +- .../skills/search-knowledge/scripts/search.py | 0 .../skills/dispatch-agent-task/SKILL.md | 20 +- .../scripts/dispatch_agent_task.py | 57 +- .../scripts/role_policy.py | 23 + .../dispatch-agent-task/scripts/role_task.py | 42 +- .../lifecycle/flow}/chains/README.md | 4 +- .../book}/design-story-foundation/SKILL.md | 4 +- .../references/candidate-contract.md | 0 .../chapter-content-spec-chapters-1-5.md | 0 .../chapter-content-spec-chapters-6-9.md | 0 .../references/chapter-content-spec.md | 0 .../scripts/assert_selection_handoff.py | 0 .../scripts/candidate_tree.json | 0 .../scripts/validate_candidates.py | 0 .../book}/merge-story-candidates/SKILL.md | 6 +- .../references/serial-merge-contract.md | 0 .../scripts/serial_merge.py | 0 .../flow/skills/book}/plan-story/SKILL.md | 2 +- .../plan-story/scripts/persist_planning.py | 8 +- .../scripts/record_planning_execution.py | 8 +- .../scripts/repair_deterministic_receipt.py | 0 .../plan-story/scripts/select_patterns.py | 9 +- .../skills/chapter}/plan-chapter/SKILL.md | 4 +- .../lifecycle/quality/harness}/README.md | 8 +- .../quality/harness}/evals/skill_eval.py | 0 .../skills/diagnose-ai-flavor/run_eval.py | 16 +- .../skills/diagnose-ai-flavor/scenarios.json | 0 .../quality/harness}/evals/test_skill_eval.py | 15 +- .../quality/harness}/manifests/skills.json | 134 ++--- .../harness}/manifests/test-inventory.json | 125 +++- .../quality/harness/project_paths.py | 17 + .../quality/harness}/run_selected.py | 73 ++- .../quality/harness}/skill_harness.py | 192 +++--- .../lifecycle/quality/harness/skills_index.py | 282 +++++++++ .../harness}/specs/skill-quality-rubric.md | 18 +- .../quality/harness}/specs/skill-testing.md | 2 +- .../quality/harness}/test_run_selected.py | 39 +- .../quality/harness}/test_skill_harness.py | 48 +- .../lifecycle/quality/humanization}/README.md | 12 +- .../humanization}/cards/backfill-example.yaml | 0 .../quality/humanization}/config.yaml | 0 .../contracts/audit_report.schema.json | 0 .../contracts/case_card.schema.json | 0 .../contracts/finding.schema.json | 0 .../humanization}/contracts/patch.schema.json | 0 .../contracts/prevention.schema.json | 0 .../humanization}/contracts/rule.schema.json | 0 .../contracts/sample.schema.json | 0 .../contracts/voice_baseline.schema.json | 0 .../quality/humanization}/eval/run_eval.py | 0 .../quality/humanization}/pyproject.toml | 0 ...project-humanization-rule-catalog.zh-CN.md | 4 +- .../research/20-project-skill-coverage.yaml | 52 +- .../humanization}/rules/density/d001.yaml | 0 .../humanization}/rules/density/d002.yaml | 0 .../humanization}/rules/density/d003.yaml | 0 .../humanization}/rules/density/d004.yaml | 0 .../humanization}/rules/density/d005.yaml | 0 .../humanization}/rules/density/d006.yaml | 0 .../humanization}/rules/lexical/l001.yaml | 0 .../humanization}/rules/lexical/l002.yaml | 0 .../humanization}/rules/lexical/l003.yaml | 0 .../humanization}/rules/lexical/l004.yaml | 0 .../humanization}/rules/lexical/l005.yaml | 0 .../humanization}/rules/lexical/l006.yaml | 0 .../humanization}/rules/mechanical/m001.yaml | 0 .../humanization}/rules/mechanical/m002.yaml | 0 .../humanization}/rules/mechanical/m003.yaml | 0 .../humanization}/rules/mechanical/m004.yaml | 0 .../humanization}/rules/semantic/sem001.yaml | 0 .../humanization}/rules/semantic/sem002.yaml | 0 .../humanization}/rules/semantic/sem003.yaml | 0 .../humanization}/rules/structural/s001.yaml | 0 .../humanization}/rules/structural/s002.yaml | 0 .../humanization}/rules/structural/s003.yaml | 0 .../humanization}/rules/structural/s004.yaml | 0 .../humanization}/rules/structural/s005.yaml | 0 .../humanization}/rules/structural/s006.yaml | 0 .../humanization}/rules/structural/s007.yaml | 0 .../humanization}/samples/boundary.yaml | 0 .../humanization}/samples/regression.yaml | 0 .../quality/humanization}/samples/sf.yaml | 0 .../quality/humanization}/samples/snf.yaml | 0 .../skills/capture-ai-flavor-cases/SKILL.md | 16 +- .../references/case-card-contract.md | 0 .../references/fixtures/README.md | 4 +- .../fixtures/backfill-hash-only.yaml | 0 .../fixtures/canonical-samples.yaml | 0 .../references/fixtures/rule-candidates.yaml | 0 .../scripts/capture_cases.py | 0 .../scripts/persist_cases.py | 0 .../skills/diagnose-ai-flavor/SKILL.md | 0 .../scripts/diagnose_ai_flavor.py | 0 .../skills/establish-voice-baseline/SKILL.md | 0 .../scripts/establish_voice_baseline.py | 0 .../skills/prevent-ai-flavor/SKILL.md | 0 .../scripts/prevent_ai_flavor.py | 0 .../skills/promote-ai-flavor-rule/SKILL.md | 16 +- .../scripts/mine_ai_flavor.py | 0 .../skills/revise-ai-flavor/SKILL.md | 0 .../scripts/revise_ai_flavor.py | 0 .../humanization}/src/deai/__init__.py | 0 .../humanization}/src/deai/baseline.py | 0 .../quality/humanization}/src/deai/cards.py | 0 .../humanization}/src/deai/carriers.py | 0 .../humanization}/src/deai/diagnose.py | 0 .../humanization}/src/deai/evaluation.py | 0 .../quality/humanization}/src/deai/gates.py | 0 .../quality/humanization}/src/deai/load.py | 0 .../quality/humanization}/src/deai/load_db.py | 0 .../humanization}/src/deai/pairwise.py | 0 .../quality/humanization}/src/deai/patch.py | 0 .../humanization}/src/deai/pipeline.py | 0 .../quality/humanization}/src/deai/report.py | 0 .../quality/humanization}/src/deai/schemas.py | 0 .../quality/humanization}/tests/__init__.py | 0 .../humanization}/tests/test_contracts.py | 0 .../tests/test_framework_coverage.py | 9 +- .../tests/test_humanization_v2.py | 4 +- .../humanization}/tests/test_load_db.py | 0 .../tests/test_load_db_pg_smoke.py | 0 .../humanization}/tests/test_seed_rules_db.py | 0 .../humanization}/tools/seed_rules_db.py | 0 .../judge}/optimize-content-quality/SKILL.md | 3 +- .../judge}/score-content-quality/SKILL.md | 0 .../scripts/dispatch_judge_bridge.py | 15 +- .../scripts/fine_outline_rubric.py | 0 .../scripts/judge_via_dispatch.py | 4 +- .../scripts/run_writer_blind_judge.py | 0 .../scripts/writer_rubric.py | 0 .../adjudicate-quality-gate/SKILL.md | 0 .../scripts/gate_input_builder.py | 7 +- .../scripts/writer_gate.py | 0 .../replay}/evaluate-frozen-replay/SKILL.md | 2 +- .../scripts/fine_outline_detector.py | 0 .../scripts/run_replay.py | 20 +- .../scripts/write_report.py | 0 .../load-replay-reference-work/SKILL.md | 0 .../scripts/load_writer_reference_work.py | 16 +- .../replay}/replay-writer-gate/SKILL.md | 4 +- ...r-gate-a-deep-space-card-selectors-v1.json | 0 .../configs/writer-gate-a-deep-space-v1.json | 0 .../scripts/run_writer_replay/__init__.py | 0 .../scripts/run_writer_replay/__main__.py | 0 .../scripts/run_writer_replay/_common.py | 22 +- .../run_writer_replay/authorization.py | 2 +- .../scripts/run_writer_replay/blind.py | 0 .../scripts/run_writer_replay/budget.py | 0 .../scripts/run_writer_replay/execute.py | 0 .../scripts/run_writer_replay/sample.py | 0 .../scripts/writer_eval_preregister.py | 0 .../check-content-consistency/SKILL.md | 0 .../scripts/check_writer_candidate.py | 0 .../scripts/run_writer_semantic_detector.py | 0 {muse-db => muse/platform/db}/pyproject.toml | 0 .../platform/db}/src/muse_db/__init__.py | 0 .../platform/embed}/pyproject.toml | 0 .../platform/embed}/src/muse_embed.py | 0 .../platform/llm}/pyproject.toml | 0 .../llm}/skills/call-content-model/SKILL.md | 5 +- .../skills/call-content-model/scripts/llm.py | 0 .../llm}/skills/execute-role-task/SKILL.md | 0 .../skills/refresh-runtime-probe/SKILL.md | 4 +- .../scripts/refresh_runtime_probe.py | 14 +- .../platform/llm}/src/muse_llm.py | 0 .../platform/llm}/src/muse_role.py | 0 .../platform/llm}/src/muse_role_contract.py | 2 +- .../docs/architecture => muse/sot}/_index.md | 0 .../sot}/domains/01-作品领域.md | 2 +- .../sot}/domains/02-实体领域.md | 30 +- .../sot}/domains/03-范式领域.md | 12 +- .../sot}/domains/04-上下文领域.md | 6 +- .../sot}/domains/05-创作流程领域.md | 32 +- .../sot}/domains/06-质量与复利领域.md | 8 +- .../sot}/domains/07-Agent与Skill领域.md | 12 +- .../sot}/domains/08-数据权威与可视化领域.md | 12 +- .../sot}/domains/_index.md | 16 +- .../sot}/创作周期与Skill导读.md | 292 ++++----- .../sot}/可视化模块合同.md | 26 +- .../architecture => muse/sot}/角色合同.md | 0 .../architecture => muse/sot}/边界合同.md | 1 + requirements.txt | 8 +- tests/architecture/test_dsh_adapter.py | 230 +++++++ .../test_framework_port_purity.py | 43 ++ tests/architecture/test_framework_protocol.py | 122 ++++ tests/architecture/test_import_boundaries.py | 82 ++- tests/architecture/test_markdown_links.py | 48 ++ tests/architecture/test_skill_projections.py | 77 +++ tests/architecture/test_skills_index.py | 10 +- .../test_authorization_snapshot_ddl.py | 2 +- .../skills/access-database/test_db_params.py | 2 +- .../access-database/test_skill_catalog.py | 2 +- .../test_gate_input_builder.py | 4 +- .../test_writer_gate.py | 8 +- .../test_assemble_writer_context.py | 2 +- .../test_fine_outline_reader.py | 2 +- .../test_fine_outline_unification.py | 2 +- .../test_freeze_lesson_offline.py | 4 +- .../test_pattern_binding_reader.py | 2 +- .../test_persist_freeze_db.py | 2 +- .../test_retrieve_writer_sources.py | 6 +- .../assemble-context/test_style_loader.py | 2 +- .../assemble-context/test_writer_contract.py | 2 +- .../test_backup_upgrade_work_offline.py | 2 +- .../test_call_persistence.py | 2 +- .../test_capture_cases.py | 2 +- .../test_capture_lesson_offline.py | 4 +- .../test_build_semantic_input.py | 6 +- .../test_check_writer_candidate.py | 6 +- .../test_run_writer_semantic_detector.py | 2 +- .../test_clean_detect_offline.py | 2 +- .../test_confirm_knowledge_offline.py | 2 +- .../test_decision_lesson_offline.py | 4 +- .../decide-candidate/test_fact_delta.py | 4 +- .../decide-candidate/test_fact_delta_db.py | 2 +- .../test_next_steps_offline.py | 4 +- .../decide-candidate/test_projection_db.py | 2 +- .../test_write_canonical_db.py | 2 +- .../test_writer_acceptance.py | 6 +- .../test_deconstruct_lesson_offline.py | 4 +- .../test_parse_llm_offline.py | 2 +- .../test_parse_outline_offline.py | 2 +- .../test_assert_selection_handoff.py | 2 +- .../test_validate_candidates.py | 2 +- .../test_diagnose_ai_flavor.py | 2 +- .../test_dispatch_agent_task.py | 33 +- .../dispatch-agent-task/test_read_tools.py | 10 +- .../test_embed_drafts_offline.py | 2 +- .../test_establish_voice_baseline.py | 2 +- .../test_fine_outline_detector.py | 7 +- .../evaluate-frozen-replay/test_run_replay.py | 4 +- .../test_chapter_extract_lesson_offline.py | 4 +- .../test_dispatch_extraction_bridge.py | 2 +- .../test_extract_knowledge_offline.py | 2 +- .../test_parse_upgrade_offline.py | 2 +- .../test_parse_upgrade_pg_smoke.py | 2 +- .../test_presence_dedupe.py | 2 +- .../test_upgrade_lesson_offline.py | 4 +- .../test_upgrade_work_lock_offline.py | 2 +- .../freeze-context/test_audit_leakage.py | 2 +- .../freeze-context/test_build_snapshot.py | 2 +- .../freeze-context/test_check_snapshot.py | 2 +- .../test_load_reference_work.py | 2 +- .../test_load_writer_reference_work.py | 14 +- .../test_pattern_reference_injection.py | 14 +- .../test_serial_merge.py | 2 +- tests/skills/plan-chapter/test_contract.py | 6 +- .../skills/plan-story/test_field_coverage.py | 2 +- .../test_planning_lesson_offline.py | 4 +- .../test_record_planning_execution.py | 2 +- .../test_repair_deterministic_receipt.py | 2 +- .../test_select_patterns_offline.py | 2 +- .../test_prevent_ai_flavor.py | 2 +- .../test_prevention_lesson_offline.py | 4 +- .../test_propose_rule.py | 4 +- .../record-run-evidence/test_agent_trace.py | 2 +- .../record-run-evidence/test_file_cas.py | 2 +- .../test_lesson_registry_db.py | 2 +- .../record-run-evidence/test_persist_raw.py | 2 +- .../record-run-evidence/test_raw_vault.py | 2 +- .../test_record_failed_run.py | 2 +- .../test_repair_receipt_evidence.py | 2 +- .../record-run-evidence/test_run_registry.py | 2 +- .../test_refresh_runtime_probe.py | 6 +- .../test_run_writer_replay.py | 10 +- .../test_writer_eval_preregister.py | 2 +- .../test_reset_upgrade_work_offline.py | 6 +- .../test_calibrate_stamp.py | 2 +- .../test_review_lesson_offline.py | 4 +- .../revise-ai-flavor/test_revise_ai_flavor.py | 4 +- .../test_revision_lesson_offline.py | 4 +- .../test_assert_expected_revision.py | 2 +- .../test_dispatch_judge_bridge.py | 2 +- .../score-content-quality/test_rubric.py | 2 +- .../test_run_writer_blind_judge.py | 2 +- .../test_score_lesson_offline.py | 4 +- .../test_writer_rubric.py | 2 +- tests/skills/search-knowledge/test_search.py | 2 +- .../write-next-chapter/test_candidate_cas.py | 6 +- .../test_candidate_cas_db.py | 2 +- .../test_dispatch_writer_bridge.py | 2 +- .../test_gate_anchor_projection.py | 2 +- .../test_persist_writer_run.py | 2 +- .../test_production_evidence_reassemble.py | 4 +- .../write-next-chapter/test_run_writer.py | 4 +- .../test_run_writer_pipeline.py | 6 +- .../test_semantic_verdict.py | 2 +- .../test_two_phase_writer.py | 2 +- .../test_writer_lesson_offline.py | 4 +- 902 files changed, 34545 insertions(+), 1385 deletions(-) rename .agent/skills/{ => diagnosis}/novel-diagnosis/SKILL.md (100%) rename .agent/skills/{ => diagnosis}/novel-diagnosis/references/_coverage.md (100%) rename .agent/skills/{ => diagnosis}/novel-diagnosis/references/diagnosis-workflow.md (100%) rename .agent/skills/{ => diagnosis}/novel-diagnosis/references/dimension-frameworks.md (100%) rename .agent/skills/{ => diagnosis}/novel-diagnosis/references/fantasy-prophecy.md (100%) rename .agent/skills/{ => diagnosis}/novel-diagnosis/references/pattern-rhythm.md (100%) rename .agent/skills/{ => diagnosis}/novel-diagnosis/references/plot-character.md (100%) rename .agent/skills/{ => diagnosis}/novel-diagnosis/references/quack-scholar-scan.md (100%) rename .agent/skills/{ => diagnosis}/novel-diagnosis/references/quack-scholar.md (100%) rename .agent/skills/{ => diagnosis}/novel-diagnosis/references/round-table.md (100%) rename .agent/skills/{ => diagnosis}/novel-diagnosis/references/story-plot.md (100%) rename .agent/skills/{ => diagnosis}/novel-diagnosis/references/time-value.md (100%) rename .agent/skills/{ => planning}/concept-design/SKILL.md (100%) rename .agent/skills/{ => planning}/concept-design/references/_coverage.md (100%) rename .agent/skills/{ => planning}/concept-design/references/concept-worksheet.md (100%) rename .agent/skills/{ => planning}/concept-design/references/delivery-strategy.md (100%) rename .agent/skills/{ => planning}/concept-design/references/four-questions.md (100%) rename .agent/skills/{ => planning}/concept-design/references/originality.md (100%) rename .agent/skills/{ => planning}/concept-design/references/story-engine.md (100%) rename .agent/skills/{ => planning}/concept-design/references/what-if.md (100%) rename .agent/skills/{ => planning}/foreshadow-payoff/SKILL.md (100%) rename .agent/skills/{ => planning}/foreshadow-payoff/references/_coverage.md (100%) rename .agent/skills/{ => planning}/foreshadow-payoff/references/boundaries-and-pitfalls.md (100%) rename .agent/skills/{ => planning}/foreshadow-payoff/references/detail-driven-climax.md (100%) rename .agent/skills/{ => planning}/foreshadow-payoff/references/foreshadow-checklist.md (100%) rename .agent/skills/{ => planning}/foreshadow-payoff/references/foreshadow-ledger-template.md (100%) rename .agent/skills/{ => planning}/foreshadow-payoff/references/natural-staircase.md (100%) rename .agent/skills/{ => planning}/foreshadow-payoff/references/register-and-repay.md (100%) rename .agent/skills/{ => planning}/narrative-momentum/SKILL.md (100%) rename .agent/skills/{ => planning}/narrative-momentum/references/_coverage.md (100%) rename .agent/skills/{ => planning}/narrative-momentum/references/alternation-and-distinctions.md (100%) rename .agent/skills/{ => planning}/narrative-momentum/references/breakpoint-hooks.md (100%) rename .agent/skills/{ => planning}/narrative-momentum/references/build-momentum.md (100%) rename .agent/skills/{ => planning}/narrative-momentum/references/midway-rewards.md (100%) rename .agent/skills/{ => planning}/narrative-momentum/references/momentum-checklist.md (100%) rename .agent/skills/{ => planning}/story-ending/SKILL.md (100%) rename .agent/skills/{ => planning}/story-ending/references/_coverage.md (100%) rename .agent/skills/{ => planning}/story-ending/references/ending-strategies.md (100%) rename .agent/skills/{ => planning}/story-ending/references/execution-chain.md (100%) rename .agent/skills/{ => planning}/story-ending/references/expansion-completion.md (100%) rename .agent/skills/{ => planning}/story-ending/references/fix-final-scene.md (100%) rename .agent/skills/{ => planning}/story-ending/references/natural-stop.md (100%) rename .agent/skills/{ => planning}/story-ending/references/pitfalls-and-boundaries.md (100%) rename .agent/skills/{ => planning}/story-planning/SKILL.md (100%) rename .agent/skills/{ => planning}/story-planning/references/_coverage.md (100%) rename .agent/skills/{ => planning}/story-planning/references/beat-sheet.md (100%) rename .agent/skills/{ => planning}/story-planning/references/draft-flow.md (100%) rename .agent/skills/{ => planning}/story-planning/references/plan-vs-pantsing.md (100%) rename .agent/skills/{ => planning}/story-planning/references/planning-workflow-checklist.md (100%) rename .agent/skills/{ => planning}/story-structure/SKILL.md (100%) rename .agent/skills/{ => planning}/story-structure/references/_coverage.md (100%) rename .agent/skills/{ => planning}/story-structure/references/first-plot-point.md (100%) rename .agent/skills/{ => planning}/story-structure/references/four-boxes.md (100%) rename .agent/skills/{ => planning}/story-structure/references/inciting-incident.md (100%) rename .agent/skills/{ => planning}/story-structure/references/inciting-vs-fpp.md (100%) rename .agent/skills/{ => planning}/story-structure/references/length-system.md (100%) rename .agent/skills/{ => planning}/story-structure/references/midpoint.md (100%) rename .agent/skills/{ => planning}/story-structure/references/opening.md (100%) rename .agent/skills/{ => planning}/story-structure/references/part2-wanderer.md (100%) rename .agent/skills/{ => planning}/story-structure/references/setup.md (100%) rename .agent/skills/{ => planning}/story-structure/references/six-milestones.md (100%) rename .agent/skills/{ => planning}/story-structure/references/structure-checklists.md (100%) rename .agent/skills/{ => writing}/character-design/SKILL.md (100%) rename .agent/skills/{ => writing}/character-design/references/_coverage.md (100%) rename .agent/skills/{ => writing}/character-design/references/archetype-reversal.md (100%) rename .agent/skills/{ => writing}/character-design/references/character-diagnosis.md (100%) rename .agent/skills/{ => writing}/character-design/references/character-worksheet.md (100%) rename .agent/skills/{ => writing}/character-design/references/flat-vs-round.md (100%) create mode 100644 .agent/skills/writing/character-design/references/inner-demon.md rename .agent/skills/{ => writing}/character-design/references/seven-variables.md (100%) rename .agent/skills/{ => writing}/character-design/references/three-dimensions.md (100%) rename .agent/skills/{ => writing}/character-presentation/SKILL.md (100%) rename .agent/skills/{ => writing}/character-presentation/references/_coverage.md (100%) rename .agent/skills/{ => writing}/character-presentation/references/abnormal-moment.md (100%) rename .agent/skills/{ => writing}/character-presentation/references/character-collision.md (100%) rename .agent/skills/{ => writing}/character-presentation/references/detail-mosaic.md (100%) rename .agent/skills/{ => writing}/character-presentation/references/presentation-checklist.md (100%) rename .agent/skills/{ => writing}/character-presentation/references/relationship-web.md (100%) rename .agent/skills/{ => writing}/character-presentation/references/visible-private-life.md (100%) rename .agent/skills/{ => writing}/character-presentation/references/voice-discovery-process.md (100%) rename .agent/skills/{ => writing}/dialogue-craft/SKILL.md (100%) rename .agent/skills/{ => writing}/dialogue-craft/references/_coverage.md (100%) rename .agent/skills/{ => writing}/dialogue-craft/references/boundaries-and-pitfalls.md (100%) rename .agent/skills/{ => writing}/dialogue-craft/references/character-voice.md (100%) rename .agent/skills/{ => writing}/dialogue-craft/references/dialogue-does-things.md (100%) rename .agent/skills/{ => writing}/dialogue-craft/references/dialogue-revision-checklist.md (100%) rename .agent/skills/{ => writing}/dialogue-craft/references/execution-flow.md (100%) rename .agent/skills/{ => writing}/dialogue-craft/references/real-speech-texture.md (100%) rename .agent/skills/{ => writing}/dialogue-craft/references/rhythm-and-density.md (100%) rename .agent/skills/{ => writing}/dialogue-craft/references/tags-and-attribution.md (100%) rename .agent/skills/{ => writing}/dialogue-craft/references/when-to-use-dialogue.md (100%) rename .agent/skills/{ => writing}/narration-pov/SKILL.md (100%) rename .agent/skills/{ => writing}/narration-pov/references/_coverage.md (100%) rename .agent/skills/{ => writing}/narration-pov/references/broken-line.md (100%) rename .agent/skills/{ => writing}/narration-pov/references/certainty-uncertainty.md (100%) rename .agent/skills/{ => writing}/narration-pov/references/narration-pov-checklist.md (100%) rename .agent/skills/{ => writing}/narration-pov/references/outsider-entry.md (100%) rename .agent/skills/{ => writing}/narration-pov/references/pov-camera.md (100%) rename .agent/skills/{ => writing}/narration-pov/references/pov-execution.md (100%) rename .agent/skills/{ => writing}/narration-pov/references/skeptical-stance.md (100%) rename .agent/skills/{ => writing}/prose-craft/SKILL.md (100%) rename .agent/skills/{ => writing}/prose-craft/references/_coverage.md (100%) rename .agent/skills/{ => writing}/prose-craft/references/abstraction-ladder.md (100%) rename .agent/skills/{ => writing}/prose-craft/references/base-temperature.md (100%) rename .agent/skills/{ => writing}/prose-craft/references/lyric-restraint.md (100%) rename .agent/skills/{ => writing}/prose-craft/references/pattern-and-break.md (100%) create mode 100644 .agent/skills/writing/prose-craft/references/plain-description.md rename .agent/skills/{ => writing}/prose-craft/references/revision-checklist.md (100%) rename .agent/skills/{ => writing}/prose-craft/references/rhetoric-density.md (100%) rename .agent/skills/{ => writing}/prose-craft/references/sentence-rhythm.md (100%) rename .agent/skills/{ => writing}/prose-craft/references/voice-equalizer.md (100%) rename .agent/skills/{ => writing}/scene-craft/SKILL.md (100%) rename .agent/skills/{ => writing}/scene-craft/references/_coverage.md (100%) rename .agent/skills/{ => writing}/scene-craft/references/boundaries-and-pitfalls.md (100%) rename .agent/skills/{ => writing}/scene-craft/references/scene-camera.md (100%) rename .agent/skills/{ => writing}/scene-craft/references/scene-detail.md (100%) rename .agent/skills/{ => writing}/scene-craft/references/scene-entry-exit.md (100%) rename .agent/skills/{ => writing}/scene-craft/references/scene-ledger-template.md (100%) rename .agent/skills/{ => writing}/scene-craft/references/scene-mission.md (100%) rename .agent/skills/{ => writing}/scene-craft/references/scene-mystification.md (100%) rename .agent/skills/{ => writing}/scene-craft/references/scene-revision-checklist.md (100%) rename .agent/skills/{ => writing}/scene-craft/references/scene-rhythm.md (100%) rename .agent/skills/{ => writing}/show-and-omission/SKILL.md (100%) rename .agent/skills/{ => writing}/show-and-omission/references/_coverage.md (100%) rename .agent/skills/{ => writing}/show-and-omission/references/anti-logic.md (100%) rename .agent/skills/{ => writing}/show-and-omission/references/extreme-emotion-body.md (100%) rename .agent/skills/{ => writing}/show-and-omission/references/iceberg.md (100%) rename .agent/skills/{ => writing}/show-and-omission/references/imagination-anchor.md (100%) rename .agent/skills/{ => writing}/show-and-omission/references/pov-knowledge-boundary.md (100%) rename .agent/skills/{ => writing}/show-and-omission/references/reader-gap-diagnosis.md (100%) rename .agent/skills/{ => writing}/show-and-omission/references/show-omission-checklist.md (100%) rename .agent/skills/{ => writing}/show-and-omission/references/show-vs-tell.md (100%) rename .agent/skills/{ => writing}/theme-and-stance/SKILL.md (100%) rename .agent/skills/{ => writing}/theme-and-stance/references/_coverage.md (100%) rename .agent/skills/{ => writing}/theme-and-stance/references/boundaries-and-pitfalls.md (100%) rename .agent/skills/{ => writing}/theme-and-stance/references/humor-as-stance.md (100%) rename .agent/skills/{ => writing}/theme-and-stance/references/mercy-ruth.md (100%) rename .agent/skills/{ => writing}/theme-and-stance/references/stance-by-logic.md (100%) rename .agent/skills/{ => writing}/theme-and-stance/references/theme-demonstration.md (100%) rename .agent/skills/{ => writing}/theme-and-stance/references/theme-stance-checklist.md (100%) create mode 100644 docs/plans/2026-08-23-目录分层改造.md create mode 100644 docs/plans/2026-08-24-双底座适配接缝.md create mode 100644 docs/research/2026-08-24-dsh-local-runtime-baseline.md create mode 100644 framework/README.md create mode 100644 framework/__init__.py create mode 100644 framework/adapters/__init__.py create mode 100644 framework/adapters/dsh/README.md create mode 100644 framework/adapters/dsh/__init__.py create mode 100644 framework/adapters/dsh/normalization.py create mode 100644 framework/adapters/dsh/runner.py create mode 100644 framework/adapters/pi/__init__.py rename .agent/skills/dispatch-agent-task/scripts/muse_read_tools_extension.ts => framework/adapters/pi/mcp_bridge.ts (100%) create mode 100644 framework/adapters/pi/normalization.py rename .agent/skills/dispatch-agent-task/scripts/pi_runner.py => framework/adapters/pi/runner.py (92%) create mode 100644 framework/catalog/catalog.json create mode 100644 framework/catalog/dsh/skills/character-design/SKILL.md create mode 100644 framework/catalog/dsh/skills/character-design/references/_coverage.md create mode 100644 framework/catalog/dsh/skills/character-design/references/archetype-reversal.md create mode 100644 framework/catalog/dsh/skills/character-design/references/character-diagnosis.md create mode 100644 framework/catalog/dsh/skills/character-design/references/character-worksheet.md create mode 100644 framework/catalog/dsh/skills/character-design/references/flat-vs-round.md rename {.agent => framework/catalog/dsh}/skills/character-design/references/inner-demon.md (100%) create mode 100644 framework/catalog/dsh/skills/character-design/references/seven-variables.md create mode 100644 framework/catalog/dsh/skills/character-design/references/three-dimensions.md create mode 100644 framework/catalog/dsh/skills/character-presentation/SKILL.md create mode 100644 framework/catalog/dsh/skills/character-presentation/references/_coverage.md create mode 100644 framework/catalog/dsh/skills/character-presentation/references/abnormal-moment.md create mode 100644 framework/catalog/dsh/skills/character-presentation/references/character-collision.md create mode 100644 framework/catalog/dsh/skills/character-presentation/references/detail-mosaic.md create mode 100644 framework/catalog/dsh/skills/character-presentation/references/presentation-checklist.md create mode 100644 framework/catalog/dsh/skills/character-presentation/references/relationship-web.md create mode 100644 framework/catalog/dsh/skills/character-presentation/references/visible-private-life.md create mode 100644 framework/catalog/dsh/skills/character-presentation/references/voice-discovery-process.md create mode 100644 framework/catalog/dsh/skills/concept-design/SKILL.md create mode 100644 framework/catalog/dsh/skills/concept-design/references/_coverage.md create mode 100644 framework/catalog/dsh/skills/concept-design/references/concept-worksheet.md create mode 100644 framework/catalog/dsh/skills/concept-design/references/delivery-strategy.md create mode 100644 framework/catalog/dsh/skills/concept-design/references/four-questions.md create mode 100644 framework/catalog/dsh/skills/concept-design/references/originality.md create mode 100644 framework/catalog/dsh/skills/concept-design/references/story-engine.md create mode 100644 framework/catalog/dsh/skills/concept-design/references/what-if.md create mode 100644 framework/catalog/dsh/skills/dialogue-craft/SKILL.md create mode 100644 framework/catalog/dsh/skills/dialogue-craft/references/_coverage.md create mode 100644 framework/catalog/dsh/skills/dialogue-craft/references/boundaries-and-pitfalls.md create mode 100644 framework/catalog/dsh/skills/dialogue-craft/references/character-voice.md create mode 100644 framework/catalog/dsh/skills/dialogue-craft/references/dialogue-does-things.md create mode 100644 framework/catalog/dsh/skills/dialogue-craft/references/dialogue-revision-checklist.md create mode 100644 framework/catalog/dsh/skills/dialogue-craft/references/execution-flow.md create mode 100644 framework/catalog/dsh/skills/dialogue-craft/references/real-speech-texture.md create mode 100644 framework/catalog/dsh/skills/dialogue-craft/references/rhythm-and-density.md create mode 100644 framework/catalog/dsh/skills/dialogue-craft/references/tags-and-attribution.md create mode 100644 framework/catalog/dsh/skills/dialogue-craft/references/when-to-use-dialogue.md create mode 100644 framework/catalog/dsh/skills/foreshadow-payoff/SKILL.md create mode 100644 framework/catalog/dsh/skills/foreshadow-payoff/references/_coverage.md create mode 100644 framework/catalog/dsh/skills/foreshadow-payoff/references/boundaries-and-pitfalls.md create mode 100644 framework/catalog/dsh/skills/foreshadow-payoff/references/detail-driven-climax.md create mode 100644 framework/catalog/dsh/skills/foreshadow-payoff/references/foreshadow-checklist.md create mode 100644 framework/catalog/dsh/skills/foreshadow-payoff/references/foreshadow-ledger-template.md create mode 100644 framework/catalog/dsh/skills/foreshadow-payoff/references/natural-staircase.md create mode 100644 framework/catalog/dsh/skills/foreshadow-payoff/references/register-and-repay.md create mode 100644 framework/catalog/dsh/skills/narration-pov/SKILL.md create mode 100644 framework/catalog/dsh/skills/narration-pov/references/_coverage.md create mode 100644 framework/catalog/dsh/skills/narration-pov/references/broken-line.md create mode 100644 framework/catalog/dsh/skills/narration-pov/references/certainty-uncertainty.md create mode 100644 framework/catalog/dsh/skills/narration-pov/references/narration-pov-checklist.md create mode 100644 framework/catalog/dsh/skills/narration-pov/references/outsider-entry.md create mode 100644 framework/catalog/dsh/skills/narration-pov/references/pov-camera.md create mode 100644 framework/catalog/dsh/skills/narration-pov/references/pov-execution.md create mode 100644 framework/catalog/dsh/skills/narration-pov/references/skeptical-stance.md create mode 100644 framework/catalog/dsh/skills/narrative-momentum/SKILL.md create mode 100644 framework/catalog/dsh/skills/narrative-momentum/references/_coverage.md create mode 100644 framework/catalog/dsh/skills/narrative-momentum/references/alternation-and-distinctions.md create mode 100644 framework/catalog/dsh/skills/narrative-momentum/references/breakpoint-hooks.md create mode 100644 framework/catalog/dsh/skills/narrative-momentum/references/build-momentum.md create mode 100644 framework/catalog/dsh/skills/narrative-momentum/references/midway-rewards.md create mode 100644 framework/catalog/dsh/skills/narrative-momentum/references/momentum-checklist.md create mode 100644 framework/catalog/dsh/skills/novel-diagnosis/SKILL.md create mode 100644 framework/catalog/dsh/skills/novel-diagnosis/references/_coverage.md create mode 100644 framework/catalog/dsh/skills/novel-diagnosis/references/diagnosis-workflow.md create mode 100644 framework/catalog/dsh/skills/novel-diagnosis/references/dimension-frameworks.md create mode 100644 framework/catalog/dsh/skills/novel-diagnosis/references/fantasy-prophecy.md create mode 100644 framework/catalog/dsh/skills/novel-diagnosis/references/pattern-rhythm.md create mode 100644 framework/catalog/dsh/skills/novel-diagnosis/references/plot-character.md create mode 100644 framework/catalog/dsh/skills/novel-diagnosis/references/quack-scholar-scan.md create mode 100644 framework/catalog/dsh/skills/novel-diagnosis/references/quack-scholar.md create mode 100644 framework/catalog/dsh/skills/novel-diagnosis/references/round-table.md create mode 100644 framework/catalog/dsh/skills/novel-diagnosis/references/story-plot.md create mode 100644 framework/catalog/dsh/skills/novel-diagnosis/references/time-value.md create mode 100644 framework/catalog/dsh/skills/prose-craft/SKILL.md create mode 100644 framework/catalog/dsh/skills/prose-craft/references/_coverage.md create mode 100644 framework/catalog/dsh/skills/prose-craft/references/abstraction-ladder.md create mode 100644 framework/catalog/dsh/skills/prose-craft/references/base-temperature.md create mode 100644 framework/catalog/dsh/skills/prose-craft/references/lyric-restraint.md create mode 100644 framework/catalog/dsh/skills/prose-craft/references/pattern-and-break.md rename {.agent => framework/catalog/dsh}/skills/prose-craft/references/plain-description.md (100%) create mode 100644 framework/catalog/dsh/skills/prose-craft/references/revision-checklist.md create mode 100644 framework/catalog/dsh/skills/prose-craft/references/rhetoric-density.md create mode 100644 framework/catalog/dsh/skills/prose-craft/references/sentence-rhythm.md create mode 100644 framework/catalog/dsh/skills/prose-craft/references/voice-equalizer.md create mode 100644 framework/catalog/dsh/skills/scene-craft/SKILL.md create mode 100644 framework/catalog/dsh/skills/scene-craft/references/_coverage.md create mode 100644 framework/catalog/dsh/skills/scene-craft/references/boundaries-and-pitfalls.md create mode 100644 framework/catalog/dsh/skills/scene-craft/references/scene-camera.md create mode 100644 framework/catalog/dsh/skills/scene-craft/references/scene-detail.md create mode 100644 framework/catalog/dsh/skills/scene-craft/references/scene-entry-exit.md create mode 100644 framework/catalog/dsh/skills/scene-craft/references/scene-ledger-template.md create mode 100644 framework/catalog/dsh/skills/scene-craft/references/scene-mission.md create mode 100644 framework/catalog/dsh/skills/scene-craft/references/scene-mystification.md create mode 100644 framework/catalog/dsh/skills/scene-craft/references/scene-revision-checklist.md create mode 100644 framework/catalog/dsh/skills/scene-craft/references/scene-rhythm.md create mode 100644 framework/catalog/dsh/skills/show-and-omission/SKILL.md create mode 100644 framework/catalog/dsh/skills/show-and-omission/references/_coverage.md create mode 100644 framework/catalog/dsh/skills/show-and-omission/references/anti-logic.md create mode 100644 framework/catalog/dsh/skills/show-and-omission/references/extreme-emotion-body.md create mode 100644 framework/catalog/dsh/skills/show-and-omission/references/iceberg.md create mode 100644 framework/catalog/dsh/skills/show-and-omission/references/imagination-anchor.md create mode 100644 framework/catalog/dsh/skills/show-and-omission/references/pov-knowledge-boundary.md create mode 100644 framework/catalog/dsh/skills/show-and-omission/references/reader-gap-diagnosis.md create mode 100644 framework/catalog/dsh/skills/show-and-omission/references/show-omission-checklist.md create mode 100644 framework/catalog/dsh/skills/show-and-omission/references/show-vs-tell.md create mode 100644 framework/catalog/dsh/skills/story-ending/SKILL.md create mode 100644 framework/catalog/dsh/skills/story-ending/references/_coverage.md create mode 100644 framework/catalog/dsh/skills/story-ending/references/ending-strategies.md create mode 100644 framework/catalog/dsh/skills/story-ending/references/execution-chain.md create mode 100644 framework/catalog/dsh/skills/story-ending/references/expansion-completion.md create mode 100644 framework/catalog/dsh/skills/story-ending/references/fix-final-scene.md create mode 100644 framework/catalog/dsh/skills/story-ending/references/natural-stop.md create mode 100644 framework/catalog/dsh/skills/story-ending/references/pitfalls-and-boundaries.md create mode 100644 framework/catalog/dsh/skills/story-planning/SKILL.md create mode 100644 framework/catalog/dsh/skills/story-planning/references/_coverage.md create mode 100644 framework/catalog/dsh/skills/story-planning/references/beat-sheet.md create mode 100644 framework/catalog/dsh/skills/story-planning/references/draft-flow.md create mode 100644 framework/catalog/dsh/skills/story-planning/references/plan-vs-pantsing.md create mode 100644 framework/catalog/dsh/skills/story-planning/references/planning-workflow-checklist.md create mode 100644 framework/catalog/dsh/skills/story-structure/SKILL.md create mode 100644 framework/catalog/dsh/skills/story-structure/references/_coverage.md create mode 100644 framework/catalog/dsh/skills/story-structure/references/first-plot-point.md create mode 100644 framework/catalog/dsh/skills/story-structure/references/four-boxes.md create mode 100644 framework/catalog/dsh/skills/story-structure/references/inciting-incident.md create mode 100644 framework/catalog/dsh/skills/story-structure/references/inciting-vs-fpp.md create mode 100644 framework/catalog/dsh/skills/story-structure/references/length-system.md create mode 100644 framework/catalog/dsh/skills/story-structure/references/midpoint.md create mode 100644 framework/catalog/dsh/skills/story-structure/references/opening.md create mode 100644 framework/catalog/dsh/skills/story-structure/references/part2-wanderer.md create mode 100644 framework/catalog/dsh/skills/story-structure/references/setup.md create mode 100644 framework/catalog/dsh/skills/story-structure/references/six-milestones.md create mode 100644 framework/catalog/dsh/skills/story-structure/references/structure-checklists.md create mode 100644 framework/catalog/dsh/skills/theme-and-stance/SKILL.md create mode 100644 framework/catalog/dsh/skills/theme-and-stance/references/_coverage.md create mode 100644 framework/catalog/dsh/skills/theme-and-stance/references/boundaries-and-pitfalls.md create mode 100644 framework/catalog/dsh/skills/theme-and-stance/references/humor-as-stance.md create mode 100644 framework/catalog/dsh/skills/theme-and-stance/references/mercy-ruth.md create mode 100644 framework/catalog/dsh/skills/theme-and-stance/references/stance-by-logic.md create mode 100644 framework/catalog/dsh/skills/theme-and-stance/references/theme-demonstration.md create mode 100644 framework/catalog/dsh/skills/theme-and-stance/references/theme-stance-checklist.md create mode 100644 framework/catalog/generate_skill_projections.py create mode 100644 framework/catalog/pi/skills/character-design/SKILL.md create mode 100644 framework/catalog/pi/skills/character-design/references/_coverage.md create mode 100644 framework/catalog/pi/skills/character-design/references/archetype-reversal.md create mode 100644 framework/catalog/pi/skills/character-design/references/character-diagnosis.md create mode 100644 framework/catalog/pi/skills/character-design/references/character-worksheet.md create mode 100644 framework/catalog/pi/skills/character-design/references/flat-vs-round.md create mode 100644 framework/catalog/pi/skills/character-design/references/inner-demon.md create mode 100644 framework/catalog/pi/skills/character-design/references/seven-variables.md create mode 100644 framework/catalog/pi/skills/character-design/references/three-dimensions.md create mode 100644 framework/catalog/pi/skills/character-presentation/SKILL.md create mode 100644 framework/catalog/pi/skills/character-presentation/references/_coverage.md create mode 100644 framework/catalog/pi/skills/character-presentation/references/abnormal-moment.md create mode 100644 framework/catalog/pi/skills/character-presentation/references/character-collision.md create mode 100644 framework/catalog/pi/skills/character-presentation/references/detail-mosaic.md create mode 100644 framework/catalog/pi/skills/character-presentation/references/presentation-checklist.md create mode 100644 framework/catalog/pi/skills/character-presentation/references/relationship-web.md create mode 100644 framework/catalog/pi/skills/character-presentation/references/visible-private-life.md create mode 100644 framework/catalog/pi/skills/character-presentation/references/voice-discovery-process.md create mode 100644 framework/catalog/pi/skills/concept-design/SKILL.md create mode 100644 framework/catalog/pi/skills/concept-design/references/_coverage.md create mode 100644 framework/catalog/pi/skills/concept-design/references/concept-worksheet.md create mode 100644 framework/catalog/pi/skills/concept-design/references/delivery-strategy.md create mode 100644 framework/catalog/pi/skills/concept-design/references/four-questions.md create mode 100644 framework/catalog/pi/skills/concept-design/references/originality.md create mode 100644 framework/catalog/pi/skills/concept-design/references/story-engine.md create mode 100644 framework/catalog/pi/skills/concept-design/references/what-if.md create mode 100644 framework/catalog/pi/skills/dialogue-craft/SKILL.md create mode 100644 framework/catalog/pi/skills/dialogue-craft/references/_coverage.md create mode 100644 framework/catalog/pi/skills/dialogue-craft/references/boundaries-and-pitfalls.md create mode 100644 framework/catalog/pi/skills/dialogue-craft/references/character-voice.md create mode 100644 framework/catalog/pi/skills/dialogue-craft/references/dialogue-does-things.md create mode 100644 framework/catalog/pi/skills/dialogue-craft/references/dialogue-revision-checklist.md create mode 100644 framework/catalog/pi/skills/dialogue-craft/references/execution-flow.md create mode 100644 framework/catalog/pi/skills/dialogue-craft/references/real-speech-texture.md create mode 100644 framework/catalog/pi/skills/dialogue-craft/references/rhythm-and-density.md create mode 100644 framework/catalog/pi/skills/dialogue-craft/references/tags-and-attribution.md create mode 100644 framework/catalog/pi/skills/dialogue-craft/references/when-to-use-dialogue.md create mode 100644 framework/catalog/pi/skills/foreshadow-payoff/SKILL.md create mode 100644 framework/catalog/pi/skills/foreshadow-payoff/references/_coverage.md create mode 100644 framework/catalog/pi/skills/foreshadow-payoff/references/boundaries-and-pitfalls.md create mode 100644 framework/catalog/pi/skills/foreshadow-payoff/references/detail-driven-climax.md create mode 100644 framework/catalog/pi/skills/foreshadow-payoff/references/foreshadow-checklist.md create mode 100644 framework/catalog/pi/skills/foreshadow-payoff/references/foreshadow-ledger-template.md create mode 100644 framework/catalog/pi/skills/foreshadow-payoff/references/natural-staircase.md create mode 100644 framework/catalog/pi/skills/foreshadow-payoff/references/register-and-repay.md create mode 100644 framework/catalog/pi/skills/narration-pov/SKILL.md create mode 100644 framework/catalog/pi/skills/narration-pov/references/_coverage.md create mode 100644 framework/catalog/pi/skills/narration-pov/references/broken-line.md create mode 100644 framework/catalog/pi/skills/narration-pov/references/certainty-uncertainty.md create mode 100644 framework/catalog/pi/skills/narration-pov/references/narration-pov-checklist.md create mode 100644 framework/catalog/pi/skills/narration-pov/references/outsider-entry.md create mode 100644 framework/catalog/pi/skills/narration-pov/references/pov-camera.md create mode 100644 framework/catalog/pi/skills/narration-pov/references/pov-execution.md create mode 100644 framework/catalog/pi/skills/narration-pov/references/skeptical-stance.md create mode 100644 framework/catalog/pi/skills/narrative-momentum/SKILL.md create mode 100644 framework/catalog/pi/skills/narrative-momentum/references/_coverage.md create mode 100644 framework/catalog/pi/skills/narrative-momentum/references/alternation-and-distinctions.md create mode 100644 framework/catalog/pi/skills/narrative-momentum/references/breakpoint-hooks.md create mode 100644 framework/catalog/pi/skills/narrative-momentum/references/build-momentum.md create mode 100644 framework/catalog/pi/skills/narrative-momentum/references/midway-rewards.md create mode 100644 framework/catalog/pi/skills/narrative-momentum/references/momentum-checklist.md create mode 100644 framework/catalog/pi/skills/novel-diagnosis/SKILL.md create mode 100644 framework/catalog/pi/skills/novel-diagnosis/references/_coverage.md create mode 100644 framework/catalog/pi/skills/novel-diagnosis/references/diagnosis-workflow.md create mode 100644 framework/catalog/pi/skills/novel-diagnosis/references/dimension-frameworks.md create mode 100644 framework/catalog/pi/skills/novel-diagnosis/references/fantasy-prophecy.md create mode 100644 framework/catalog/pi/skills/novel-diagnosis/references/pattern-rhythm.md create mode 100644 framework/catalog/pi/skills/novel-diagnosis/references/plot-character.md create mode 100644 framework/catalog/pi/skills/novel-diagnosis/references/quack-scholar-scan.md create mode 100644 framework/catalog/pi/skills/novel-diagnosis/references/quack-scholar.md create mode 100644 framework/catalog/pi/skills/novel-diagnosis/references/round-table.md create mode 100644 framework/catalog/pi/skills/novel-diagnosis/references/story-plot.md create mode 100644 framework/catalog/pi/skills/novel-diagnosis/references/time-value.md create mode 100644 framework/catalog/pi/skills/prose-craft/SKILL.md create mode 100644 framework/catalog/pi/skills/prose-craft/references/_coverage.md create mode 100644 framework/catalog/pi/skills/prose-craft/references/abstraction-ladder.md create mode 100644 framework/catalog/pi/skills/prose-craft/references/base-temperature.md create mode 100644 framework/catalog/pi/skills/prose-craft/references/lyric-restraint.md create mode 100644 framework/catalog/pi/skills/prose-craft/references/pattern-and-break.md create mode 100644 framework/catalog/pi/skills/prose-craft/references/plain-description.md create mode 100644 framework/catalog/pi/skills/prose-craft/references/revision-checklist.md create mode 100644 framework/catalog/pi/skills/prose-craft/references/rhetoric-density.md create mode 100644 framework/catalog/pi/skills/prose-craft/references/sentence-rhythm.md create mode 100644 framework/catalog/pi/skills/prose-craft/references/voice-equalizer.md create mode 100644 framework/catalog/pi/skills/scene-craft/SKILL.md create mode 100644 framework/catalog/pi/skills/scene-craft/references/_coverage.md create mode 100644 framework/catalog/pi/skills/scene-craft/references/boundaries-and-pitfalls.md create mode 100644 framework/catalog/pi/skills/scene-craft/references/scene-camera.md create mode 100644 framework/catalog/pi/skills/scene-craft/references/scene-detail.md create mode 100644 framework/catalog/pi/skills/scene-craft/references/scene-entry-exit.md create mode 100644 framework/catalog/pi/skills/scene-craft/references/scene-ledger-template.md create mode 100644 framework/catalog/pi/skills/scene-craft/references/scene-mission.md create mode 100644 framework/catalog/pi/skills/scene-craft/references/scene-mystification.md create mode 100644 framework/catalog/pi/skills/scene-craft/references/scene-revision-checklist.md create mode 100644 framework/catalog/pi/skills/scene-craft/references/scene-rhythm.md create mode 100644 framework/catalog/pi/skills/show-and-omission/SKILL.md create mode 100644 framework/catalog/pi/skills/show-and-omission/references/_coverage.md create mode 100644 framework/catalog/pi/skills/show-and-omission/references/anti-logic.md create mode 100644 framework/catalog/pi/skills/show-and-omission/references/extreme-emotion-body.md create mode 100644 framework/catalog/pi/skills/show-and-omission/references/iceberg.md create mode 100644 framework/catalog/pi/skills/show-and-omission/references/imagination-anchor.md create mode 100644 framework/catalog/pi/skills/show-and-omission/references/pov-knowledge-boundary.md create mode 100644 framework/catalog/pi/skills/show-and-omission/references/reader-gap-diagnosis.md create mode 100644 framework/catalog/pi/skills/show-and-omission/references/show-omission-checklist.md create mode 100644 framework/catalog/pi/skills/show-and-omission/references/show-vs-tell.md create mode 100644 framework/catalog/pi/skills/story-ending/SKILL.md create mode 100644 framework/catalog/pi/skills/story-ending/references/_coverage.md create mode 100644 framework/catalog/pi/skills/story-ending/references/ending-strategies.md create mode 100644 framework/catalog/pi/skills/story-ending/references/execution-chain.md create mode 100644 framework/catalog/pi/skills/story-ending/references/expansion-completion.md create mode 100644 framework/catalog/pi/skills/story-ending/references/fix-final-scene.md create mode 100644 framework/catalog/pi/skills/story-ending/references/natural-stop.md create mode 100644 framework/catalog/pi/skills/story-ending/references/pitfalls-and-boundaries.md create mode 100644 framework/catalog/pi/skills/story-planning/SKILL.md create mode 100644 framework/catalog/pi/skills/story-planning/references/_coverage.md create mode 100644 framework/catalog/pi/skills/story-planning/references/beat-sheet.md create mode 100644 framework/catalog/pi/skills/story-planning/references/draft-flow.md create mode 100644 framework/catalog/pi/skills/story-planning/references/plan-vs-pantsing.md create mode 100644 framework/catalog/pi/skills/story-planning/references/planning-workflow-checklist.md create mode 100644 framework/catalog/pi/skills/story-structure/SKILL.md create mode 100644 framework/catalog/pi/skills/story-structure/references/_coverage.md create mode 100644 framework/catalog/pi/skills/story-structure/references/first-plot-point.md create mode 100644 framework/catalog/pi/skills/story-structure/references/four-boxes.md create mode 100644 framework/catalog/pi/skills/story-structure/references/inciting-incident.md create mode 100644 framework/catalog/pi/skills/story-structure/references/inciting-vs-fpp.md create mode 100644 framework/catalog/pi/skills/story-structure/references/length-system.md create mode 100644 framework/catalog/pi/skills/story-structure/references/midpoint.md create mode 100644 framework/catalog/pi/skills/story-structure/references/opening.md create mode 100644 framework/catalog/pi/skills/story-structure/references/part2-wanderer.md create mode 100644 framework/catalog/pi/skills/story-structure/references/setup.md create mode 100644 framework/catalog/pi/skills/story-structure/references/six-milestones.md create mode 100644 framework/catalog/pi/skills/story-structure/references/structure-checklists.md create mode 100644 framework/catalog/pi/skills/theme-and-stance/SKILL.md create mode 100644 framework/catalog/pi/skills/theme-and-stance/references/_coverage.md create mode 100644 framework/catalog/pi/skills/theme-and-stance/references/boundaries-and-pitfalls.md create mode 100644 framework/catalog/pi/skills/theme-and-stance/references/humor-as-stance.md create mode 100644 framework/catalog/pi/skills/theme-and-stance/references/mercy-ruth.md create mode 100644 framework/catalog/pi/skills/theme-and-stance/references/stance-by-logic.md create mode 100644 framework/catalog/pi/skills/theme-and-stance/references/theme-demonstration.md create mode 100644 framework/catalog/pi/skills/theme-and-stance/references/theme-stance-checklist.md create mode 100644 framework/primitives/__init__.py create mode 100644 framework/primitives/artifacts.py create mode 100644 framework/primitives/execution.py create mode 100644 framework/primitives/schemas/framework_event.schema.json create mode 100644 framework/primitives/schemas/framework_execution_request.schema.json create mode 100644 framework/primitives/schemas/framework_execution_result.schema.json delete mode 100644 harness/skills_index.py create mode 100644 muse/_skills_index.md rename {db => muse/authority/db}/ddl/100-example规划与冻结.sql (100%) rename {db => muse/authority/db}/ddl/101-example-raw.sql (100%) rename {db => muse/authority/db}/ddl/102-example智能体技能登记.sql (100%) rename {db => muse/authority/db}/ddl/103-example评测隔离引擎强制.sql (100%) rename {db => muse/authority/db}/ddl/104-example-ai-flavor-cases.sql (100%) rename {db => muse/authority/db}/ddl/105-example候选语义审查.sql (100%) rename {db => muse/authority/db}/ddl/106-example事实增量.sql (100%) rename {db => muse/authority/db}/ddl/107-example投影登记.sql (100%) rename {db => muse/authority/db}/ddl/108-example经验升格.sql (100%) rename {db => muse/authority/db}/ddl/109-example候选状态CAS.sql (100%) rename {db => muse/authority/db}/ddl/110-example-voice-baseline.sql (100%) rename {db => muse/authority/db}/ddl/111-example-humanization规则与样例.sql (100%) rename {db => muse/authority/db}/ddl/112-example角色模型策略与登记路径.sql (93%) rename {db => muse/authority/db}/ddl/113-example代理事件账本.sql (100%) rename {db => muse/authority/db}/ddl/114-example冻结幂等键-清单加上下文对.sql (100%) rename {db => muse/authority/db}/ddl/90-主仓ALTER摘录-V9V10V14V30.sql (100%) rename {db => muse/authority/db}/ddl/91-example实验私货.sql (100%) rename {db => muse/authority/db}/ddl/92-example清洗日志.sql (100%) rename {db => muse/authority/db}/ddl/93-example大纲聚合.sql (100%) rename {db => muse/authority/db}/ddl/94-example作品面升格.sql (100%) rename {db => muse/authority/db}/ddl/95-example额度账本.sql (100%) rename {db => muse/authority/db}/ddl/96-example参考作品授权快照.sql (100%) rename {db => muse/authority/db}/ddl/97-example模型调用明细.sql (100%) rename {db => muse/authority/db}/ddl/98-example运行与回执与质量结果.sql (100%) rename {db => muse/authority/db}/ddl/99-example候选与决策.sql (100%) rename {db => muse/authority/db}/ddl/V1__init_content_schema.sql (100%) rename {db => muse/authority/db}/ddl/V26__fix_content_softdelete_order_uk_partial.sql (100%) rename {db => muse/authority/db}/ddl/V3__init_meta_schema.sql (100%) rename {db => muse/authority/db}/ddl/V5__init_knowledge_schema.sql (100%) rename {db => muse/authority/db}/表映射.md (97%) rename {db => muse/authority/db}/连接信息.md (100%) rename {.agent => muse/authority/evidence}/skills/access-database/SKILL.md (63%) rename {.agent => muse/authority/evidence}/skills/access-database/scripts/db.py (100%) rename {.agent => muse/authority/evidence}/skills/access-database/scripts/seed_schemas.py (100%) rename {.agent => muse/authority/evidence}/skills/access-database/scripts/sync_agent_registry.py (91%) rename {.agent => muse/authority/evidence}/skills/record-run-evidence/SKILL.md (100%) rename {.agent => muse/authority/evidence}/skills/record-run-evidence/scripts/agent_trace.py (100%) rename {.agent => muse/authority/evidence}/skills/record-run-evidence/scripts/file_cas.py (100%) rename {.agent => muse/authority/evidence}/skills/record-run-evidence/scripts/invariant_checks.py (97%) rename {.agent => muse/authority/evidence}/skills/record-run-evidence/scripts/lesson_registry.py (100%) rename {.agent => muse/authority/evidence}/skills/record-run-evidence/scripts/persist_llm_call.py (100%) rename {.agent => muse/authority/evidence}/skills/record-run-evidence/scripts/persist_raw.py (100%) rename {.agent => muse/authority/evidence}/skills/record-run-evidence/scripts/raw_vault.py (100%) rename {.agent => muse/authority/evidence}/skills/record-run-evidence/scripts/record_failed_run.py (100%) rename {.agent => muse/authority/evidence}/skills/record-run-evidence/scripts/repair_receipt_evidence.py (100%) rename {.agent => muse/authority/evidence}/skills/record-run-evidence/scripts/run_registry.py (100%) rename {dashboard => muse/authority/studio/read}/fixtures/README.md (100%) rename {dashboard => muse/authority/studio/read}/fixtures/backfill-inventory-2026-08-13.json (100%) rename {dashboard => muse/authority/studio/read}/fixtures/revalidation-2026-08-14.json (100%) rename {dashboard => muse/authority/studio/read}/server.py (99%) rename {dashboard => muse/authority/studio/read}/test_server_display.py (100%) rename {dashboard => muse/authority/studio/write/decision}/decision_channel.py (100%) rename {dashboard => muse/authority/studio/write/lesson}/lesson_confirm.py (99%) rename {.agent/skills/dispatch-agent-task/scripts => muse/authority/tools/read}/read_tools.py (100%) rename {.agent/skills => muse/content/entity/skills/extract}/extract-chapter-knowledge/SKILL.md (100%) rename {.agent/skills => muse/content/entity/skills/extract}/extract-chapter-knowledge/scripts/dispatch_extraction_bridge.py (95%) rename {.agent/skills => muse/content/entity/skills/extract}/extract-chapter-knowledge/scripts/extract_knowledge.py (98%) rename {.agent/skills => muse/content/entity/skills/extract}/extract-chapter-knowledge/scripts/extract_via_dispatch.py (93%) rename {.agent/skills => muse/content/entity/skills/ingest}/backup-work-extraction/SKILL.md (91%) rename {.agent/skills => muse/content/entity/skills/ingest}/backup-work-extraction/scripts/backup_upgrade_work.py (97%) rename {.agent/skills => muse/content/entity/skills/ingest}/clean-book-text/SKILL.md (81%) rename {.agent/skills => muse/content/entity/skills/ingest}/clean-book-text/scripts/clean_apply.py (100%) rename {.agent/skills => muse/content/entity/skills/ingest}/clean-book-text/scripts/clean_batch.py (100%) rename {.agent/skills => muse/content/entity/skills/ingest}/clean-book-text/scripts/clean_detect.py (100%) rename {.agent/skills => muse/content/entity/skills/ingest}/clean-book-text/scripts/clean_prep.py (100%) rename {.agent/skills => muse/content/entity/skills/ingest}/clean-book-text/scripts/clean_sweep.py (100%) rename {.agent/skills => muse/content/entity/skills/ingest}/deconstruct-book/SKILL.md (91%) rename {.agent/skills => muse/content/entity/skills/ingest}/deconstruct-book/scripts/parse_ingest.py (100%) rename {.agent/skills => muse/content/entity/skills/ingest}/deconstruct-book/scripts/parse_llm.py (100%) rename {.agent/skills => muse/content/entity/skills/ingest}/deconstruct-book/scripts/parse_outline.py (100%) rename {.agent/skills => muse/content/entity/skills/ingest}/deconstruct-book/scripts/parse_salvage.py (100%) rename {.agent/skills => muse/content/entity/skills/ingest}/extract-work-knowledge/SKILL.md (90%) rename {.agent/skills => muse/content/entity/skills/ingest}/extract-work-knowledge/scripts/upgrade.py (99%) rename {.agent/skills => muse/content/entity/skills/ingest}/extract-work-knowledge/scripts/upgrade_work_lock.py (100%) rename {.agent/skills => muse/content/entity/skills/ingest}/import-book/SKILL.md (86%) rename {.agent/skills => muse/content/entity/skills/ingest}/import-book/scripts/import_novel.py (100%) rename {.agent/skills => muse/content/entity/skills/ingest}/inspect-parse-health/SKILL.md (82%) rename {.agent/skills => muse/content/entity/skills/ingest}/inspect-parse-health/scripts/parse_export.py (100%) rename {.agent/skills => muse/content/entity/skills/ingest}/inspect-parse-health/scripts/parse_health.py (100%) rename {.agent/skills => muse/content/entity/skills/ingest}/repair-work-extraction/SKILL.md (96%) rename {.agent/skills => muse/content/entity/skills/ingest}/repair-work-extraction/scripts/maintenance.py (100%) rename {.agent/skills => muse/content/entity/skills/ingest}/repair-work-extraction/scripts/migrate_upgrade_windows.py (100%) rename {.agent/skills => muse/content/entity/skills/ingest}/repair-work-extraction/scripts/parse_rewash.py (100%) rename {.agent/skills => muse/content/entity/skills/ingest}/reset-work-extraction/SKILL.md (93%) rename {.agent/skills => muse/content/entity/skills/ingest}/reset-work-extraction/scripts/reset_upgrade_work.py (94%) rename {.agent/skills => muse/content/entity/skills/review}/review-knowledge-cards/SKILL.md (95%) rename {.agent/skills => muse/content/entity/skills/review}/review-knowledge-cards/golden/scores-cal002-m3旧尺子对照.json (100%) rename {.agent/skills => muse/content/entity/skills/review}/review-knowledge-cards/golden/scores-cal002.json (100%) rename {.agent/skills => muse/content/entity/skills/review}/review-knowledge-cards/golden/scores.json (100%) rename {.agent/skills => muse/content/entity/skills/review}/review-knowledge-cards/golden/金标准-主编-2026-07-13.md (100%) rename {.agent/skills => muse/content/entity/skills/review}/review-knowledge-cards/golden/金标准-番茄作家-2026-07-13.md (100%) rename {.agent/skills => muse/content/entity/skills/review}/review-knowledge-cards/golden/金标准-起点作家-2026-07-13.md (100%) rename {.agent/skills => muse/content/entity/skills/review}/review-knowledge-cards/scripts/review_cards.py (100%) rename {.agent/skills => muse/content/entity/skills/sovereignty}/confirm-knowledge-draft/SKILL.md (85%) rename {.agent/skills => muse/content/entity/skills/sovereignty}/confirm-knowledge-draft/scripts/confirm_knowledge.py (100%) rename {knowledge => muse/content/entity/sources}/README.md (100%) rename {knowledge => muse/content/entity/sources}/参考书/封神演义/档案.md (100%) rename {knowledge => muse/content/entity/sources}/参考书/封神演义/第12回.txt (100%) rename {knowledge => muse/content/entity/sources}/参考书/封神演义/第13回.txt (100%) rename {knowledge => muse/content/entity/sources}/参考书/封神演义/第14回.txt (100%) rename {meta => muse/content/meta}/schemas/README.md (90%) rename {meta => muse/content/meta}/schemas/chapter.yaml (100%) rename {meta => muse/content/meta}/schemas/character.yaml (100%) rename {meta => muse/content/meta}/schemas/character_relation.yaml (100%) rename {meta => muse/content/meta}/schemas/combat.yaml (100%) rename {meta => muse/content/meta}/schemas/craft.yaml (100%) rename {meta => muse/content/meta}/schemas/emotion.yaml (100%) rename {meta => muse/content/meta}/schemas/event.yaml (100%) rename {meta => muse/content/meta}/schemas/faction.yaml (100%) rename {meta => muse/content/meta}/schemas/fine_outline.yaml (100%) rename {meta => muse/content/meta}/schemas/generation_context.yaml (96%) rename {meta => muse/content/meta}/schemas/item.yaml (100%) rename {meta => muse/content/meta}/schemas/location.yaml (100%) rename {meta => muse/content/meta}/schemas/narrative_state.yaml (100%) rename {meta => muse/content/meta}/schemas/novel_work.yaml (100%) rename {meta => muse/content/meta}/schemas/outline.yaml (100%) rename {meta => muse/content/meta}/schemas/pacing.yaml (100%) rename {meta => muse/content/meta}/schemas/power_system.yaml (100%) rename {meta => muse/content/meta}/schemas/reference_work.yaml (100%) rename {meta => muse/content/meta}/schemas/scene.yaml (100%) rename {meta => muse/content/meta}/schemas/scene_pattern.yaml (100%) rename {meta => muse/content/meta}/schemas/style.yaml (100%) rename {meta => muse/content/meta}/schemas/trope.yaml (100%) rename {meta => muse/content/meta}/schemas/work_core.yaml (100%) rename {meta => muse/content/meta}/schemas/world.yaml (100%) rename {.agent/skills => muse/content/work/skills/generate}/expand-scene/SKILL.md (100%) rename {.agent/skills => muse/content/work/skills/generate}/polish-prose/SKILL.md (100%) rename {.agent/skills => muse/content/work/skills/generate}/rewrite-selection/SKILL.md (96%) rename {.agent/skills => muse/content/work/skills/generate}/rewrite-selection/scripts/assert_expected_revision.py (100%) rename {.agent/skills => muse/content/work/skills/generate}/write-next-chapter/SKILL.md (100%) rename {.agent/skills => muse/content/work/skills/generate}/write-next-chapter/scripts/candidate_cas.py (98%) rename {.agent/skills => muse/content/work/skills/generate}/write-next-chapter/scripts/dispatch_writer_bridge.py (94%) rename {.agent/skills => muse/content/work/skills/generate}/write-next-chapter/scripts/persist_writer_run.py (97%) rename {.agent/skills => muse/content/work/skills/generate}/write-next-chapter/scripts/produce_next_chapter.py (96%) rename {.agent/skills => muse/content/work/skills/generate}/write-next-chapter/scripts/production_evidence_reassemble.py (100%) rename {.agent/skills => muse/content/work/skills/generate}/write-next-chapter/scripts/run_contrast_writer.py (98%) rename {.agent/skills => muse/content/work/skills/generate}/write-next-chapter/scripts/run_writer.py (96%) rename {.agent/skills => muse/content/work/skills/generate}/write-next-chapter/scripts/run_writer_pipeline.py (98%) rename {.agent/skills => muse/content/work/skills/generate}/write-next-chapter/scripts/two_phase_writer.py (96%) rename {.agent/skills => muse/content/work/skills/sovereignty}/decide-candidate/SKILL.md (91%) rename {.agent/skills => muse/content/work/skills/sovereignty}/decide-candidate/scripts/acceptance_state.py (100%) rename {.agent/skills => muse/content/work/skills/sovereignty}/decide-candidate/scripts/check_writer_acceptance.py (100%) rename {.agent/skills => muse/content/work/skills/sovereignty}/decide-candidate/scripts/fact_delta.py (98%) rename {.agent/skills => muse/content/work/skills/sovereignty}/decide-candidate/scripts/projection_registry.py (100%) rename {.agent/skills => muse/content/work/skills/sovereignty}/decide-candidate/scripts/write_canonical.py (98%) rename {.agent => muse/lifecycle/context}/skills/assemble-context/SKILL.md (97%) rename {.agent => muse/lifecycle/context}/skills/assemble-context/scripts/assemble_writer_context.py (100%) rename {.agent => muse/lifecycle/context}/skills/assemble-context/scripts/persist_context_freeze.py (100%) rename {.agent => muse/lifecycle/context}/skills/assemble-context/scripts/retrieve_writer_sources.py (100%) rename {.agent => muse/lifecycle/context}/skills/assemble-context/scripts/writer_contract.py (100%) rename {.agent => muse/lifecycle/context}/skills/embed-knowledge/SKILL.md (84%) rename {.agent => muse/lifecycle/context}/skills/embed-knowledge/scripts/embed_drafts.py (100%) rename {.agent => muse/lifecycle/context}/skills/freeze-context/SKILL.md (100%) rename {.agent => muse/lifecycle/context}/skills/freeze-context/scripts/audit_leakage.py (100%) rename {.agent => muse/lifecycle/context}/skills/freeze-context/scripts/build_snapshot.py (100%) rename {.agent => muse/lifecycle/context}/skills/freeze-context/scripts/check_snapshot.py (100%) rename {.agent => muse/lifecycle/context}/skills/freeze-context/scripts/load_reference_work.py (100%) rename {.agent => muse/lifecycle/context}/skills/search-knowledge/SKILL.md (82%) rename {.agent => muse/lifecycle/context}/skills/search-knowledge/scripts/search.py (100%) rename {.agent => muse/lifecycle/dispatch}/skills/dispatch-agent-task/SKILL.md (65%) rename {.agent => muse/lifecycle/dispatch}/skills/dispatch-agent-task/scripts/dispatch_agent_task.py (93%) create mode 100644 muse/lifecycle/dispatch/skills/dispatch-agent-task/scripts/role_policy.py rename .agent/skills/dispatch-agent-task/scripts/agent_task.py => muse/lifecycle/dispatch/skills/dispatch-agent-task/scripts/role_task.py (88%) rename {meta => muse/lifecycle/flow}/chains/README.md (96%) rename {.agent/skills => muse/lifecycle/flow/skills/book}/design-story-foundation/SKILL.md (94%) rename {.agent/skills => muse/lifecycle/flow/skills/book}/design-story-foundation/references/candidate-contract.md (100%) rename {.agent/skills => muse/lifecycle/flow/skills/book}/design-story-foundation/references/chapter-content-spec-chapters-1-5.md (100%) rename {.agent/skills => muse/lifecycle/flow/skills/book}/design-story-foundation/references/chapter-content-spec-chapters-6-9.md (100%) rename {.agent/skills => muse/lifecycle/flow/skills/book}/design-story-foundation/references/chapter-content-spec.md (100%) rename {.agent/skills => muse/lifecycle/flow/skills/book}/design-story-foundation/scripts/assert_selection_handoff.py (100%) rename {.agent/skills => muse/lifecycle/flow/skills/book}/design-story-foundation/scripts/candidate_tree.json (100%) rename {.agent/skills => muse/lifecycle/flow/skills/book}/design-story-foundation/scripts/validate_candidates.py (100%) rename {.agent/skills => muse/lifecycle/flow/skills/book}/merge-story-candidates/SKILL.md (90%) rename {.agent/skills => muse/lifecycle/flow/skills/book}/merge-story-candidates/references/serial-merge-contract.md (100%) rename {.agent/skills => muse/lifecycle/flow/skills/book}/merge-story-candidates/scripts/serial_merge.py (100%) rename {.agent/skills => muse/lifecycle/flow/skills/book}/plan-story/SKILL.md (95%) rename {.agent/skills => muse/lifecycle/flow/skills/book}/plan-story/scripts/persist_planning.py (97%) rename {.agent/skills => muse/lifecycle/flow/skills/book}/plan-story/scripts/record_planning_execution.py (96%) rename {.agent/skills => muse/lifecycle/flow/skills/book}/plan-story/scripts/repair_deterministic_receipt.py (100%) rename {.agent/skills => muse/lifecycle/flow/skills/book}/plan-story/scripts/select_patterns.py (91%) rename {.agent/skills => muse/lifecycle/flow/skills/chapter}/plan-chapter/SKILL.md (95%) rename {harness => muse/lifecycle/quality/harness}/README.md (90%) rename {harness => muse/lifecycle/quality/harness}/evals/skill_eval.py (100%) rename {harness => muse/lifecycle/quality/harness}/evals/skills/diagnose-ai-flavor/run_eval.py (82%) rename {harness => muse/lifecycle/quality/harness}/evals/skills/diagnose-ai-flavor/scenarios.json (100%) rename {harness => muse/lifecycle/quality/harness}/evals/test_skill_eval.py (88%) rename {harness => muse/lifecycle/quality/harness}/manifests/skills.json (80%) rename {harness => muse/lifecycle/quality/harness}/manifests/test-inventory.json (93%) create mode 100644 muse/lifecycle/quality/harness/project_paths.py rename {harness => muse/lifecycle/quality/harness}/run_selected.py (93%) rename {harness => muse/lifecycle/quality/harness}/skill_harness.py (93%) create mode 100644 muse/lifecycle/quality/harness/skills_index.py rename {harness => muse/lifecycle/quality/harness}/specs/skill-quality-rubric.md (94%) rename {harness => muse/lifecycle/quality/harness}/specs/skill-testing.md (96%) rename {harness => muse/lifecycle/quality/harness}/test_run_selected.py (92%) rename {harness => muse/lifecycle/quality/harness}/test_skill_harness.py (94%) rename {humanization => muse/lifecycle/quality/humanization}/README.md (72%) rename {humanization => muse/lifecycle/quality/humanization}/cards/backfill-example.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/config.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/contracts/audit_report.schema.json (100%) rename {humanization => muse/lifecycle/quality/humanization}/contracts/case_card.schema.json (100%) rename {humanization => muse/lifecycle/quality/humanization}/contracts/finding.schema.json (100%) rename {humanization => muse/lifecycle/quality/humanization}/contracts/patch.schema.json (100%) rename {humanization => muse/lifecycle/quality/humanization}/contracts/prevention.schema.json (100%) rename {humanization => muse/lifecycle/quality/humanization}/contracts/rule.schema.json (100%) rename {humanization => muse/lifecycle/quality/humanization}/contracts/sample.schema.json (100%) rename {humanization => muse/lifecycle/quality/humanization}/contracts/voice_baseline.schema.json (100%) rename {humanization => muse/lifecycle/quality/humanization}/eval/run_eval.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/pyproject.toml (100%) rename {humanization => muse/lifecycle/quality/humanization}/research/20-project-humanization-rule-catalog.zh-CN.md (99%) rename {humanization => muse/lifecycle/quality/humanization}/research/20-project-skill-coverage.yaml (71%) rename {humanization => muse/lifecycle/quality/humanization}/rules/density/d001.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/density/d002.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/density/d003.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/density/d004.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/density/d005.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/density/d006.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/lexical/l001.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/lexical/l002.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/lexical/l003.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/lexical/l004.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/lexical/l005.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/lexical/l006.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/mechanical/m001.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/mechanical/m002.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/mechanical/m003.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/mechanical/m004.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/semantic/sem001.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/semantic/sem002.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/semantic/sem003.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/structural/s001.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/structural/s002.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/structural/s003.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/structural/s004.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/structural/s005.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/structural/s006.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/rules/structural/s007.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/samples/boundary.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/samples/regression.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/samples/sf.yaml (100%) rename {humanization => muse/lifecycle/quality/humanization}/samples/snf.yaml (100%) rename {.agent => muse/lifecycle/quality/humanization}/skills/capture-ai-flavor-cases/SKILL.md (86%) rename {.agent => muse/lifecycle/quality/humanization}/skills/capture-ai-flavor-cases/references/case-card-contract.md (100%) rename {.agent => muse/lifecycle/quality/humanization}/skills/capture-ai-flavor-cases/references/fixtures/README.md (67%) rename {.agent => muse/lifecycle/quality/humanization}/skills/capture-ai-flavor-cases/references/fixtures/backfill-hash-only.yaml (100%) rename {.agent => muse/lifecycle/quality/humanization}/skills/capture-ai-flavor-cases/references/fixtures/canonical-samples.yaml (100%) rename {.agent => muse/lifecycle/quality/humanization}/skills/capture-ai-flavor-cases/references/fixtures/rule-candidates.yaml (100%) rename {.agent => muse/lifecycle/quality/humanization}/skills/capture-ai-flavor-cases/scripts/capture_cases.py (100%) rename {.agent => muse/lifecycle/quality/humanization}/skills/capture-ai-flavor-cases/scripts/persist_cases.py (100%) rename {.agent => muse/lifecycle/quality/humanization}/skills/diagnose-ai-flavor/SKILL.md (100%) rename {.agent => muse/lifecycle/quality/humanization}/skills/diagnose-ai-flavor/scripts/diagnose_ai_flavor.py (100%) rename {.agent => muse/lifecycle/quality/humanization}/skills/establish-voice-baseline/SKILL.md (100%) rename {.agent => muse/lifecycle/quality/humanization}/skills/establish-voice-baseline/scripts/establish_voice_baseline.py (100%) rename {.agent => muse/lifecycle/quality/humanization}/skills/prevent-ai-flavor/SKILL.md (100%) rename {.agent => muse/lifecycle/quality/humanization}/skills/prevent-ai-flavor/scripts/prevent_ai_flavor.py (100%) rename {.agent => muse/lifecycle/quality/humanization}/skills/promote-ai-flavor-rule/SKILL.md (83%) rename {.agent => muse/lifecycle/quality/humanization}/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py (100%) rename {.agent => muse/lifecycle/quality/humanization}/skills/revise-ai-flavor/SKILL.md (100%) rename {.agent => muse/lifecycle/quality/humanization}/skills/revise-ai-flavor/scripts/revise_ai_flavor.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/src/deai/__init__.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/src/deai/baseline.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/src/deai/cards.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/src/deai/carriers.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/src/deai/diagnose.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/src/deai/evaluation.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/src/deai/gates.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/src/deai/load.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/src/deai/load_db.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/src/deai/pairwise.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/src/deai/patch.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/src/deai/pipeline.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/src/deai/report.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/src/deai/schemas.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/tests/__init__.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/tests/test_contracts.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/tests/test_framework_coverage.py (86%) rename {humanization => muse/lifecycle/quality/humanization}/tests/test_humanization_v2.py (98%) rename {humanization => muse/lifecycle/quality/humanization}/tests/test_load_db.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/tests/test_load_db_pg_smoke.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/tests/test_seed_rules_db.py (100%) rename {humanization => muse/lifecycle/quality/humanization}/tools/seed_rules_db.py (100%) rename {.agent/skills => muse/lifecycle/quality/skills/judge}/optimize-content-quality/SKILL.md (94%) rename {.agent/skills => muse/lifecycle/quality/skills/judge}/score-content-quality/SKILL.md (100%) rename {.agent/skills => muse/lifecycle/quality/skills/judge}/score-content-quality/scripts/dispatch_judge_bridge.py (93%) rename {.agent/skills => muse/lifecycle/quality/skills/judge}/score-content-quality/scripts/fine_outline_rubric.py (100%) rename {.agent/skills => muse/lifecycle/quality/skills/judge}/score-content-quality/scripts/judge_via_dispatch.py (97%) rename {.agent/skills => muse/lifecycle/quality/skills/judge}/score-content-quality/scripts/run_writer_blind_judge.py (100%) rename {.agent/skills => muse/lifecycle/quality/skills/judge}/score-content-quality/scripts/writer_rubric.py (100%) rename {.agent/skills => muse/lifecycle/quality/skills/mechanical}/adjudicate-quality-gate/SKILL.md (100%) rename {.agent/skills => muse/lifecycle/quality/skills/mechanical}/adjudicate-quality-gate/scripts/gate_input_builder.py (99%) rename {.agent/skills => muse/lifecycle/quality/skills/mechanical}/adjudicate-quality-gate/scripts/writer_gate.py (100%) rename {.agent/skills => muse/lifecycle/quality/skills/replay}/evaluate-frozen-replay/SKILL.md (95%) rename {.agent/skills => muse/lifecycle/quality/skills/replay}/evaluate-frozen-replay/scripts/fine_outline_detector.py (100%) rename {.agent/skills => muse/lifecycle/quality/skills/replay}/evaluate-frozen-replay/scripts/run_replay.py (98%) rename {.agent/skills => muse/lifecycle/quality/skills/replay}/evaluate-frozen-replay/scripts/write_report.py (100%) rename {.agent/skills => muse/lifecycle/quality/skills/replay}/load-replay-reference-work/SKILL.md (100%) rename {.agent/skills => muse/lifecycle/quality/skills/replay}/load-replay-reference-work/scripts/load_writer_reference_work.py (99%) rename {.agent/skills => muse/lifecycle/quality/skills/replay}/replay-writer-gate/SKILL.md (97%) rename {.agent/skills => muse/lifecycle/quality/skills/replay}/replay-writer-gate/configs/writer-gate-a-deep-space-card-selectors-v1.json (100%) rename {.agent/skills => muse/lifecycle/quality/skills/replay}/replay-writer-gate/configs/writer-gate-a-deep-space-v1.json (100%) rename {.agent/skills => muse/lifecycle/quality/skills/replay}/replay-writer-gate/scripts/run_writer_replay/__init__.py (100%) rename {.agent/skills => muse/lifecycle/quality/skills/replay}/replay-writer-gate/scripts/run_writer_replay/__main__.py (100%) rename {.agent/skills => muse/lifecycle/quality/skills/replay}/replay-writer-gate/scripts/run_writer_replay/_common.py (90%) rename {.agent/skills => muse/lifecycle/quality/skills/replay}/replay-writer-gate/scripts/run_writer_replay/authorization.py (99%) rename {.agent/skills => muse/lifecycle/quality/skills/replay}/replay-writer-gate/scripts/run_writer_replay/blind.py (100%) rename {.agent/skills => muse/lifecycle/quality/skills/replay}/replay-writer-gate/scripts/run_writer_replay/budget.py (100%) rename {.agent/skills => muse/lifecycle/quality/skills/replay}/replay-writer-gate/scripts/run_writer_replay/execute.py (100%) rename {.agent/skills => muse/lifecycle/quality/skills/replay}/replay-writer-gate/scripts/run_writer_replay/sample.py (100%) rename {.agent/skills => muse/lifecycle/quality/skills/replay}/replay-writer-gate/scripts/writer_eval_preregister.py (100%) rename {.agent/skills => muse/lifecycle/quality/skills/semantic}/check-content-consistency/SKILL.md (100%) rename {.agent/skills => muse/lifecycle/quality/skills/semantic}/check-content-consistency/scripts/check_writer_candidate.py (100%) rename {.agent/skills => muse/lifecycle/quality/skills/semantic}/check-content-consistency/scripts/run_writer_semantic_detector.py (100%) rename {muse-db => muse/platform/db}/pyproject.toml (100%) rename {muse-db => muse/platform/db}/src/muse_db/__init__.py (100%) rename {muse-embed => muse/platform/embed}/pyproject.toml (100%) rename {muse-embed => muse/platform/embed}/src/muse_embed.py (100%) rename {muse-llm => muse/platform/llm}/pyproject.toml (100%) rename {.agent => muse/platform/llm}/skills/call-content-model/SKILL.md (92%) rename {.agent => muse/platform/llm}/skills/call-content-model/scripts/llm.py (100%) rename {.agent => muse/platform/llm}/skills/execute-role-task/SKILL.md (100%) rename {.agent => muse/platform/llm}/skills/refresh-runtime-probe/SKILL.md (93%) rename {.agent => muse/platform/llm}/skills/refresh-runtime-probe/scripts/refresh_runtime_probe.py (96%) rename {muse-llm => muse/platform/llm}/src/muse_llm.py (100%) rename {muse-llm => muse/platform/llm}/src/muse_role.py (100%) rename {muse-llm => muse/platform/llm}/src/muse_role_contract.py (98%) rename {.agent/docs/architecture => muse/sot}/_index.md (100%) rename {.agent/docs/architecture => muse/sot}/domains/01-作品领域.md (98%) rename {.agent/docs/architecture => muse/sot}/domains/02-实体领域.md (84%) rename {.agent/docs/architecture => muse/sot}/domains/03-范式领域.md (93%) rename {.agent/docs/architecture => muse/sot}/domains/04-上下文领域.md (94%) rename {.agent/docs/architecture => muse/sot}/domains/05-创作流程领域.md (83%) rename {.agent/docs/architecture => muse/sot}/domains/06-质量与复利领域.md (83%) rename {.agent/docs/architecture => muse/sot}/domains/07-Agent与Skill领域.md (86%) rename {.agent/docs/architecture => muse/sot}/domains/08-数据权威与可视化领域.md (95%) rename {.agent/docs/architecture => muse/sot}/domains/_index.md (86%) rename {.agent/docs/architecture => muse/sot}/创作周期与Skill导读.md (56%) rename {.agent/docs/architecture => muse/sot}/可视化模块合同.md (91%) rename {.agent/docs/architecture => muse/sot}/角色合同.md (100%) rename {.agent/docs/architecture => muse/sot}/边界合同.md (97%) create mode 100644 tests/architecture/test_dsh_adapter.py create mode 100644 tests/architecture/test_framework_port_purity.py create mode 100644 tests/architecture/test_framework_protocol.py create mode 100644 tests/architecture/test_markdown_links.py create mode 100644 tests/architecture/test_skill_projections.py diff --git a/.agent/_index.md b/.agent/_index.md index ea4a58d..cda1203 100644 --- a/.agent/_index.md +++ b/.agent/_index.md @@ -1,9 +1,10 @@ # agent-example 长期知识索引 -- [项目长期文档](docs/_index.md) -- [Skill 发现总索引](skills/_index.md) +- [Muse SoT](../muse/sot/_index.md) +- [Skill 方法发现总索引](skills/_index.md) +- [Skill 编排索引](../muse/_skills_index.md) - [角色身份提示](agents/)(writer / planner / extractor / detector / judge) -- [角色合同](docs/architecture/角色合同.md)(稳定角色边界、模型策略与派发合同唯一事实源) -- [边界合同](docs/architecture/边界合同.md)(组件职责边界与约束归属唯一事实源) +- [角色合同](../muse/sot/角色合同.md)(稳定角色边界、模型策略与派发合同唯一事实源) +- [边界合同](../muse/sot/边界合同.md)(组件职责边界与约束归属唯一事实源) 项目入口与协作规则仍由根目录 [`AGENTS.md`](../AGENTS.md) 拥有;本目录只保存跨任务稳定知识。 diff --git a/.agent/docs/_index.md b/.agent/docs/_index.md index 740fcdd..5bb0bbe 100644 --- a/.agent/docs/_index.md +++ b/.agent/docs/_index.md @@ -1,4 +1,5 @@ # 长期文档索引 -- [架构](architecture/_index.md),包含 [角色合同](architecture/角色合同.md) -- [创作周期与 Skill 导读](architecture/创作周期与Skill导读.md)(教学地图,不是合同权威) +领域与架构 SoT 已迁至 [`../../muse/sot/_index.md`](../../muse/sot/_index.md)。 + +方法 Skill 发现见 [`../_index.md`](../_index.md)。 diff --git a/.agent/skills/_index.md b/.agent/skills/_index.md index 9788682..3dfe30f 100644 --- a/.agent/skills/_index.md +++ b/.agent/skills/_index.md @@ -1,110 +1,42 @@ -# Skill 发现总索引 +# Skill 方法发现总索引 -> **发现合同**:任何 agent(不限宿主)读 [`AGENTS.md`](../../AGENTS.md) 后必须读本索引,需要某项能力时按 `skill_file` 读对应 `SKILL.md`。发现只靠 AGENTS.md → 本索引 → SKILL.md 的渐进披露,不依赖任何 coding agent 的 skill 自动发现;物理目录位置只是索引里的数据。 +> **发现合同**:任何 agent(不限宿主)读 [`AGENTS.md`](../../AGENTS.md) 后必须读本索引,需要某项能力时按 `skill_file` 读对应 `SKILL.md`。发现只靠 AGENTS.md → 本索引 → SKILL.md 的渐进披露,不依赖任何 coding agent 的 skill 自动发现;物理目录位置完全取自 manifest 的 `skill_path`,允许嵌套。 -本索引只登记三字段:`skill_name`(目录名,即调用名)、`skill_file`(合同文件路径)、`skill_description`(适用与边界描述,与 SKILL.md frontmatter 逐字一致,frontmatter 是 SoT)。分类字段(`lifecycle` / `invocation` / `side_effects` / `compounding`)逐个登记在 [`harness/manifests/skills.json`](../../harness/manifests/skills.json),由 `harness/skill_harness.py` 机械校验,不在本索引重复。 +本索引只登记三字段:`skill_name`(目录名,即调用名)、`skill_file`(合同文件路径)、`skill_description`(适用与边界描述,与 SKILL.md frontmatter 逐字一致,frontmatter 是 SoT)。分类字段(`lifecycle` / `invocation` / `side_effects` / `compounding`)逐个登记在 [`muse/lifecycle/quality/harness/manifests/skills.json`](../../muse/lifecycle/quality/harness/manifests/skills.json),由 `muse/lifecycle/quality/harness/skill_harness.py` 机械校验,不在本索引重复。 -本文件由 `harness/skills_index.py --write` 生成,手改会被覆盖;一致性由 `--check` 与 `tests/architecture/test_skills_index.py` 机械把关。按生命周期分域,共 58 个 skill。 - -## 0 平台底座 - -| skill_name | skill_file | skill_description | -|---|---|---| -| access-database | `.agent/skills/access-database/SKILL.md` | 通过唯一受控入口查询或修改 muse-example PostgreSQL,并应用可审计 DDL。主会话或 Skill 需要通用数据库访问时使用;专用导入、嵌入和检索仍走各自 Skill,禁止裸连和一次性脚本。 | -| call-content-model | `.agent/skills/call-content-model/SKILL.md` | 通过 New-API 的统一治理入口调用内容模型,执行额度窗口、模型降级、重试和 JSON 提取。清洗、拆书或知识审核需要 MiniMax 等内容模型时使用;不得裸调外部服务。 | -| dispatch-agent-task | `.agent/skills/dispatch-agent-task/SKILL.md` | 把冻结角色任务包派发给 Agent 框架子代理执行并自动留痕:注入角色 prompt 与输出 Schema、按白名单开放工具、归一框架事件流写入代理事件账本,结构化输出经 Draft 2020-12 校验后返回回执。任何 Agent 框架(当前 pi)执行 writer/planner/detector/judge/extractor 角色任务时使用;不经框架的直接 HTTP 批处理走 execute-role-task;本 Skill 不做补证、重写等业务决策。 | -| execute-role-task | `.agent/skills/execute-role-task/SKILL.md` | 以冻结 RoleExecutionProfile 运行一次不经框架的直接 HTTP 角色调用,校验模型策略、期限、预算、结构和输入输出哈希并返回 RoleExecutionReceipt。writer、planner、extractor、detector 或 judge 的无工具批处理需要直接模型调用时使用;需要框架原生 ReAct/工具循环的子代理执行走 dispatch-agent-task;能力探针刷新交给 refresh-runtime-probe,本 Skill 不负责保存 raw、登记运行或裁决业务结果。 | -| record-run-evidence | `.agent/skills/record-run-evidence/SKILL.md` | 记录模型调用、运行登记、不可变回执、CAS revision 和受控 raw 证据。执行器或业务 Skill 需要持久化一次运行、追加失败证据、补回执引用或管理 raw 备份时使用;不负责调用模型或裁决内容质量。 | -| refresh-runtime-probe | `.agent/skills/refresh-runtime-probe/SKILL.md` | 通过 execute-role-task 用当前 writer 提示词、结构和档案实跑一次极小合成角色任务,刷新运行探针记录与自哈希并把完整配置写到新文件。角色合同或运行时、模型策略版本变化导致执行门失败时使用;不就地覆盖原配置,不把离线预览伪装成成功证明。 | - -## 1 素材导入与拆解 - -| skill_name | skill_file | skill_description | -|---|---|---| -| backup-work-extraction | `.agent/skills/backup-work-extraction/SKILL.md` | 对单本作品的 upgrade_book 派生状态做七域一致性备份、离线复验、回滚演练与精确恢复。需要在重置或高危维护前留下可复验快照、或需要把作品抽取状态恢复到某个备份点时使用;不负责重置、定向修复和正常按窗抽取。 | -| clean-book-text | `.agent/skills/clean-book-text/SKILL.md` | 识别并删除参考书或旧稿中的广告、水印、作者拉票和乱码噪声,同时保留逐段审计。静态导入后仍有语义垃圾时使用;模型只提候选,确定性守卫决定是否删除,绝不改写正文。首次 txt 分章落库归 import-book;本 Skill 只在已有 block 上做语义噪声清洗。 | -| deconstruct-book | `.agent/skills/deconstruct-book/SKILL.md` | 从完整存量作品逆向拆出章节细纲、阶段大纲、实体线索和脱敏写作范式。需要解析用户旧稿或参考书全书时使用;不负责把作品面知识按窗升格,也不确认产物。 | -| extract-work-knowledge | `.agent/skills/extract-work-knowledge/SKILL.md` | 将已完成拆解的作品正文按窗口抽取为 upgrade_book 实体、关系与演变草稿。作品完成拆书后需要建立本书知识面、续跑抽取窗口或查看抽取进度时使用;备份/恢复归 backup-work-extraction,全量重置归 reset-work-extraction,定向修复/迁移归 repair-work-extraction,本 Skill 不负责这三类维护。 | -| import-book | `.agent/skills/import-book/SKILL.md` | 将参考书或用户旧稿 txt 确定性分章并写入作品、章节、正文 block 和来源档案。首次导入完整书稿或明确重导时使用;不调用模型、不改写正文。导入后散落广告/乱码/拉票等语义噪声归 clean-book-text,本 Skill 不做 M3 探测删除。 | -| inspect-parse-health | `.agent/skills/inspect-parse-health/SKILL.md` | 只读体检拆书与升格两条管线的终态,并导出范式卡与升格实体卡样张。需要在一批跑完后机械核对章级细纲、窗级大纲、范式出卡和作品面升格四层健康度、或需要呈报样张时使用;不负责解析、抽取和任何修复动作。 | -| repair-work-extraction | `.agent/skills/repair-work-extraction/SKILL.md` | 对已有 upgrade_book 抽取结果做定向修复与存量迁移,包括 legacy failed 窗口恢复、单卡质量修复、presence 重复清理、存量窗口章号定位和存量回洗。需要修补个别窗口或行而不是重跑全书时使用;正常按窗抽取归 extract-work-knowledge,全量重置归 reset-work-extraction,备份恢复归 backup-work-extraction。 | -| reset-work-extraction | `.agent/skills/reset-work-extraction/SKILL.md` | 全量重抽前预览或清空单本作品的 upgrade_book 派生状态,把窗口退回 pending。需要对一本书重新跑一遍作品面抽取时使用;正常按窗抽取归 extract-work-knowledge,定向修复归 repair-work-extraction,备份恢复归 backup-work-extraction。 | - -## 2 知识与上下文供给 - -| skill_name | skill_file | skill_description | -|---|---|---| -| assemble-context | `.agent/skills/assemble-context/SKILL.md` | 按冻结点从 PostgreSQL 读取可信来源,组装可审计上下文,并为 writer、detector、judge、planner 或 extractor 生成最小投影。创作或评测调用模型前需要受控上下文时使用。 | -| embed-knowledge | `.agent/skills/embed-knowledge/SKILL.md` | 使用固定 Qwen3 嵌入模型将知识草稿或实体批量写入 pgvector,并按内容哈希幂等处理 owner 与版本。知识行需要建立或刷新检索向量时使用;不嵌入参考书全文。 | -| extract-chapter-knowledge | `.agent/skills/extract-chapter-knowledge/SKILL.md` | 从已接受章节抽取实体、关系、事件和叙事状态草稿,并提出既有知识更新。正文进入 Canonical 后需要章后增量知识时使用;只产草稿,不自动确认知识。 | -| freeze-context | `.agent/skills/freeze-context/SKILL.md` | 将截至指定章号的来源冻结为可重复清单,并校验授权、版本、未来信息泄漏和只读原文装载。上下文组装或回放评测需要稳定时间边界时使用;不调用模型、不写正式数据。 | -| review-knowledge-cards | `.agent/skills/review-knowledge-cards/SKILL.md` | 以三种编辑视角审核公共知识卡的成立性、创作可用性和跨书复用性,并写回 pass、revise 或 reject。拆书产出公共卡后使用;不负责生成卡或确认作品私有知识。 | -| search-knowledge | `.agent/skills/search-knowledge/SKILL.md` | 将创作意图嵌入后从 pgvector 召回知识,并按绑定、状态和 aiContext 权限裁剪结果。管理审查或上下文组装需要知识候选时使用;不返回参考书全文,不绕过作品绑定。 | +本文件由 `muse/lifecycle/quality/harness/skills_index.py --write` 生成,手改会被覆盖;一致性由 `--check` 与 `tests/architecture/test_skills_index.py` 机械把关。按生命周期分域,共 15 个 skill。 ## 3 概念与前期设计 | skill_name | skill_file | skill_description | |---|---|---| -| concept-design | `.agent/skills/concept-design/SKILL.md` | 激活场景:用户手里只有模糊 idea、真实素材或"写了一半散掉"的稿子,还没形成能撑长篇的概念——"我想写 X 但不知道够不够"、"我的点子太平"、"题材写烂了,我没新意"、"真实事件想写成小说"、"朋友问小说讲什么我答不上来"、"写到一半故事散了"、"教学生怎么从 idea 到 concept"(教学演示)、"我有 3 个 idea,哪个最有潜力"(比较选择)、"朋友推荐我写 X,怎么判断值不值得"(第三方评估)、"真实人物的真实经历(传记/回忆录)怎么让它有 concept"、"读到一本好书/好新闻,想改写成小说"(非虚构改编)。关键 trigger:"what if / 把 idea 变成 concept / 升级点子 / 故事种子 / premise / 这个点子够不够 /这个点子能写成小说吗 / 能撑 30 万字吗 / 哪个 idea 最有潜力 / 题材写烂了 / 我没新意 / 和别人一样 /我必须想新点子 / 真实事件写小说 / 历史题材 / 传记 / 回忆录 / 非虚构改编 / 叙事策略 / 通过谁的眼睛讲 /故事引擎 / story engine / 核心问题 / 小说在回答什么问题 / 中段失去方向 / 写到一半散了 / 故事没有主心骨"。不适用于:纯抒情散文与反结构实验小说(问题引擎合法缺席);要求严格 1:1 复刻真实的新闻报道;概念已定之后的结构诊断(见 story-structure);写作习惯、心理状态等作者培养问题。与 story-planning 交接:用户第一句话只有模糊 idea / 素材 / 引擎不清 → 本 Skill;概念已定、要做节拍表/工作流 → story-planning。 | -| design-story-foundation | `.agent/skills/design-story-foundation/SKILL.md` | 在正式规划前固化作品根设定,按固定三级章节树生成可比较的前期设计候选。用户仍在单文档前期设计阶段时使用;不写正文、不落库、不替用户定稿。不适用于合并多案(归 merge-story-candidates)或正式规划落库(归 plan-story)。 | -| merge-story-candidates | `.agent/skills/merge-story-candidates/SKILL.md` | 把多份已完成的前期设计候选逐章串行统合成一份新候选,一级章节一个 fresh 代理,权威顺序固定为根设定优先。用户明确要求综合多案时使用;不生成候选、不做机械门校验、不改前期设计 SoT。 | +| concept-design | `.agent/skills/planning/concept-design/SKILL.md` | 激活场景:用户手里只有模糊 idea、真实素材或"写了一半散掉"的稿子,还没形成能撑长篇的概念——"我想写 X 但不知道够不够"、"我的点子太平"、"题材写烂了,我没新意"、"真实事件想写成小说"、"朋友问小说讲什么我答不上来"、"写到一半故事散了"、"教学生怎么从 idea 到 concept"(教学演示)、"我有 3 个 idea,哪个最有潜力"(比较选择)、"朋友推荐我写 X,怎么判断值不值得"(第三方评估)、"真实人物的真实经历(传记/回忆录)怎么让它有 concept"、"读到一本好书/好新闻,想改写成小说"(非虚构改编)。关键 trigger:"what if / 把 idea 变成 concept / 升级点子 / 故事种子 / premise / 这个点子够不够 /这个点子能写成小说吗 / 能撑 30 万字吗 / 哪个 idea 最有潜力 / 题材写烂了 / 我没新意 / 和别人一样 /我必须想新点子 / 真实事件写小说 / 历史题材 / 传记 / 回忆录 / 非虚构改编 / 叙事策略 / 通过谁的眼睛讲 /故事引擎 / story engine / 核心问题 / 小说在回答什么问题 / 中段失去方向 / 写到一半散了 / 故事没有主心骨"。不适用于:纯抒情散文与反结构实验小说(问题引擎合法缺席);要求严格 1:1 复刻真实的新闻报道;概念已定之后的结构诊断(见 story-structure);写作习惯、心理状态等作者培养问题。与 story-planning 交接:用户第一句话只有模糊 idea / 素材 / 引擎不清 → 本 Skill;概念已定、要做节拍表/工作流 → story-planning。 | ## 4 结构与规划 | skill_name | skill_file | skill_description | |---|---|---| -| foreshadow-payoff | `.agent/skills/foreshadow-payoff/SKILL.md` | 小说写作的伏笔与回收方法:把显著元素登记成债务、把铺垫埋得自然、让兑现从已埋细节生长出来。当用户说"埋了没收""线索失踪""伏笔太突兀""这个细节是装饰还是债务""契诃夫之枪怎么用""伏笔怎么分层""兑现时间表",或明确在谈埋/收/铺垫链、特殊人物出场前的台阶时激活。关键 trigger:"伏笔" / "回收" / "铺垫" / "契诃夫之枪" / "chekhov's gun" / "foreshadow" /"线索失踪" / "埋了没收" / "承诺不兑现" / "前面挖的坑没填" / "删除测试" / "伏笔分层" /"短期伏笔 / 中期伏笔 / 长期伏笔" / "兑现时间表" / "伏笔台账" / "修楼梯" / "Hitchcock 变体" /"显眼的凶器" / "预暴露的伏笔" / "前后呼应" / "高潮从天而降(欠债未兑)"。不适用于:仅问「高潮怎么写」「反转怎么设计」「大场面怎么拍」而无埋/收/契诃夫语境(归 scene-craft / story-structure / story-ending);散文/随笔(无情节承兑机制)、纯意识流/氛围小说(无情节闭环压力,元素出现又消失是合法的)、解构/反小说(刻意让伏笔不兑现正是其目的)、需要大场面直接冲击的灾难/战争场景、1000 字以下超短篇(没有埋设与生长的空间;1500 字以下不需要分层)。与 scene-craft 交接:单场景高潮执行(使命/镜头/进出)归 scene-craft;本 Skill 只管债务登记与兑现链。与 story-ending 交接:终局姿态与倒推收束归 story-ending;本 Skill 只保证前文债务可兑。 | -| narrative-momentum | `.agent/skills/narrative-momentum/SKILL.md` | 写或改长篇小说、网文连载、章节体故事遇到动力问题时激活:情节推不动、事件之间接不上、中段塌陷读者弃读、章末平淡翻不下去、高潮不爆。三台发动机:给事件接因果推力链(造势)、沿途埋小奖励(金币)、在断点挂未解问题(内悬念)。关键 trigger:造势 / 势 / 推力 / 情节推不动 / 情节跳跃 / 高潮不爆 / 中段无力 /中段塌陷且读者弃读 / sagging middle / 读者弃读 / 金币 / 沿途埋金 / gold coin /章末钩子 / 段末悬念 / 卷末悬念 / internal cliffhanger / 内悬念 / 钩子 / 怎么让读者翻下去 / 付费点钩子。(裸「中段塌陷」无弃读/钩子语境时先查 story-structure)不适用于:抒情散文与诗(没有叙事路径和断点);意识流、反悬念的实验叙事(靠情绪流,不靠势与钩子);新闻报道(倒金字塔结构)。沿途埋金不适用于 1 万字以下短篇(没有中段可埋);造势与断点钩子对短篇仍适用(势链要短要密)。与 story-structure 交接:中段塌陷若来自里程碑错位/赌注不升,先查 story-structure;本 Skill 只管读者动力(势/金币/钩子)。 | -| plan-chapter | `.agent/skills/plan-chapter/SKILL.md` | 根据已确认规划、叙事状态和冻结事实生成下一章结构细纲草稿。正文生成前需要明确章目标、事件因果、出场实体、伏笔动作和章末钩子时使用;不写正文、不读取目标章答案。书级设定/大纲/装配归 plan-story;本 Skill 是 section_type=fine_outline 的唯一写入方(经 persist_planning.py --owner-skill plan-chapter)。 | -| plan-story | `.agent/skills/plan-story/SKILL.md` | 按正式 schema 生成或修订作品设定包、大纲、知识卡、状态和装配草稿。前期方向已由用户选定并进入正式规划,或续作需要调整规划时使用;不写正文,未确认产物不进入生成上下文。单章 fine_outline(含 writer 硬依赖字段)只归 plan-chapter;本 Skill 不得写入 section_type=fine_outline。 | -| story-ending | `.agent/skills/story-ending/SKILL.md` | 小说收尾阶段激活。当用户问"结尾怎么写"、担心烂尾、觉得最后几章拖尾或结尾无力、在开放式与闭合式结局之间拿不定主意、想从终局倒推前文、系列小说要协调本集结局与系列结局、或需要判断读者读完是"被关起来"还是"被打开"时使用。关键 trigger:"怎么结尾" / "收尾" / "烂尾" / "拖尾" / "结尾无力" / "结尾策略" / "结局设计" /"倒推" / "从最后一章写起" / "chain of execution" / "完成还是打开" / "收束还是扩展" /"戛然而止" / "意犹未尽" / "被关起来" / "被打开" / "ending"。不适用于:以"无结尾"本身为表达的开放实验文学与反叙事解构作品、短抒情诗与散文、刻意反高潮的平铺直叙、必须闭环的事务性场景(合同签署、手术完成、机器启动)与必须收束的紧急信息("立即撤离"类)。与 foreshadow-payoff 交接:收束前未兑伏笔债归 foreshadow-payoff;终局姿态与倒推路径归本 Skill。与 story-structure 交接:全书里程碑/四箱/中段结构成因归 story-structure;只谈收尾姿态用本 Skill。与 narrative-momentum 交接:结尾前金币/势/弃读归后者。 | -| story-planning | `.agent/skills/story-planning/SKILL.md` | 激活场景:用户在规划新故事、做故事蓝图或节拍表;纠结"凭灵感写还是按计划写";有一个想法想变成完整故事;凭灵感写作卡在中段、故事乱、不知道接下来写什么;写完一稿想诊断故事哪里出了问题。关键 trigger:"节拍表 / beat sheet / 什么是节拍表 / 节拍表是什么 / 故事大纲 / 故事规划 / story planning /故事蓝图 / 写之前要做什么 / 我应该怎么规划故事 / 灵感写作 / pantsing / 计划写作 / plotting / 凭灵感写 /凭感觉写 / 短篇怎么开始 / 小说怎么写 / 故事写作步骤 / 我想写小说 / 我有一个想法 / 怎么把想法变成完整故事 /故事没头没尾 / 卡在故事中段 / 接下来写什么 / 写到第 5 稿还在找故事"。不适用于:故事结构本身的定义(四箱、六里程碑见 story-structure);场景、对话、叙述层面的改稿技巧;作者日常写作习惯与心态调节;非虚构写作;实验性非线性写作(节拍表假设线性)。与 concept-design 交接:只有模糊 idea、引擎不清 → concept-design;概念已定、要节拍表与工作流 → 本 Skill。 | -| story-structure | `.agent/skills/story-structure/SKILL.md` | 激活场景: 为长篇/中篇小说或剧本搭结构骨架、改稿时做结构诊断、判断开头与关键节点该放在哪、处理"中段塌陷""故事没启动""赌注不升""开头抓不住读者"等结构问题、写前确认短中长篇体裁。关键 trigger: "故事结构 / 四箱 / 三幕 / 6 里程碑 / first plot point / FPP / 第一情节点 / midpoint / 中点 /煽动事件 / inciting incident / 触发事件 / Setup 段 / 开篇五件事 / 中段塌陷 / 赌注没升 / up the ante /不知道怎么开头 / 想不到第一句 / 开头抓不住读者 / 开头没冲突 / 主角的日常没被打破 / 开头像介绍背景 /短中长篇体制 / 主角转主动 / 主角太英雄 / 故事节奏 / pinch point / 夹点 / 故事没启动"。不适用于: 非叙事内容(纯数据/公文)、没有可识别人物主角线的纯设定集、意识流与抒情散文(不靠外部事件推动)、新闻导语与学术摘要类非虚构开头、单场景内的微观写作(归 scene-craft)、作者写作习惯与心理状态(作者培养类)。与 narrative-momentum 交接:「中段塌陷」的结构成因(里程碑/赌注/四箱)归本 Skill;弃读、章末钩子、势链/金币/内悬念归后者。 | +| foreshadow-payoff | `.agent/skills/planning/foreshadow-payoff/SKILL.md` | 小说写作的伏笔与回收方法:把显著元素登记成债务、把铺垫埋得自然、让兑现从已埋细节生长出来。当用户说"埋了没收""线索失踪""伏笔太突兀""这个细节是装饰还是债务""契诃夫之枪怎么用""伏笔怎么分层""兑现时间表",或明确在谈埋/收/铺垫链、特殊人物出场前的台阶时激活。关键 trigger:"伏笔" / "回收" / "铺垫" / "契诃夫之枪" / "chekhov's gun" / "foreshadow" /"线索失踪" / "埋了没收" / "承诺不兑现" / "前面挖的坑没填" / "删除测试" / "伏笔分层" /"短期伏笔 / 中期伏笔 / 长期伏笔" / "兑现时间表" / "伏笔台账" / "修楼梯" / "Hitchcock 变体" /"显眼的凶器" / "预暴露的伏笔" / "前后呼应" / "高潮从天而降(欠债未兑)"。不适用于:仅问「高潮怎么写」「反转怎么设计」「大场面怎么拍」而无埋/收/契诃夫语境(归 scene-craft / story-structure / story-ending);散文/随笔(无情节承兑机制)、纯意识流/氛围小说(无情节闭环压力,元素出现又消失是合法的)、解构/反小说(刻意让伏笔不兑现正是其目的)、需要大场面直接冲击的灾难/战争场景、1000 字以下超短篇(没有埋设与生长的空间;1500 字以下不需要分层)。与 scene-craft 交接:单场景高潮执行(使命/镜头/进出)归 scene-craft;本 Skill 只管债务登记与兑现链。与 story-ending 交接:终局姿态与倒推收束归 story-ending;本 Skill 只保证前文债务可兑。 | +| narrative-momentum | `.agent/skills/planning/narrative-momentum/SKILL.md` | 写或改长篇小说、网文连载、章节体故事遇到动力问题时激活:情节推不动、事件之间接不上、中段塌陷读者弃读、章末平淡翻不下去、高潮不爆。三台发动机:给事件接因果推力链(造势)、沿途埋小奖励(金币)、在断点挂未解问题(内悬念)。关键 trigger:造势 / 势 / 推力 / 情节推不动 / 情节跳跃 / 高潮不爆 / 中段无力 /中段塌陷且读者弃读 / sagging middle / 读者弃读 / 金币 / 沿途埋金 / gold coin /章末钩子 / 段末悬念 / 卷末悬念 / internal cliffhanger / 内悬念 / 钩子 / 怎么让读者翻下去 / 付费点钩子。(裸「中段塌陷」无弃读/钩子语境时先查 story-structure)不适用于:抒情散文与诗(没有叙事路径和断点);意识流、反悬念的实验叙事(靠情绪流,不靠势与钩子);新闻报道(倒金字塔结构)。沿途埋金不适用于 1 万字以下短篇(没有中段可埋);造势与断点钩子对短篇仍适用(势链要短要密)。与 story-structure 交接:中段塌陷若来自里程碑错位/赌注不升,先查 story-structure;本 Skill 只管读者动力(势/金币/钩子)。 | +| story-ending | `.agent/skills/planning/story-ending/SKILL.md` | 小说收尾阶段激活。当用户问"结尾怎么写"、担心烂尾、觉得最后几章拖尾或结尾无力、在开放式与闭合式结局之间拿不定主意、想从终局倒推前文、系列小说要协调本集结局与系列结局、或需要判断读者读完是"被关起来"还是"被打开"时使用。关键 trigger:"怎么结尾" / "收尾" / "烂尾" / "拖尾" / "结尾无力" / "结尾策略" / "结局设计" /"倒推" / "从最后一章写起" / "chain of execution" / "完成还是打开" / "收束还是扩展" /"戛然而止" / "意犹未尽" / "被关起来" / "被打开" / "ending"。不适用于:以"无结尾"本身为表达的开放实验文学与反叙事解构作品、短抒情诗与散文、刻意反高潮的平铺直叙、必须闭环的事务性场景(合同签署、手术完成、机器启动)与必须收束的紧急信息("立即撤离"类)。与 foreshadow-payoff 交接:收束前未兑伏笔债归 foreshadow-payoff;终局姿态与倒推路径归本 Skill。与 story-structure 交接:全书里程碑/四箱/中段结构成因归 story-structure;只谈收尾姿态用本 Skill。与 narrative-momentum 交接:结尾前金币/势/弃读归后者。 | +| story-planning | `.agent/skills/planning/story-planning/SKILL.md` | 激活场景:用户在规划新故事、做故事蓝图或节拍表;纠结"凭灵感写还是按计划写";有一个想法想变成完整故事;凭灵感写作卡在中段、故事乱、不知道接下来写什么;写完一稿想诊断故事哪里出了问题。关键 trigger:"节拍表 / beat sheet / 什么是节拍表 / 节拍表是什么 / 故事大纲 / 故事规划 / story planning /故事蓝图 / 写之前要做什么 / 我应该怎么规划故事 / 灵感写作 / pantsing / 计划写作 / plotting / 凭灵感写 /凭感觉写 / 短篇怎么开始 / 小说怎么写 / 故事写作步骤 / 我想写小说 / 我有一个想法 / 怎么把想法变成完整故事 /故事没头没尾 / 卡在故事中段 / 接下来写什么 / 写到第 5 稿还在找故事"。不适用于:故事结构本身的定义(四箱、六里程碑见 story-structure);场景、对话、叙述层面的改稿技巧;作者日常写作习惯与心态调节;非虚构写作;实验性非线性写作(节拍表假设线性)。与 concept-design 交接:只有模糊 idea、引擎不清 → concept-design;概念已定、要节拍表与工作流 → 本 Skill。 | +| story-structure | `.agent/skills/planning/story-structure/SKILL.md` | 激活场景: 为长篇/中篇小说或剧本搭结构骨架、改稿时做结构诊断、判断开头与关键节点该放在哪、处理"中段塌陷""故事没启动""赌注不升""开头抓不住读者"等结构问题、写前确认短中长篇体裁。关键 trigger: "故事结构 / 四箱 / 三幕 / 6 里程碑 / first plot point / FPP / 第一情节点 / midpoint / 中点 /煽动事件 / inciting incident / 触发事件 / Setup 段 / 开篇五件事 / 中段塌陷 / 赌注没升 / up the ante /不知道怎么开头 / 想不到第一句 / 开头抓不住读者 / 开头没冲突 / 主角的日常没被打破 / 开头像介绍背景 /短中长篇体制 / 主角转主动 / 主角太英雄 / 故事节奏 / pinch point / 夹点 / 故事没启动"。不适用于: 非叙事内容(纯数据/公文)、没有可识别人物主角线的纯设定集、意识流与抒情散文(不靠外部事件推动)、新闻导语与学术摘要类非虚构开头、单场景内的微观写作(归 scene-craft)、作者写作习惯与心理状态(作者培养类)。与 narrative-momentum 交接:「中段塌陷」的结构成因(里程碑/赌注/四箱)归本 Skill;弃读、章末钩子、势链/金币/内悬念归后者。 | ## 5 正文写作与呈现 | skill_name | skill_file | skill_description | |---|---|---| -| character-design | `.agent/skills/character-design/SKILL.md` | 小说写作的人物设计方法:用 7 变量全维度建角色,用表层/内层/深层三层信息让角色立体,用内在恶魔给角色驱动力和角色弧,用一句话测试给人物选扁平/圆形形态,把人物站在叙事原型上做反转。激活场景:创建新角色(包括"AI 协作建角色,给我一份清单")、角色库管理(很多角色要系统化区分)、角色不鲜明/脸谱化/一维、角色感觉飘或假、角色工具人没驱动力没弧、读者不关心主角、两个角色撞型、群像分不清、配角和主角怎么分配深度、人物太单薄或太符号化、想用原型/神话母题但不想俗套、网文主角类型设计、历史人物重写、主题象征想用但用力过猛。关键 trigger:"角色设计 / 角色构建 / 角色要素 / character profile / 角色 sheet / 角色清单 / 角色怎么写 /角色背景 / 角色目标 / 角色动机 / 7 变量 / 角色旋钮 / 角色维度 /立体 / 角色深度 / 角色层次 / 表层 / 内层 / 深层 / 3 维角色 / 一维 / 主角是 1 维 / 怎么让角色活 /扁平 / 圆形 / flat / round / 一句话概括 / 人物太单薄 / 如何让人物丰满 /内在恶魔 / inner demon / 内在冲突 / 角色弧 / 工具人 / 角色是搬运工 / 没有驱动力 / 没有灵魂 /为什么读者不关心我的主角 / 原型 / archetype / 刻板印象 / stereotype / 人物塑造 / 主题象征 / symbol /中国小说原型 / 本土原型 / 东方母题 / father horst / 墙不只是墙 / 象征不必是钹 /如何用原型又不套路 / 用原型别让原型用你"。不适用于:对真实人物的全面评价(道德问题,不是方法问题);无人物的纯信息文本;后现代解构作品故意反原型、反母题时(原型定位合法缺席)。与 character-presentation 交接:7 变量/弧线/扁圆/原型归本 Skill;定型后的登场细节、关系网、反常瞬间呈现归 character-presentation。与 dialogue-craft / narration-pov 交接:正文对话声音与视角执行归后两者,本 Skill 不写对话课。 | -| character-presentation | `.agent/skills/character-presentation/SKILL.md` | 写小说时要把人物呈现给读者看,而不是讲给读者听,遇到这些情况激活:人物登场段读起来像性格形容词清单,用了勇敢、热情、冷酷等抽象词但读起来假;人物扁平、脸谱化、群像分不清;次要人物只有 200 字登场空间不知道怎么让人记住;情节靠巧合推动,主角无故倒霉;人物没戏、该转变但读者看不到转变;想知道"如何显示人物"而不是"告诉"。关键 trigger:"细节马赛克 / mosaic of detail / 人物立体 / 人物脸谱化 / 登场段 /性格形容词 / show not tell / status details / Tom Wolfe / 网文主角人设 /性格碰撞 / 性格即命运 / 反常即戏 / 反常瞬间 / 关系网 / 隐藏关系 / 人物很立体 /比现实更真实 / 人物让我看到了看不到的东西 / 过程发现 / 人物自己说话了"。不适用于:人物变量设计、人物弧线与原型定位、扁圆人物一句话测试(归 character-design);纯意识流、极简主义与人物作为思想载体的抽象哲学小说;真实人物之间的理解问题(那是心理学不是文学);非虚构写作(纪实作品人物的话必须基于事实)。与 dialogue-craft 交接:说话方式、句长、口头禅、同一声音诊断、遮住名字测试归 dialogue-craft;本 Skill 只管登场呈现、关系网、反常瞬间与"过程发现"叙事。与 character-design 交接:建角变量与弧线归后者;定型后的场景内呈现归本 Skill。 | -| dialogue-craft | `.agent/skills/dialogue-craft/SKILL.md` | 激活场景:写或改小说对话——用户说"我对话写不好"、"对话太书面、像论文答辩"、"对话全是 X 说 Y 说"、"所有角色说话一个声音"、"对话推动不了情节"、"不知道什么时候用对话什么时候用叙述"、"对话只是在传递信息"、"对话没张力"、"对话写得像答辩"、"写了一整章对话情节没推进"、"权力博弈场景对话没张力"、"对话怎么暴露人物、怎么改变权力关系"。关键 trigger:"对话写不好"、"对话太书面"、"对话像答辩"、"什么时候用对话"、"对话一个声音"、"对话推动情节"、"X说Y说"、"对话没张力"、"对话太碎/太满"、"对话即行动"、"dialogue as action"、"对话和引语的区别"、"dialogue vs quote"、"对话暴露人物"、"对话改变权力"、"小说对话技巧"。不适用于:说明文/议论文;访谈记录与会议实录(非虚构对话是转录,不是小说);剧本(两书冲突保留:布兰德认为对白即剧本全体、无需判断何时用;克拉克源单元声明适用于写剧本;见 references/boundaries-and-pitfalls.md 适用范围节);纯抒情与内心独白(规则不同,见 narration-pov);无对话的纯动作戏(见 scene-craft);辩论稿与演讲稿(目标是说服,不是"做事");用户整篇不会写(那是 story-planning 的活);对话只是其中一部分、想整体优化(先把稿子放一边、隔夜重读做整篇优化,不在对话层面修)。与 character-presentation 交接:登场呈现与"过程发现"归后者;说话方式、句长、口头禅、同一声音诊断归本 Skill。 | -| expand-scene | `.agent/skills/expand-scene/SKILL.md` | 在既有场景内补充动作链、对话潜台词、感官细节和环境互动。用户认为某个场景过薄并明确要求扩写时使用;不新开场景、不改落点、不夹带新设定。点名改情节/翻案归 rewrite-selection;只修语病/标点/节奏归 polish-prose;AI 味须先 diagnose-ai-flavor,本槽不得绕过。 | -| narration-pov | `.agent/skills/narration-pov/SKILL.md` | 中文小说写作中选择视角、叙述立场和叙述模式时使用。激活场景:选视角人物并决定向读者透露多少信息;想揭示封闭组织、社区、制度的荒谬而不说教;想写开放式结局、暧昧关系、命运类故事让读者回味;想避免作者跳出来下判断、给简单答案;决定何时暂停主线去做反思、插叙、独白、闪回并落回主线。关键 trigger:视角、POV、全知、限制视角、外来者视角、局外人、叙述立场、怀疑、说教、太直白、开放式结局、不确定性、留白、插叙、倒叙、意识流、内心独白、主线太平、折线落不回去、主线与折线、折线、汽笛站、卡夫卡式、fish out of water、broken line。不适用于:无叙事时间的纯抒情诗或散文;千字以内的单场景小品;推理悬疑等结尾必须给出确定答案的作品;需要明确价值观引导的儿童文学;需要明确立场的议论文、社论;纯对话剧本(对话的功能见 dialogue-craft)。与 theme-and-stance 交接:远距荒诞外来者(布尔加科夫式撒旦访莫斯科)的完整案例与幽默结构归 theme-and-stance;本 Skill 只保留外来者切入机制,案例见 references/outsider-entry.md 第三节指针。 | -| polish-prose | `.agent/skills/polish-prose/SKILL.md` | 修正候选或既有正文的错字、语病、标点、节奏和角色声音指纹(非规则级去 AI 味)。用户只要求改善表达层时使用;不得改变情节事实、场景结构或对白语义。场景加厚归 expand-scene;点名改范围/翻案归 rewrite-selection;AI 味检测与修订归 diagnose-ai-flavor → revise-ai-flavor,本 Skill 不得自称去 AI 味入口。 | -| prose-craft | `.agent/skills/prose-craft/SKILL.md` | 中文小说的语言与修辞领域:写稿或改稿时调整句子层与段落层的文本。激活场景:段落读起来单调催眠,句长或主谓位置需要诊断;满纸抽象,读者既看不见也摸不着,怀疑卡在官僚话、套话、公文腔;重大场景(死亡、战争、重病)用力过猛,或日常场景没有文气;抒情太直白变滥情;想用白描立人物;文本或人物温度不稳、没有辨识度;风格漂移,想逐根杠杆诊断声音。关键 trigger:"句法节奏" / "主谓先行" / "右分支句" / "句长" / "模式转折" / "boom boom bang" / "翻译腔" / "抽象梯子" / "太抽象" / "能给我个例子吗" / "给我个例子" / "由抽象到具体" / "怎么写得有深意" / "用力过猛" / "修辞密度" / "克制" / "back off" / "show off" / "抒情" / "滥情" / "白描" / "基础体温" / "声音均衡器" / "graphic equalizer" / "风格漂移" / "风格诊断" / "找到自己的声音" / "三十个杠杆"。不适用于:诗歌;实验文学与故意打破语法的项目;翻译文本(应保留原语节奏);纯动作戏(无抽象层与修辞校准需求);公文、教科书、工具书、学术论文、商业文案等非叙事文体。与 show-and-omission 交接:「太抽象 / 读者看不见」若主要是情绪/性格标签堆叠,归后者做标签→场景;本 Skill 管句段修辞、句长、修辞密度与声音杠杆。 | -| rewrite-selection | `.agent/skills/rewrite-selection/SKILL.md` | 按用户意见重写指定段落或场景,并校验范围、事实锚和版本。用户明确点名修改范围时使用;范围外原文不动,不顺手改规划或知识卡。场景过薄只加厚归 expand-scene;只修表达层归 polish-prose;AI 味须先 diagnose-ai-flavor,本槽不得绕过。 | -| scene-craft | `.agent/skills/scene-craft/SKILL.md` | 小说场景执行方法:给每个场景定使命、定详略、定进出点、定镜头距离,把相邻场景排成节奏,再把拼装痕迹蒙蔽掉。用户建场景、改场景、诊断场景时激活:"这个场景有什么用、场景散、小说拖、场景太慢、不知道该详写还是略写、字数安排不合理、过渡生硬、场景扁平、没画面感、全程中景、场景切换不自然、读者出戏、高潮没力"。关键 trigger:"场景使命 / 场景任务 / scene mission / 晚进入 / 早退出 / enter late leave early /场景进入退出 / 场景节奏 / 场景紧凑 / 详写略写 / 字数安排 / 过渡 / 镜头距离 / 摄影机距离 /拉远推近 / 远景中景特写 / 鸟瞰 / 建立镜头 / cinematic distances / 没画面感 / 场景扁平 /全程中景 / 对质戏 / 对峙戏 / 群像戏 / 回忆与现实切换 / 突兀 / 不自然 / 拼装痕迹 / 蒙蔽 /读者出戏"。不适用于:整体篇章结构与里程碑(用 story-structure)、对话写法(用 dialogue-craft)、展示与留白的一般原则(用 show-and-omission)、视角选择与叙述模式(用 narration-pov)、没有场景概念的非虚构与诗歌散文、剧本台词部分、纯抒情独白与全程单一距离的意识流章节、三千字以下切不开档的极短篇。与 foreshadow-payoff 交接:有「埋了没收 / 契诃夫之枪 / 铺垫债」语境 → foreshadow-payoff;仅「这个场景高潮没力 / 进出点弱」→ 本 Skill。与 narrative-momentum 交接:跨场景章末钩子、弃读、势链归后者;单场景使命与排节奏归本 Skill。 | -| show-and-omission | `.agent/skills/show-and-omission/SKILL.md` | 激活场景:小说文本里情绪、氛围、性格被抽象标签堆出来("她很悲伤""气氛阴森""他是个好人"),读者没有画面;写到极端情绪场景(崩溃、杀人后、噩耗、求爱)不知道心理怎么下笔;奇幻、梦境、超现实情节写得假、读者出戏;对话和动作看着平淡,扛不出第二层意思;想藏住两个人之间的秘密或暗流,不想明说;视角人物说出了自己不可能知道的信息;或者总怕读者看不懂,解释越写越多,读者仍说读不懂。关键 trigger:"show don't tell" / "展示不说教" / "没有画面感" / "太抽象" / "形容词太多" /"心理描写怎么写" / "不写他感到,写他做什么" / "留白" / "飞白" / "冰山" / "写得假" / "出戏" /"imagination" / "magical realism" /"读者不信" / "藏着不写明" / "说得太满" / "视角穿帮" / "人物知道了不该知道的" / "信息差" /"读者读不懂" / "明明很显然" / "跳步" / "术语太多" / "why is this jargon"。不适用于:意识流作品里刻意的直接心理呈现(乔伊斯、伍尔夫式的美学追求);第一人称主观独白和全知叙述者的合法评述;纪实写作和须符合科学逻辑的硬科幻;需要逻辑严密的悬疑推理与动作戏(反逻辑法不能用);说明书、新闻导语、学术论文、儿童启蒙等只需明确传递信息的段落;写给同行的专业文献(术语是该有的)。与 prose-craft 交接:句长单调、修辞密度、风格杠杆诊断归 prose-craft。与 theme-and-stance 交接:抽象标签、极端情绪缺画面、视角穿帮归本 Skill;主题演示、作家立场、手软/心慈手狠归 theme-and-stance(含 show don't tell 主题层)。 | -| theme-and-stance | `.agent/skills/theme-and-stance/SKILL.md` | 中文小说的主题表达与作家立场的执行层:主题不由作者说出来,由人物在关键时刻的选择演示出来;立场不靠主题先行去安排,藏进环境与性格的碰撞里自然浮现;沉重题材不写成控诉、苦情或谩骂,用幽默建立与现实的关系;人物该受的苦,作者不能因为心软而放过。激活场景:主题写成说教、立场太直白;人物像作者传声筒、情节被安排去服务主题;沉重题材写得压抑、愤怒、读着难受;作者舍不得人物受苦、写到关键处手抖。关键 trigger:"主题说教" "主题太直白" "主题先行" "席勒化" "莎士比亚化" "主题怎么表达""show don't tell 主题" "演示主题" "手软" "舍不得" "手抖" "心慈手狠" "狠瞬间""黑色幽默" "沉重题材" "太沉重了" "批判但不说教" "读着压抑" "布尔加科夫" "卡夫卡式幽默"。不适用于:非虚构/纪实/学术写作(主题表达方式不同);寓言、童话、儿童文学(可以明说主题,也可以心慈不手狠);纯喜剧写作(幽默本身就是目的);大屠杀、重大灾难等纯悲剧庄重题材(慎用幽默,会显得轻佻);主题尚未建立(先用 concept-design 做概念设计)。与 show-and-omission 交接:标签换场景、冰山留白、视角穿帮归 show-and-omission;主题演示、立场与手软/幽默结构归本 Skill。与 narration-pov 交接:外来者切入的荒诞/幽默距离与结构(含撒旦访莫斯科全文案例)归本 Skill;narration-pov 只保留 POV 侧外来者机制指针。 | -| write-next-chapter | `.agent/skills/write-next-chapter/SKILL.md` | 按已确认细纲、冻结事实和动态篇幅合同生成下一整章候选。作品需要续写下一章且输入合同完整时使用;不自行检索、不改规划、不把候选直接写入 Canonical。 | +| character-design | `.agent/skills/writing/character-design/SKILL.md` | 小说写作的人物设计方法:用 7 变量全维度建角色,用表层/内层/深层三层信息让角色立体,用内在恶魔给角色驱动力和角色弧,用一句话测试给人物选扁平/圆形形态,把人物站在叙事原型上做反转。激活场景:创建新角色(包括"AI 协作建角色,给我一份清单")、角色库管理(很多角色要系统化区分)、角色不鲜明/脸谱化/一维、角色感觉飘或假、角色工具人没驱动力没弧、读者不关心主角、两个角色撞型、群像分不清、配角和主角怎么分配深度、人物太单薄或太符号化、想用原型/神话母题但不想俗套、网文主角类型设计、历史人物重写、主题象征想用但用力过猛。关键 trigger:"角色设计 / 角色构建 / 角色要素 / character profile / 角色 sheet / 角色清单 / 角色怎么写 /角色背景 / 角色目标 / 角色动机 / 7 变量 / 角色旋钮 / 角色维度 /立体 / 角色深度 / 角色层次 / 表层 / 内层 / 深层 / 3 维角色 / 一维 / 主角是 1 维 / 怎么让角色活 /扁平 / 圆形 / flat / round / 一句话概括 / 人物太单薄 / 如何让人物丰满 /内在恶魔 / inner demon / 内在冲突 / 角色弧 / 工具人 / 角色是搬运工 / 没有驱动力 / 没有灵魂 /为什么读者不关心我的主角 / 原型 / archetype / 刻板印象 / stereotype / 人物塑造 / 主题象征 / symbol /中国小说原型 / 本土原型 / 东方母题 / father horst / 墙不只是墙 / 象征不必是钹 /如何用原型又不套路 / 用原型别让原型用你"。不适用于:对真实人物的全面评价(道德问题,不是方法问题);无人物的纯信息文本;后现代解构作品故意反原型、反母题时(原型定位合法缺席)。与 character-presentation 交接:7 变量/弧线/扁圆/原型归本 Skill;定型后的登场细节、关系网、反常瞬间呈现归 character-presentation。与 dialogue-craft / narration-pov 交接:正文对话声音与视角执行归后两者,本 Skill 不写对话课。 | +| character-presentation | `.agent/skills/writing/character-presentation/SKILL.md` | 写小说时要把人物呈现给读者看,而不是讲给读者听,遇到这些情况激活:人物登场段读起来像性格形容词清单,用了勇敢、热情、冷酷等抽象词但读起来假;人物扁平、脸谱化、群像分不清;次要人物只有 200 字登场空间不知道怎么让人记住;情节靠巧合推动,主角无故倒霉;人物没戏、该转变但读者看不到转变;想知道"如何显示人物"而不是"告诉"。关键 trigger:"细节马赛克 / mosaic of detail / 人物立体 / 人物脸谱化 / 登场段 /性格形容词 / show not tell / status details / Tom Wolfe / 网文主角人设 /性格碰撞 / 性格即命运 / 反常即戏 / 反常瞬间 / 关系网 / 隐藏关系 / 人物很立体 /比现实更真实 / 人物让我看到了看不到的东西 / 过程发现 / 人物自己说话了"。不适用于:人物变量设计、人物弧线与原型定位、扁圆人物一句话测试(归 character-design);纯意识流、极简主义与人物作为思想载体的抽象哲学小说;真实人物之间的理解问题(那是心理学不是文学);非虚构写作(纪实作品人物的话必须基于事实)。与 dialogue-craft 交接:说话方式、句长、口头禅、同一声音诊断、遮住名字测试归 dialogue-craft;本 Skill 只管登场呈现、关系网、反常瞬间与"过程发现"叙事。与 character-design 交接:建角变量与弧线归后者;定型后的场景内呈现归本 Skill。 | +| dialogue-craft | `.agent/skills/writing/dialogue-craft/SKILL.md` | 激活场景:写或改小说对话——用户说"我对话写不好"、"对话太书面、像论文答辩"、"对话全是 X 说 Y 说"、"所有角色说话一个声音"、"对话推动不了情节"、"不知道什么时候用对话什么时候用叙述"、"对话只是在传递信息"、"对话没张力"、"对话写得像答辩"、"写了一整章对话情节没推进"、"权力博弈场景对话没张力"、"对话怎么暴露人物、怎么改变权力关系"。关键 trigger:"对话写不好"、"对话太书面"、"对话像答辩"、"什么时候用对话"、"对话一个声音"、"对话推动情节"、"X说Y说"、"对话没张力"、"对话太碎/太满"、"对话即行动"、"dialogue as action"、"对话和引语的区别"、"dialogue vs quote"、"对话暴露人物"、"对话改变权力"、"小说对话技巧"。不适用于:说明文/议论文;访谈记录与会议实录(非虚构对话是转录,不是小说);剧本(两书冲突保留:布兰德认为对白即剧本全体、无需判断何时用;克拉克源单元声明适用于写剧本;见 references/boundaries-and-pitfalls.md 适用范围节);纯抒情与内心独白(规则不同,见 narration-pov);无对话的纯动作戏(见 scene-craft);辩论稿与演讲稿(目标是说服,不是"做事");用户整篇不会写(那是 story-planning 的活);对话只是其中一部分、想整体优化(先把稿子放一边、隔夜重读做整篇优化,不在对话层面修)。与 character-presentation 交接:登场呈现与"过程发现"归后者;说话方式、句长、口头禅、同一声音诊断归本 Skill。 | +| narration-pov | `.agent/skills/writing/narration-pov/SKILL.md` | 中文小说写作中选择视角、叙述立场和叙述模式时使用。激活场景:选视角人物并决定向读者透露多少信息;想揭示封闭组织、社区、制度的荒谬而不说教;想写开放式结局、暧昧关系、命运类故事让读者回味;想避免作者跳出来下判断、给简单答案;决定何时暂停主线去做反思、插叙、独白、闪回并落回主线。关键 trigger:视角、POV、全知、限制视角、外来者视角、局外人、叙述立场、怀疑、说教、太直白、开放式结局、不确定性、留白、插叙、倒叙、意识流、内心独白、主线太平、折线落不回去、主线与折线、折线、汽笛站、卡夫卡式、fish out of water、broken line。不适用于:无叙事时间的纯抒情诗或散文;千字以内的单场景小品;推理悬疑等结尾必须给出确定答案的作品;需要明确价值观引导的儿童文学;需要明确立场的议论文、社论;纯对话剧本(对话的功能见 dialogue-craft)。与 theme-and-stance 交接:远距荒诞外来者(布尔加科夫式撒旦访莫斯科)的完整案例与幽默结构归 theme-and-stance;本 Skill 只保留外来者切入机制,案例见 references/outsider-entry.md 第三节指针。 | +| prose-craft | `.agent/skills/writing/prose-craft/SKILL.md` | 中文小说的语言与修辞领域:写稿或改稿时调整句子层与段落层的文本。激活场景:段落读起来单调催眠,句长或主谓位置需要诊断;满纸抽象,读者既看不见也摸不着,怀疑卡在官僚话、套话、公文腔;重大场景(死亡、战争、重病)用力过猛,或日常场景没有文气;抒情太直白变滥情;想用白描立人物;文本或人物温度不稳、没有辨识度;风格漂移,想逐根杠杆诊断声音。关键 trigger:"句法节奏" / "主谓先行" / "右分支句" / "句长" / "模式转折" / "boom boom bang" / "翻译腔" / "抽象梯子" / "太抽象" / "能给我个例子吗" / "给我个例子" / "由抽象到具体" / "怎么写得有深意" / "用力过猛" / "修辞密度" / "克制" / "back off" / "show off" / "抒情" / "滥情" / "白描" / "基础体温" / "声音均衡器" / "graphic equalizer" / "风格漂移" / "风格诊断" / "找到自己的声音" / "三十个杠杆"。不适用于:诗歌;实验文学与故意打破语法的项目;翻译文本(应保留原语节奏);纯动作戏(无抽象层与修辞校准需求);公文、教科书、工具书、学术论文、商业文案等非叙事文体。与 show-and-omission 交接:「太抽象 / 读者看不见」若主要是情绪/性格标签堆叠,归后者做标签→场景;本 Skill 管句段修辞、句长、修辞密度与声音杠杆。 | +| scene-craft | `.agent/skills/writing/scene-craft/SKILL.md` | 小说场景执行方法:给每个场景定使命、定详略、定进出点、定镜头距离,把相邻场景排成节奏,再把拼装痕迹蒙蔽掉。用户建场景、改场景、诊断场景时激活:"这个场景有什么用、场景散、小说拖、场景太慢、不知道该详写还是略写、字数安排不合理、过渡生硬、场景扁平、没画面感、全程中景、场景切换不自然、读者出戏、高潮没力"。关键 trigger:"场景使命 / 场景任务 / scene mission / 晚进入 / 早退出 / enter late leave early /场景进入退出 / 场景节奏 / 场景紧凑 / 详写略写 / 字数安排 / 过渡 / 镜头距离 / 摄影机距离 /拉远推近 / 远景中景特写 / 鸟瞰 / 建立镜头 / cinematic distances / 没画面感 / 场景扁平 /全程中景 / 对质戏 / 对峙戏 / 群像戏 / 回忆与现实切换 / 突兀 / 不自然 / 拼装痕迹 / 蒙蔽 /读者出戏"。不适用于:整体篇章结构与里程碑(用 story-structure)、对话写法(用 dialogue-craft)、展示与留白的一般原则(用 show-and-omission)、视角选择与叙述模式(用 narration-pov)、没有场景概念的非虚构与诗歌散文、剧本台词部分、纯抒情独白与全程单一距离的意识流章节、三千字以下切不开档的极短篇。与 foreshadow-payoff 交接:有「埋了没收 / 契诃夫之枪 / 铺垫债」语境 → foreshadow-payoff;仅「这个场景高潮没力 / 进出点弱」→ 本 Skill。与 narrative-momentum 交接:跨场景章末钩子、弃读、势链归后者;单场景使命与排节奏归本 Skill。 | +| show-and-omission | `.agent/skills/writing/show-and-omission/SKILL.md` | 激活场景:小说文本里情绪、氛围、性格被抽象标签堆出来("她很悲伤""气氛阴森""他是个好人"),读者没有画面;写到极端情绪场景(崩溃、杀人后、噩耗、求爱)不知道心理怎么下笔;奇幻、梦境、超现实情节写得假、读者出戏;对话和动作看着平淡,扛不出第二层意思;想藏住两个人之间的秘密或暗流,不想明说;视角人物说出了自己不可能知道的信息;或者总怕读者看不懂,解释越写越多,读者仍说读不懂。关键 trigger:"show don't tell" / "展示不说教" / "没有画面感" / "太抽象" / "形容词太多" /"心理描写怎么写" / "不写他感到,写他做什么" / "留白" / "飞白" / "冰山" / "写得假" / "出戏" /"imagination" / "magical realism" /"读者不信" / "藏着不写明" / "说得太满" / "视角穿帮" / "人物知道了不该知道的" / "信息差" /"读者读不懂" / "明明很显然" / "跳步" / "术语太多" / "why is this jargon"。不适用于:意识流作品里刻意的直接心理呈现(乔伊斯、伍尔夫式的美学追求);第一人称主观独白和全知叙述者的合法评述;纪实写作和须符合科学逻辑的硬科幻;需要逻辑严密的悬疑推理与动作戏(反逻辑法不能用);说明书、新闻导语、学术论文、儿童启蒙等只需明确传递信息的段落;写给同行的专业文献(术语是该有的)。与 prose-craft 交接:句长单调、修辞密度、风格杠杆诊断归 prose-craft。与 theme-and-stance 交接:抽象标签、极端情绪缺画面、视角穿帮归本 Skill;主题演示、作家立场、手软/心慈手狠归 theme-and-stance(含 show don't tell 主题层)。 | +| theme-and-stance | `.agent/skills/writing/theme-and-stance/SKILL.md` | 中文小说的主题表达与作家立场的执行层:主题不由作者说出来,由人物在关键时刻的选择演示出来;立场不靠主题先行去安排,藏进环境与性格的碰撞里自然浮现;沉重题材不写成控诉、苦情或谩骂,用幽默建立与现实的关系;人物该受的苦,作者不能因为心软而放过。激活场景:主题写成说教、立场太直白;人物像作者传声筒、情节被安排去服务主题;沉重题材写得压抑、愤怒、读着难受;作者舍不得人物受苦、写到关键处手抖。关键 trigger:"主题说教" "主题太直白" "主题先行" "席勒化" "莎士比亚化" "主题怎么表达""show don't tell 主题" "演示主题" "手软" "舍不得" "手抖" "心慈手狠" "狠瞬间""黑色幽默" "沉重题材" "太沉重了" "批判但不说教" "读着压抑" "布尔加科夫" "卡夫卡式幽默"。不适用于:非虚构/纪实/学术写作(主题表达方式不同);寓言、童话、儿童文学(可以明说主题,也可以心慈不手狠);纯喜剧写作(幽默本身就是目的);大屠杀、重大灾难等纯悲剧庄重题材(慎用幽默,会显得轻佻);主题尚未建立(先用 concept-design 做概念设计)。与 show-and-omission 交接:标签换场景、冰山留白、视角穿帮归 show-and-omission;主题演示、立场与手软/幽默结构归本 Skill。与 narration-pov 交接:外来者切入的荒诞/幽默距离与结构(含撒旦访莫斯科全文案例)归本 Skill;narration-pov 只保留 POV 侧外来者机制指针。 | ## 6 检测、评分与诊断 | skill_name | skill_file | skill_description | |---|---|---| -| adjudicate-quality-gate | `.agent/skills/adjudicate-quality-gate/SKILL.md` | 从不可变逐层回执构建 Gate 输入,并按父仓专题-04 的固定顺序产出 Gate A/B 终态与可核验 receipt。回放评测收集完逐样本脱敏结果、需要一个不可协商的通过/不通过裁决时使用;不评分、不改样本、不放宽阈值。 | -| check-content-consistency | `.agent/skills/check-content-consistency/SKILL.md` | 检查正文或细纲候选的结构、事实、角色状态、能力代价、伏笔和证据缺口。候选进入用户决策或独立评分前使用;只产检测报告,不修改候选。 | -| evaluate-frozen-replay | `.agent/skills/evaluate-frozen-replay/SKILL.md` | 编排细纲隔离回放:把参考作品冻结到 as_of 章号,跑三臂 planner、盲 detector 与双盲 judge,产出可审计的逐样本结果。需要验证知识或上下文方案对细纲质量是否有增益时使用;阻断未来信息、未授权来源和不可接受的候选流入生产。 | -| load-replay-reference-work | `.agent/skills/load-replay-reference-work/SKILL.md` | 在单个只读事务内从实验库装配正文回放的真实临时配置:来源证明、授权快照、目标 scaffold 拆分、冻结历史与预注册卡,写到仓库外临时文件。回放要从仓内合成夹具切到真实作品时使用;只 SELECT,不查询目标章正文,不把原书写进 Git。 | -| novel-diagnosis | `.agent/skills/novel-diagnosis/SKILL.md` | 激活场景:用户手里有一部写完或在写的小说,感觉不对劲但说不清哪里不对——"我的小说有什么问题"、"它缺什么"、"为什么被拒稿"、"虎头蛇尾/高开低走"、"中段疲软"、"人物写扁了"、"全是流水账没有峰值"、"读者很兴奋但没理解"、"收尾太硬"、"形式大于内容";或要把自己的作品和参照作品比差距;或交付诊断/评论/书评结论前需要扫描一遍有没有空话。关键 trigger:"诊断作品 / 小说体检 / 我的小说有什么问题 / 缺什么 / 为什么被拒 / 虎头蛇尾 /高开低走 / 中段疲软 / 流水账 / 写扁了 / 故事还是情节 / 后来呢 / 为什么 / 有时间没价值 /情节和人物谁赢 / 模式还是节奏 / 幻想还是预言 / 六便士 / 难懂 / 奇书 / 六核 / 七侧面 /圆桌 / 伪学者 / 怎么系统地看一部小说"。不适用于:请求写作技法而非找毛病;非虚构;纯新闻速报/菜谱等时间流即内容的对象;作者习惯/心理培养问题。症状已落到具体环节时不要停在本 Skill,按下表交接:结构/里程碑→story-structure;弃读/钩子→narrative-momentum;建角变量→character-design;登场呈现→character-presentation;对话声音→dialogue-craft;场景执行→scene-craft;标签画面→show-and-omission;句段修辞→prose-craft;POV 机制→narration-pov;主题/荒诞幽默→theme-and-stance;埋收债→foreshadow-payoff;idea/引擎→concept-design;节拍工作流→story-planning;收尾姿态→story-ending;AI 味→diagnose-ai-flavor(须先诊断)。 | -| optimize-content-quality | `.agent/skills/optimize-content-quality/SKILL.md` | 根据 score-content-quality 的独立评分,锁定最低质量维度并归因到 prompt、上下文或设定层,只出单变量改进建议。候选稳定不达标且需要定位改进来源时使用;不执行重生成、不改 rubric、不自行提交代码。 | -| replay-writer-gate | `.agent/skills/replay-writer-gate/SKILL.md` | 执行正文 A/B/C 三臂隔离回放:构造并校验三臂 WriterContext、跑写手与盲评、结算预算与 raw 租约,产出逐样本脱敏结果。需要用真实作品验证卡索引对正文质量是否有增益时使用;不产生 Gate 终态,不把原书正文写进仓库。 | -| score-content-quality | `.agent/skills/score-content-quality/SKILL.md` | 按独立 rubric 评分在线正文、正文回放或细纲回放,产出逐维分数、引文证据与理由。候选交付用户前或回放实验需要独立质量判断时使用;只评分不裁决——集合级通过/不通过归 adjudicate-quality-gate;不改候选、不放宽阈值。 | - -## 7 去 AI 味与人感 - -| skill_name | skill_file | skill_description | -|---|---|---| -| capture-ai-flavor-cases | `.agent/skills/capture-ai-flavor-cases/SKILL.md` | 从已有作品或创作反馈中抽取可复核的 AI 味案例卡,保留来源哈希与位置并做来源重验证。需要反向积累人感样例、记录一次写作事故或批量回填既有作品时使用;不做标注确认与规则升格,不直接修改正文、范式或生产规则。 | -| diagnose-ai-flavor | `.agent/skills/diagnose-ai-flavor/SKILL.md` | 技能 3 诊断:对目标正文跑 active 规则库,产出带精确片段与证据的发现清单,检测完成自动落库。只查不改;没有本产物,revise-ai-flavor 拒绝启动。 | -| establish-voice-baseline | `.agent/skills/establish-voice-baseline/SKILL.md` | 技能 1 定基线:作品建立或新角色登场时,把已确认正文与作者样张产出的声音账做结构校验、grounding 门后版本化落库。不产正文;是修订门禁与前置预防的对照物。 | -| prevent-ai-flavor | `.agent/skills/prevent-ai-flavor/SKILL.md` | 技能 2 前置预防:生成前组装写作上下文合同——active 规则的负约束(附反例)加声音账的正样例与保护项。不碰正文,只供上下文组装消费。 | -| promote-ai-flavor-rule | `.agent/skills/promote-ai-flavor-rule/SKILL.md` | 把已标注的 AI 味案例卡沿 canonical→样例→规则候选→评测→激活的升格链推进,并负责降级。需要确认案例卡、投影四类样例、归纳规则候选、跑合同回放或审批激活时使用;不做案例采集与扫描,也不改正文。 | -| revise-ai-flavor | `.agent/skills/revise-ai-flavor/SKILL.md` | 技能 4 修订:在诊断产物与作者同意之上执行最小 patch,过硬门、复扫与成对选择校验,产出候选稿与审计报告。没诊断不启动;人不点头永远是候选。 | - -## 8 候选主权与落库 - -| skill_name | skill_file | skill_description | -|---|---|---| -| confirm-knowledge-draft | `.agent/skills/confirm-knowledge-draft/SKILL.md` | 用户明确确认后把知识草稿翻成作品正式知识面,写入实体或关系、绑定知识库并迁移向量 owner。抽取或拆书产出的卡需要转正时使用;不处理正文候选、规划确认和冲突裁决。 | -| decide-candidate | `.agent/skills/decide-candidate/SKILL.md` | 据用户明确指令接受、合并或丢弃 Shadow 正文候选并更新 Canonical。仅主会话在用户决定后调用;知识卡归 confirm-knowledge-draft,规划归 plan-story。 | +| novel-diagnosis | `.agent/skills/diagnosis/novel-diagnosis/SKILL.md` | 激活场景:用户手里有一部写完或在写的小说,感觉不对劲但说不清哪里不对——"我的小说有什么问题"、"它缺什么"、"为什么被拒稿"、"虎头蛇尾/高开低走"、"中段疲软"、"人物写扁了"、"全是流水账没有峰值"、"读者很兴奋但没理解"、"收尾太硬"、"形式大于内容";或要把自己的作品和参照作品比差距;或交付诊断/评论/书评结论前需要扫描一遍有没有空话。关键 trigger:"诊断作品 / 小说体检 / 我的小说有什么问题 / 缺什么 / 为什么被拒 / 虎头蛇尾 /高开低走 / 中段疲软 / 流水账 / 写扁了 / 故事还是情节 / 后来呢 / 为什么 / 有时间没价值 /情节和人物谁赢 / 模式还是节奏 / 幻想还是预言 / 六便士 / 难懂 / 奇书 / 六核 / 七侧面 /圆桌 / 伪学者 / 怎么系统地看一部小说"。不适用于:请求写作技法而非找毛病;非虚构;纯新闻速报/菜谱等时间流即内容的对象;作者习惯/心理培养问题。症状已落到具体环节时不要停在本 Skill,按下表交接:结构/里程碑→story-structure;弃读/钩子→narrative-momentum;建角变量→character-design;登场呈现→character-presentation;对话声音→dialogue-craft;场景执行→scene-craft;标签画面→show-and-omission;句段修辞→prose-craft;POV 机制→narration-pov;主题/荒诞幽默→theme-and-stance;埋收债→foreshadow-payoff;idea/引擎→concept-design;节拍工作流→story-planning;收尾姿态→story-ending;AI 味→diagnose-ai-flavor(须先诊断)。 | diff --git a/.agent/skills/novel-diagnosis/SKILL.md b/.agent/skills/diagnosis/novel-diagnosis/SKILL.md similarity index 100% rename from .agent/skills/novel-diagnosis/SKILL.md rename to .agent/skills/diagnosis/novel-diagnosis/SKILL.md diff --git a/.agent/skills/novel-diagnosis/references/_coverage.md b/.agent/skills/diagnosis/novel-diagnosis/references/_coverage.md similarity index 100% rename from .agent/skills/novel-diagnosis/references/_coverage.md rename to .agent/skills/diagnosis/novel-diagnosis/references/_coverage.md diff --git a/.agent/skills/novel-diagnosis/references/diagnosis-workflow.md b/.agent/skills/diagnosis/novel-diagnosis/references/diagnosis-workflow.md similarity index 100% rename from .agent/skills/novel-diagnosis/references/diagnosis-workflow.md rename to .agent/skills/diagnosis/novel-diagnosis/references/diagnosis-workflow.md diff --git a/.agent/skills/novel-diagnosis/references/dimension-frameworks.md b/.agent/skills/diagnosis/novel-diagnosis/references/dimension-frameworks.md similarity index 100% rename from .agent/skills/novel-diagnosis/references/dimension-frameworks.md rename to .agent/skills/diagnosis/novel-diagnosis/references/dimension-frameworks.md diff --git a/.agent/skills/novel-diagnosis/references/fantasy-prophecy.md b/.agent/skills/diagnosis/novel-diagnosis/references/fantasy-prophecy.md similarity index 100% rename from .agent/skills/novel-diagnosis/references/fantasy-prophecy.md rename to .agent/skills/diagnosis/novel-diagnosis/references/fantasy-prophecy.md diff --git a/.agent/skills/novel-diagnosis/references/pattern-rhythm.md b/.agent/skills/diagnosis/novel-diagnosis/references/pattern-rhythm.md similarity index 100% rename from .agent/skills/novel-diagnosis/references/pattern-rhythm.md rename to .agent/skills/diagnosis/novel-diagnosis/references/pattern-rhythm.md diff --git a/.agent/skills/novel-diagnosis/references/plot-character.md b/.agent/skills/diagnosis/novel-diagnosis/references/plot-character.md similarity index 100% rename from .agent/skills/novel-diagnosis/references/plot-character.md rename to .agent/skills/diagnosis/novel-diagnosis/references/plot-character.md diff --git a/.agent/skills/novel-diagnosis/references/quack-scholar-scan.md b/.agent/skills/diagnosis/novel-diagnosis/references/quack-scholar-scan.md similarity index 100% rename from .agent/skills/novel-diagnosis/references/quack-scholar-scan.md rename to .agent/skills/diagnosis/novel-diagnosis/references/quack-scholar-scan.md diff --git a/.agent/skills/novel-diagnosis/references/quack-scholar.md b/.agent/skills/diagnosis/novel-diagnosis/references/quack-scholar.md similarity index 100% rename from .agent/skills/novel-diagnosis/references/quack-scholar.md rename to .agent/skills/diagnosis/novel-diagnosis/references/quack-scholar.md diff --git a/.agent/skills/novel-diagnosis/references/round-table.md b/.agent/skills/diagnosis/novel-diagnosis/references/round-table.md similarity index 100% rename from .agent/skills/novel-diagnosis/references/round-table.md rename to .agent/skills/diagnosis/novel-diagnosis/references/round-table.md diff --git a/.agent/skills/novel-diagnosis/references/story-plot.md b/.agent/skills/diagnosis/novel-diagnosis/references/story-plot.md similarity index 100% rename from .agent/skills/novel-diagnosis/references/story-plot.md rename to .agent/skills/diagnosis/novel-diagnosis/references/story-plot.md diff --git a/.agent/skills/novel-diagnosis/references/time-value.md b/.agent/skills/diagnosis/novel-diagnosis/references/time-value.md similarity index 100% rename from .agent/skills/novel-diagnosis/references/time-value.md rename to .agent/skills/diagnosis/novel-diagnosis/references/time-value.md diff --git a/.agent/skills/concept-design/SKILL.md b/.agent/skills/planning/concept-design/SKILL.md similarity index 100% rename from .agent/skills/concept-design/SKILL.md rename to .agent/skills/planning/concept-design/SKILL.md diff --git a/.agent/skills/concept-design/references/_coverage.md b/.agent/skills/planning/concept-design/references/_coverage.md similarity index 100% rename from .agent/skills/concept-design/references/_coverage.md rename to .agent/skills/planning/concept-design/references/_coverage.md diff --git a/.agent/skills/concept-design/references/concept-worksheet.md b/.agent/skills/planning/concept-design/references/concept-worksheet.md similarity index 100% rename from .agent/skills/concept-design/references/concept-worksheet.md rename to .agent/skills/planning/concept-design/references/concept-worksheet.md diff --git a/.agent/skills/concept-design/references/delivery-strategy.md b/.agent/skills/planning/concept-design/references/delivery-strategy.md similarity index 100% rename from .agent/skills/concept-design/references/delivery-strategy.md rename to .agent/skills/planning/concept-design/references/delivery-strategy.md diff --git a/.agent/skills/concept-design/references/four-questions.md b/.agent/skills/planning/concept-design/references/four-questions.md similarity index 100% rename from .agent/skills/concept-design/references/four-questions.md rename to .agent/skills/planning/concept-design/references/four-questions.md diff --git a/.agent/skills/concept-design/references/originality.md b/.agent/skills/planning/concept-design/references/originality.md similarity index 100% rename from .agent/skills/concept-design/references/originality.md rename to .agent/skills/planning/concept-design/references/originality.md diff --git a/.agent/skills/concept-design/references/story-engine.md b/.agent/skills/planning/concept-design/references/story-engine.md similarity index 100% rename from .agent/skills/concept-design/references/story-engine.md rename to .agent/skills/planning/concept-design/references/story-engine.md diff --git a/.agent/skills/concept-design/references/what-if.md b/.agent/skills/planning/concept-design/references/what-if.md similarity index 100% rename from .agent/skills/concept-design/references/what-if.md rename to .agent/skills/planning/concept-design/references/what-if.md diff --git a/.agent/skills/foreshadow-payoff/SKILL.md b/.agent/skills/planning/foreshadow-payoff/SKILL.md similarity index 100% rename from .agent/skills/foreshadow-payoff/SKILL.md rename to .agent/skills/planning/foreshadow-payoff/SKILL.md diff --git a/.agent/skills/foreshadow-payoff/references/_coverage.md b/.agent/skills/planning/foreshadow-payoff/references/_coverage.md similarity index 100% rename from .agent/skills/foreshadow-payoff/references/_coverage.md rename to .agent/skills/planning/foreshadow-payoff/references/_coverage.md diff --git a/.agent/skills/foreshadow-payoff/references/boundaries-and-pitfalls.md b/.agent/skills/planning/foreshadow-payoff/references/boundaries-and-pitfalls.md similarity index 100% rename from .agent/skills/foreshadow-payoff/references/boundaries-and-pitfalls.md rename to .agent/skills/planning/foreshadow-payoff/references/boundaries-and-pitfalls.md diff --git a/.agent/skills/foreshadow-payoff/references/detail-driven-climax.md b/.agent/skills/planning/foreshadow-payoff/references/detail-driven-climax.md similarity index 100% rename from .agent/skills/foreshadow-payoff/references/detail-driven-climax.md rename to .agent/skills/planning/foreshadow-payoff/references/detail-driven-climax.md diff --git a/.agent/skills/foreshadow-payoff/references/foreshadow-checklist.md b/.agent/skills/planning/foreshadow-payoff/references/foreshadow-checklist.md similarity index 100% rename from .agent/skills/foreshadow-payoff/references/foreshadow-checklist.md rename to .agent/skills/planning/foreshadow-payoff/references/foreshadow-checklist.md diff --git a/.agent/skills/foreshadow-payoff/references/foreshadow-ledger-template.md b/.agent/skills/planning/foreshadow-payoff/references/foreshadow-ledger-template.md similarity index 100% rename from .agent/skills/foreshadow-payoff/references/foreshadow-ledger-template.md rename to .agent/skills/planning/foreshadow-payoff/references/foreshadow-ledger-template.md diff --git a/.agent/skills/foreshadow-payoff/references/natural-staircase.md b/.agent/skills/planning/foreshadow-payoff/references/natural-staircase.md similarity index 100% rename from .agent/skills/foreshadow-payoff/references/natural-staircase.md rename to .agent/skills/planning/foreshadow-payoff/references/natural-staircase.md diff --git a/.agent/skills/foreshadow-payoff/references/register-and-repay.md b/.agent/skills/planning/foreshadow-payoff/references/register-and-repay.md similarity index 100% rename from .agent/skills/foreshadow-payoff/references/register-and-repay.md rename to .agent/skills/planning/foreshadow-payoff/references/register-and-repay.md diff --git a/.agent/skills/narrative-momentum/SKILL.md b/.agent/skills/planning/narrative-momentum/SKILL.md similarity index 100% rename from .agent/skills/narrative-momentum/SKILL.md rename to .agent/skills/planning/narrative-momentum/SKILL.md diff --git a/.agent/skills/narrative-momentum/references/_coverage.md b/.agent/skills/planning/narrative-momentum/references/_coverage.md similarity index 100% rename from .agent/skills/narrative-momentum/references/_coverage.md rename to .agent/skills/planning/narrative-momentum/references/_coverage.md diff --git a/.agent/skills/narrative-momentum/references/alternation-and-distinctions.md b/.agent/skills/planning/narrative-momentum/references/alternation-and-distinctions.md similarity index 100% rename from .agent/skills/narrative-momentum/references/alternation-and-distinctions.md rename to .agent/skills/planning/narrative-momentum/references/alternation-and-distinctions.md diff --git a/.agent/skills/narrative-momentum/references/breakpoint-hooks.md b/.agent/skills/planning/narrative-momentum/references/breakpoint-hooks.md similarity index 100% rename from .agent/skills/narrative-momentum/references/breakpoint-hooks.md rename to .agent/skills/planning/narrative-momentum/references/breakpoint-hooks.md diff --git a/.agent/skills/narrative-momentum/references/build-momentum.md b/.agent/skills/planning/narrative-momentum/references/build-momentum.md similarity index 100% rename from .agent/skills/narrative-momentum/references/build-momentum.md rename to .agent/skills/planning/narrative-momentum/references/build-momentum.md diff --git a/.agent/skills/narrative-momentum/references/midway-rewards.md b/.agent/skills/planning/narrative-momentum/references/midway-rewards.md similarity index 100% rename from .agent/skills/narrative-momentum/references/midway-rewards.md rename to .agent/skills/planning/narrative-momentum/references/midway-rewards.md diff --git a/.agent/skills/narrative-momentum/references/momentum-checklist.md b/.agent/skills/planning/narrative-momentum/references/momentum-checklist.md similarity index 100% rename from .agent/skills/narrative-momentum/references/momentum-checklist.md rename to .agent/skills/planning/narrative-momentum/references/momentum-checklist.md diff --git a/.agent/skills/story-ending/SKILL.md b/.agent/skills/planning/story-ending/SKILL.md similarity index 100% rename from .agent/skills/story-ending/SKILL.md rename to .agent/skills/planning/story-ending/SKILL.md diff --git a/.agent/skills/story-ending/references/_coverage.md b/.agent/skills/planning/story-ending/references/_coverage.md similarity index 100% rename from .agent/skills/story-ending/references/_coverage.md rename to .agent/skills/planning/story-ending/references/_coverage.md diff --git a/.agent/skills/story-ending/references/ending-strategies.md b/.agent/skills/planning/story-ending/references/ending-strategies.md similarity index 100% rename from .agent/skills/story-ending/references/ending-strategies.md rename to .agent/skills/planning/story-ending/references/ending-strategies.md diff --git a/.agent/skills/story-ending/references/execution-chain.md b/.agent/skills/planning/story-ending/references/execution-chain.md similarity index 100% rename from .agent/skills/story-ending/references/execution-chain.md rename to .agent/skills/planning/story-ending/references/execution-chain.md diff --git a/.agent/skills/story-ending/references/expansion-completion.md b/.agent/skills/planning/story-ending/references/expansion-completion.md similarity index 100% rename from .agent/skills/story-ending/references/expansion-completion.md rename to .agent/skills/planning/story-ending/references/expansion-completion.md diff --git a/.agent/skills/story-ending/references/fix-final-scene.md b/.agent/skills/planning/story-ending/references/fix-final-scene.md similarity index 100% rename from .agent/skills/story-ending/references/fix-final-scene.md rename to .agent/skills/planning/story-ending/references/fix-final-scene.md diff --git a/.agent/skills/story-ending/references/natural-stop.md b/.agent/skills/planning/story-ending/references/natural-stop.md similarity index 100% rename from .agent/skills/story-ending/references/natural-stop.md rename to .agent/skills/planning/story-ending/references/natural-stop.md diff --git a/.agent/skills/story-ending/references/pitfalls-and-boundaries.md b/.agent/skills/planning/story-ending/references/pitfalls-and-boundaries.md similarity index 100% rename from .agent/skills/story-ending/references/pitfalls-and-boundaries.md rename to .agent/skills/planning/story-ending/references/pitfalls-and-boundaries.md diff --git a/.agent/skills/story-planning/SKILL.md b/.agent/skills/planning/story-planning/SKILL.md similarity index 100% rename from .agent/skills/story-planning/SKILL.md rename to .agent/skills/planning/story-planning/SKILL.md diff --git a/.agent/skills/story-planning/references/_coverage.md b/.agent/skills/planning/story-planning/references/_coverage.md similarity index 100% rename from .agent/skills/story-planning/references/_coverage.md rename to .agent/skills/planning/story-planning/references/_coverage.md diff --git a/.agent/skills/story-planning/references/beat-sheet.md b/.agent/skills/planning/story-planning/references/beat-sheet.md similarity index 100% rename from .agent/skills/story-planning/references/beat-sheet.md rename to .agent/skills/planning/story-planning/references/beat-sheet.md diff --git a/.agent/skills/story-planning/references/draft-flow.md b/.agent/skills/planning/story-planning/references/draft-flow.md similarity index 100% rename from .agent/skills/story-planning/references/draft-flow.md rename to .agent/skills/planning/story-planning/references/draft-flow.md diff --git a/.agent/skills/story-planning/references/plan-vs-pantsing.md b/.agent/skills/planning/story-planning/references/plan-vs-pantsing.md similarity index 100% rename from .agent/skills/story-planning/references/plan-vs-pantsing.md rename to .agent/skills/planning/story-planning/references/plan-vs-pantsing.md diff --git a/.agent/skills/story-planning/references/planning-workflow-checklist.md b/.agent/skills/planning/story-planning/references/planning-workflow-checklist.md similarity index 100% rename from .agent/skills/story-planning/references/planning-workflow-checklist.md rename to .agent/skills/planning/story-planning/references/planning-workflow-checklist.md diff --git a/.agent/skills/story-structure/SKILL.md b/.agent/skills/planning/story-structure/SKILL.md similarity index 100% rename from .agent/skills/story-structure/SKILL.md rename to .agent/skills/planning/story-structure/SKILL.md diff --git a/.agent/skills/story-structure/references/_coverage.md b/.agent/skills/planning/story-structure/references/_coverage.md similarity index 100% rename from .agent/skills/story-structure/references/_coverage.md rename to .agent/skills/planning/story-structure/references/_coverage.md diff --git a/.agent/skills/story-structure/references/first-plot-point.md b/.agent/skills/planning/story-structure/references/first-plot-point.md similarity index 100% rename from .agent/skills/story-structure/references/first-plot-point.md rename to .agent/skills/planning/story-structure/references/first-plot-point.md diff --git a/.agent/skills/story-structure/references/four-boxes.md b/.agent/skills/planning/story-structure/references/four-boxes.md similarity index 100% rename from .agent/skills/story-structure/references/four-boxes.md rename to .agent/skills/planning/story-structure/references/four-boxes.md diff --git a/.agent/skills/story-structure/references/inciting-incident.md b/.agent/skills/planning/story-structure/references/inciting-incident.md similarity index 100% rename from .agent/skills/story-structure/references/inciting-incident.md rename to .agent/skills/planning/story-structure/references/inciting-incident.md diff --git a/.agent/skills/story-structure/references/inciting-vs-fpp.md b/.agent/skills/planning/story-structure/references/inciting-vs-fpp.md similarity index 100% rename from .agent/skills/story-structure/references/inciting-vs-fpp.md rename to .agent/skills/planning/story-structure/references/inciting-vs-fpp.md diff --git a/.agent/skills/story-structure/references/length-system.md b/.agent/skills/planning/story-structure/references/length-system.md similarity index 100% rename from .agent/skills/story-structure/references/length-system.md rename to .agent/skills/planning/story-structure/references/length-system.md diff --git a/.agent/skills/story-structure/references/midpoint.md b/.agent/skills/planning/story-structure/references/midpoint.md similarity index 100% rename from .agent/skills/story-structure/references/midpoint.md rename to .agent/skills/planning/story-structure/references/midpoint.md diff --git a/.agent/skills/story-structure/references/opening.md b/.agent/skills/planning/story-structure/references/opening.md similarity index 100% rename from .agent/skills/story-structure/references/opening.md rename to .agent/skills/planning/story-structure/references/opening.md diff --git a/.agent/skills/story-structure/references/part2-wanderer.md b/.agent/skills/planning/story-structure/references/part2-wanderer.md similarity index 100% rename from .agent/skills/story-structure/references/part2-wanderer.md rename to .agent/skills/planning/story-structure/references/part2-wanderer.md diff --git a/.agent/skills/story-structure/references/setup.md b/.agent/skills/planning/story-structure/references/setup.md similarity index 100% rename from .agent/skills/story-structure/references/setup.md rename to .agent/skills/planning/story-structure/references/setup.md diff --git a/.agent/skills/story-structure/references/six-milestones.md b/.agent/skills/planning/story-structure/references/six-milestones.md similarity index 100% rename from .agent/skills/story-structure/references/six-milestones.md rename to .agent/skills/planning/story-structure/references/six-milestones.md diff --git a/.agent/skills/story-structure/references/structure-checklists.md b/.agent/skills/planning/story-structure/references/structure-checklists.md similarity index 100% rename from .agent/skills/story-structure/references/structure-checklists.md rename to .agent/skills/planning/story-structure/references/structure-checklists.md diff --git a/.agent/skills/character-design/SKILL.md b/.agent/skills/writing/character-design/SKILL.md similarity index 100% rename from .agent/skills/character-design/SKILL.md rename to .agent/skills/writing/character-design/SKILL.md diff --git a/.agent/skills/character-design/references/_coverage.md b/.agent/skills/writing/character-design/references/_coverage.md similarity index 100% rename from .agent/skills/character-design/references/_coverage.md rename to .agent/skills/writing/character-design/references/_coverage.md diff --git a/.agent/skills/character-design/references/archetype-reversal.md b/.agent/skills/writing/character-design/references/archetype-reversal.md similarity index 100% rename from .agent/skills/character-design/references/archetype-reversal.md rename to .agent/skills/writing/character-design/references/archetype-reversal.md diff --git a/.agent/skills/character-design/references/character-diagnosis.md b/.agent/skills/writing/character-design/references/character-diagnosis.md similarity index 100% rename from .agent/skills/character-design/references/character-diagnosis.md rename to .agent/skills/writing/character-design/references/character-diagnosis.md diff --git a/.agent/skills/character-design/references/character-worksheet.md b/.agent/skills/writing/character-design/references/character-worksheet.md similarity index 100% rename from .agent/skills/character-design/references/character-worksheet.md rename to .agent/skills/writing/character-design/references/character-worksheet.md diff --git a/.agent/skills/character-design/references/flat-vs-round.md b/.agent/skills/writing/character-design/references/flat-vs-round.md similarity index 100% rename from .agent/skills/character-design/references/flat-vs-round.md rename to .agent/skills/writing/character-design/references/flat-vs-round.md diff --git a/.agent/skills/writing/character-design/references/inner-demon.md b/.agent/skills/writing/character-design/references/inner-demon.md new file mode 100644 index 0000000..45be81b --- /dev/null +++ b/.agent/skills/writing/character-design/references/inner-demon.md @@ -0,0 +1,114 @@ +# 驱动:角色冲突来自内在恶魔 + +## 原文摘录 + +> "Exterior conflict is the conflict of the plot—something in the story world that opposes the hero's quest. Interior conflict is the conflict of the character, the inner demon... Both must be present. If only the external conflict is present, the character is a vehicle for the plot rather than a meaningful player in it." +> +> — Larry Brooks, *Story Engineering* (2011), Part 3 + +## 方法规则 + +### 两层冲突必须同时运作 + +角色必须有**外部冲突**和**内部冲突**同时运作。只有外部冲突,角色是工具人;只有内部冲突,角色是无剧情的独白。 + +**冲突的 2 层**: + +- **外部冲突(Exterior Conflict)**:剧情对手、社会、自然、敌人——他"做什么"会失败 +- **内部冲突(Interior Conflict / Inner Demon)**:内在恐惧、创伤、信念——他"为什么做不到" + +### Inner Demon 的四个关键特征 + +- 是**根本性**的,不是表面的(不是"他爱迟到",是"他害怕被拒绝所以迟到") +- 通常来自**童年/早期创伤** +- 是**驱动**角色弧的引擎——角色弧就是"克服 Inner Demon"的过程 +- **读者共鸣**来自 Inner Demon——读者在角色身上看到自己 + +### 操作问法 + +拿到一个角色,问"他最怕什么?"——不只是怕失败,是怕"如果我成功,我爸会怎么说"这种根深层的怕。 + +### 深度与呈现的分寸 + +**Inner Demon 越深,角色越活**。但太深(如严重心理疾病)需要谨慎呈现,避免负面示范。 + +### 深层 = 恶魔(合并点) + +本文的恶魔即 references/three-dimensions.md 的"深层":角色自己都未必意识到的驱动力。两个入口,同一件事:三层信息把它当最底层的事实,本文把它当冲突与弧的引擎。 + +## 案例全文 + +### 案例 1:反例——完美英雄,没 Inner Demon + +- **问题**:写作者写了"完美英雄",外部冲突强(打怪),但读者不关心 +- **方法论的使用**:诊断发现:Inner Demon = 0。角色没有"为什么做不到" +- **结论**:只有 External Conflict,角色是 vehicle for plot, not meaningful player +- **结果**:拒稿常见原因 + +### 案例 2:作者 5 部小说主角(恶魔角度) + +- **问题**:5 部小说主角都让出版商买,为什么? +- **方法论的使用**:每个主角都有清晰的 Inner Demon(孤儿之痛 / 父亲失败之痛 / 战火童年 / 等等) +- **结论**:5 个不同 Inner Demon = 5 个不同角色 +- **结果**:全部出版 + +> 同一案例在 references/seven-variables.md(角度:变量差异化)和 references/three-dimensions.md(角度:按 3 维建设)再次出现。角度不同,三处都保留。 + +> 结构里程碑中的 Thelma & Louise 案例 owner:`story-structure`([four-boxes.md](../../../planning/story-structure/references/four-boxes.md) 等)。Inner Demon 角度摘要:Thelma 长期被控制渴望自由;Louise 早年创伤与内疚——两恶魔撑起共情。 + +## 操作步骤 + +1. **选 1 个角色** + - 完成标准:用户指定 1 个 +2. **列出外部冲突** + - 完成标准:1 段说清"他在故事里要完成什么" + - 提示:这通常用户已经知道,5 分钟内能写 +3. **找 Inner Demon** + - 完成标准:1-2 段说清"他最怕什么" + "为什么怕"(找童年/早期根源) + - 关键问:"如果他成功了,他会失去什么?"(答:他会面对他最怕的) +4. **诊断:内外冲突共振了吗?** + - 完成标准:1 段说清"外部任务怎么激活/触碰他的 Inner Demon" + - 例:主角要公开发表演讲(外部)+ 他害怕被关注(内部)= 共振 + - 没共振 = 内外两层平行,不是故事 +5. **角色弧 = Inner Demon 的克服** + - 完成标准:1 段说清"故事结束时,他对自己的 Inner Demon 做了什么" + - 克服 / 接受 / 失败(悲剧)/ 部分克服 = 都行,但必须明确 + +## 边界与失败模式 + +### 不要在以下情况使用 + +- 角色不打算成为主角(配角可以没有完整 Inner Demon) +- 写群像/POV 切换——每个 POV 主角各做 1 次 +- 写非现实角色(动物/AI/外星人)——需调整 Inner Demon 的概念 + +### 作者警告的失败模式 + +- Inner Demon 太"社会议题"(如"他害怕贫穷")——缺乏个人化 +- Inner Demon 太"流行病"(如"他抑郁")——缺乏具体性 +- Inner Demon 没有"对外部任务的阻挡"——内外的连接是核心 + +### 作者盲点 + +- 默认 Inner Demon 是"心理疾病"——实际上更多是"信念/恐惧/习惯" +- 默认 Inner Demon 必须被克服——接受/失败的弧也有效 +- 默认 1 个 Inner Demon——多个 Inner Demon 互相矛盾也常见,但需控制 + +## 易混方法论 + +- "Character Wound"(Lisa Cron)——类似,但更聚焦"故事前发生的事件" +- "Ghost / Wound / Need"(Story Grid)——三层结构,不同于本 skill 的 1 个核心 +- "Lie the Character Believes"(K.M. Weiland)——接近,但更窄(信念 vs 恐惧) + +## 中文落地 + +- 中文读者对"家庭之痛"的共鸣最直接:恶魔的早期根源常落在家庭(被比较、被抛弃、被期待压垮)。写法上不贴诊断名词,落到那件具体的事、那句没说出口的话。 +- 网文类型(复仇流、升级流、无敌流)外部冲突普遍很强,最容易出恶魔 = 0 的工具人问题;主角至少要有一个"为什么做不到/不敢",类型爽感才不会变成流水账。 +- "他抑郁"这类写法在中文里同样是失败模式:诊断词不是恶魔,要写这个抑郁具体长什么样、挡住了外部任务的哪一步。 + +## 与其他方法的关系 + +- **建**:恶魔是 7 变量中的变量 4 → references/seven-variables.md +- **立体**:恶魔 = 三层信息的深层 → references/three-dimensions.md +- **结构衔接**:恶魔被激活、深层浮出水面的节拍常放在故事中点附近,中点的结构定位见综合 skill story-structure +- **定形**:带完整恶魔的角色几乎不可能一句话说清,天然偏圆形 → references/flat-vs-round.md diff --git a/.agent/skills/character-design/references/seven-variables.md b/.agent/skills/writing/character-design/references/seven-variables.md similarity index 100% rename from .agent/skills/character-design/references/seven-variables.md rename to .agent/skills/writing/character-design/references/seven-variables.md diff --git a/.agent/skills/character-design/references/three-dimensions.md b/.agent/skills/writing/character-design/references/three-dimensions.md similarity index 100% rename from .agent/skills/character-design/references/three-dimensions.md rename to .agent/skills/writing/character-design/references/three-dimensions.md diff --git a/.agent/skills/character-presentation/SKILL.md b/.agent/skills/writing/character-presentation/SKILL.md similarity index 100% rename from .agent/skills/character-presentation/SKILL.md rename to .agent/skills/writing/character-presentation/SKILL.md diff --git a/.agent/skills/character-presentation/references/_coverage.md b/.agent/skills/writing/character-presentation/references/_coverage.md similarity index 100% rename from .agent/skills/character-presentation/references/_coverage.md rename to .agent/skills/writing/character-presentation/references/_coverage.md diff --git a/.agent/skills/character-presentation/references/abnormal-moment.md b/.agent/skills/writing/character-presentation/references/abnormal-moment.md similarity index 100% rename from .agent/skills/character-presentation/references/abnormal-moment.md rename to .agent/skills/writing/character-presentation/references/abnormal-moment.md diff --git a/.agent/skills/character-presentation/references/character-collision.md b/.agent/skills/writing/character-presentation/references/character-collision.md similarity index 100% rename from .agent/skills/character-presentation/references/character-collision.md rename to .agent/skills/writing/character-presentation/references/character-collision.md diff --git a/.agent/skills/character-presentation/references/detail-mosaic.md b/.agent/skills/writing/character-presentation/references/detail-mosaic.md similarity index 100% rename from .agent/skills/character-presentation/references/detail-mosaic.md rename to .agent/skills/writing/character-presentation/references/detail-mosaic.md diff --git a/.agent/skills/character-presentation/references/presentation-checklist.md b/.agent/skills/writing/character-presentation/references/presentation-checklist.md similarity index 100% rename from .agent/skills/character-presentation/references/presentation-checklist.md rename to .agent/skills/writing/character-presentation/references/presentation-checklist.md diff --git a/.agent/skills/character-presentation/references/relationship-web.md b/.agent/skills/writing/character-presentation/references/relationship-web.md similarity index 100% rename from .agent/skills/character-presentation/references/relationship-web.md rename to .agent/skills/writing/character-presentation/references/relationship-web.md diff --git a/.agent/skills/character-presentation/references/visible-private-life.md b/.agent/skills/writing/character-presentation/references/visible-private-life.md similarity index 100% rename from .agent/skills/character-presentation/references/visible-private-life.md rename to .agent/skills/writing/character-presentation/references/visible-private-life.md diff --git a/.agent/skills/character-presentation/references/voice-discovery-process.md b/.agent/skills/writing/character-presentation/references/voice-discovery-process.md similarity index 100% rename from .agent/skills/character-presentation/references/voice-discovery-process.md rename to .agent/skills/writing/character-presentation/references/voice-discovery-process.md diff --git a/.agent/skills/dialogue-craft/SKILL.md b/.agent/skills/writing/dialogue-craft/SKILL.md similarity index 100% rename from .agent/skills/dialogue-craft/SKILL.md rename to .agent/skills/writing/dialogue-craft/SKILL.md diff --git a/.agent/skills/dialogue-craft/references/_coverage.md b/.agent/skills/writing/dialogue-craft/references/_coverage.md similarity index 100% rename from .agent/skills/dialogue-craft/references/_coverage.md rename to .agent/skills/writing/dialogue-craft/references/_coverage.md diff --git a/.agent/skills/dialogue-craft/references/boundaries-and-pitfalls.md b/.agent/skills/writing/dialogue-craft/references/boundaries-and-pitfalls.md similarity index 100% rename from .agent/skills/dialogue-craft/references/boundaries-and-pitfalls.md rename to .agent/skills/writing/dialogue-craft/references/boundaries-and-pitfalls.md diff --git a/.agent/skills/dialogue-craft/references/character-voice.md b/.agent/skills/writing/dialogue-craft/references/character-voice.md similarity index 100% rename from .agent/skills/dialogue-craft/references/character-voice.md rename to .agent/skills/writing/dialogue-craft/references/character-voice.md diff --git a/.agent/skills/dialogue-craft/references/dialogue-does-things.md b/.agent/skills/writing/dialogue-craft/references/dialogue-does-things.md similarity index 100% rename from .agent/skills/dialogue-craft/references/dialogue-does-things.md rename to .agent/skills/writing/dialogue-craft/references/dialogue-does-things.md diff --git a/.agent/skills/dialogue-craft/references/dialogue-revision-checklist.md b/.agent/skills/writing/dialogue-craft/references/dialogue-revision-checklist.md similarity index 100% rename from .agent/skills/dialogue-craft/references/dialogue-revision-checklist.md rename to .agent/skills/writing/dialogue-craft/references/dialogue-revision-checklist.md diff --git a/.agent/skills/dialogue-craft/references/execution-flow.md b/.agent/skills/writing/dialogue-craft/references/execution-flow.md similarity index 100% rename from .agent/skills/dialogue-craft/references/execution-flow.md rename to .agent/skills/writing/dialogue-craft/references/execution-flow.md diff --git a/.agent/skills/dialogue-craft/references/real-speech-texture.md b/.agent/skills/writing/dialogue-craft/references/real-speech-texture.md similarity index 100% rename from .agent/skills/dialogue-craft/references/real-speech-texture.md rename to .agent/skills/writing/dialogue-craft/references/real-speech-texture.md diff --git a/.agent/skills/dialogue-craft/references/rhythm-and-density.md b/.agent/skills/writing/dialogue-craft/references/rhythm-and-density.md similarity index 100% rename from .agent/skills/dialogue-craft/references/rhythm-and-density.md rename to .agent/skills/writing/dialogue-craft/references/rhythm-and-density.md diff --git a/.agent/skills/dialogue-craft/references/tags-and-attribution.md b/.agent/skills/writing/dialogue-craft/references/tags-and-attribution.md similarity index 100% rename from .agent/skills/dialogue-craft/references/tags-and-attribution.md rename to .agent/skills/writing/dialogue-craft/references/tags-and-attribution.md diff --git a/.agent/skills/dialogue-craft/references/when-to-use-dialogue.md b/.agent/skills/writing/dialogue-craft/references/when-to-use-dialogue.md similarity index 100% rename from .agent/skills/dialogue-craft/references/when-to-use-dialogue.md rename to .agent/skills/writing/dialogue-craft/references/when-to-use-dialogue.md diff --git a/.agent/skills/narration-pov/SKILL.md b/.agent/skills/writing/narration-pov/SKILL.md similarity index 100% rename from .agent/skills/narration-pov/SKILL.md rename to .agent/skills/writing/narration-pov/SKILL.md diff --git a/.agent/skills/narration-pov/references/_coverage.md b/.agent/skills/writing/narration-pov/references/_coverage.md similarity index 100% rename from .agent/skills/narration-pov/references/_coverage.md rename to .agent/skills/writing/narration-pov/references/_coverage.md diff --git a/.agent/skills/narration-pov/references/broken-line.md b/.agent/skills/writing/narration-pov/references/broken-line.md similarity index 100% rename from .agent/skills/narration-pov/references/broken-line.md rename to .agent/skills/writing/narration-pov/references/broken-line.md diff --git a/.agent/skills/narration-pov/references/certainty-uncertainty.md b/.agent/skills/writing/narration-pov/references/certainty-uncertainty.md similarity index 100% rename from .agent/skills/narration-pov/references/certainty-uncertainty.md rename to .agent/skills/writing/narration-pov/references/certainty-uncertainty.md diff --git a/.agent/skills/narration-pov/references/narration-pov-checklist.md b/.agent/skills/writing/narration-pov/references/narration-pov-checklist.md similarity index 100% rename from .agent/skills/narration-pov/references/narration-pov-checklist.md rename to .agent/skills/writing/narration-pov/references/narration-pov-checklist.md diff --git a/.agent/skills/narration-pov/references/outsider-entry.md b/.agent/skills/writing/narration-pov/references/outsider-entry.md similarity index 100% rename from .agent/skills/narration-pov/references/outsider-entry.md rename to .agent/skills/writing/narration-pov/references/outsider-entry.md diff --git a/.agent/skills/narration-pov/references/pov-camera.md b/.agent/skills/writing/narration-pov/references/pov-camera.md similarity index 100% rename from .agent/skills/narration-pov/references/pov-camera.md rename to .agent/skills/writing/narration-pov/references/pov-camera.md diff --git a/.agent/skills/narration-pov/references/pov-execution.md b/.agent/skills/writing/narration-pov/references/pov-execution.md similarity index 100% rename from .agent/skills/narration-pov/references/pov-execution.md rename to .agent/skills/writing/narration-pov/references/pov-execution.md diff --git a/.agent/skills/narration-pov/references/skeptical-stance.md b/.agent/skills/writing/narration-pov/references/skeptical-stance.md similarity index 100% rename from .agent/skills/narration-pov/references/skeptical-stance.md rename to .agent/skills/writing/narration-pov/references/skeptical-stance.md diff --git a/.agent/skills/prose-craft/SKILL.md b/.agent/skills/writing/prose-craft/SKILL.md similarity index 100% rename from .agent/skills/prose-craft/SKILL.md rename to .agent/skills/writing/prose-craft/SKILL.md diff --git a/.agent/skills/prose-craft/references/_coverage.md b/.agent/skills/writing/prose-craft/references/_coverage.md similarity index 100% rename from .agent/skills/prose-craft/references/_coverage.md rename to .agent/skills/writing/prose-craft/references/_coverage.md diff --git a/.agent/skills/prose-craft/references/abstraction-ladder.md b/.agent/skills/writing/prose-craft/references/abstraction-ladder.md similarity index 100% rename from .agent/skills/prose-craft/references/abstraction-ladder.md rename to .agent/skills/writing/prose-craft/references/abstraction-ladder.md diff --git a/.agent/skills/prose-craft/references/base-temperature.md b/.agent/skills/writing/prose-craft/references/base-temperature.md similarity index 100% rename from .agent/skills/prose-craft/references/base-temperature.md rename to .agent/skills/writing/prose-craft/references/base-temperature.md diff --git a/.agent/skills/prose-craft/references/lyric-restraint.md b/.agent/skills/writing/prose-craft/references/lyric-restraint.md similarity index 100% rename from .agent/skills/prose-craft/references/lyric-restraint.md rename to .agent/skills/writing/prose-craft/references/lyric-restraint.md diff --git a/.agent/skills/prose-craft/references/pattern-and-break.md b/.agent/skills/writing/prose-craft/references/pattern-and-break.md similarity index 100% rename from .agent/skills/prose-craft/references/pattern-and-break.md rename to .agent/skills/writing/prose-craft/references/pattern-and-break.md diff --git a/.agent/skills/writing/prose-craft/references/plain-description.md b/.agent/skills/writing/prose-craft/references/plain-description.md new file mode 100644 index 0000000..950bc39 --- /dev/null +++ b/.agent/skills/writing/prose-craft/references/plain-description.md @@ -0,0 +1,112 @@ +# 白描:用最少的字立住人物 + +> 来源:《小说课》(毕飞宇)bifeiyu-paiban —— 第 7 章,人物·修辞,难度两星,依赖要素:智商、直觉。案例来源:《促织》驼背巫的描写 + 蒲松龄的描写观。 + +> 「唇吻翕辟,不知何词。各各竦立以听。」——12 个字,一个神秘人物立住。() + +## 原文摘录 + +蒲松龄写驼背巫: + +> "巫从旁望空代祝,唇吻翕辟,不知何词。各各竦立以听。" + +**翻译**:嘴唇一张一合,不知道说什么词。所有的人都惊悚地站着听。 + +**12 个字**(不含虚词),**两个动作**(翕辟、竦立)——把一个神秘人物 + 一个静谧大场景全部搞定。 + +## 方法骨架 + +**白描 = 用最少的字画出一幅有重量的画**。 + +不是"写得简单",而是"写得精准"——每个字都**不可替换**。多一个字显得冗余,少一个字意思垮掉。 + +## 书中的案例() + +> 铺垫「自然楼梯」案例 owner:`foreshadow-payoff` → [natural-staircase.md](../../../planning/foreshadow-payoff/references/natural-staircase.md)「蒲松龄《促织》驼背巫」节。白描要点:只写动作与对话,不用形容词堆人物。 + +### 案例 2(指针):蒲松龄《促织》成名(逻辑自洽) + +> 立场/性格碰撞全文 owner:`theme-and-stance` → [stance-by-logic.md](../../theme-and-stance/references/stance-by-logic.md)。本处只保留白描对比:「为人迂讷」四字定性格,对照现代形容词堆砌写法。 + +### 案例 3:鲁迅《故乡》闰土 + +> "他站住了,脸上现出欢喜和凄凉的神情;动着嘴唇,却没有作声。他的态度终于恭敬起来了,分明地叫道:'老爷!……'" + +没有形容词——**只写动作和对话**,人物的全部复杂性就出来了。 + +(同一案例在本包 `lyric-restraint.md` 里从"不直接抒情、让读者自己懂"的角度再次引用,角度不同,两处都保留。) + +### 案例 4(指针):海明威《杀手》(对白白描) + +> POV 与多重视角案例 owner:`narration-pov` → [pov-camera.md](../../narration-pov/references/pov-camera.md)。本处只取白描角度:对话省略主语与代词,用内容本身透露说话人。 + +## 操作步骤 + +### 步骤 1:拒绝形容词 + +写第一稿时不要用"他很 X"(X = 任何形容词)。**改用动作**: + +| ❌ 形容词式 | ✅ 白描式 | +|---|---| +| 他很紧张 | 他的手指不停敲桌面 | +| 她很伤心 | 她的筷子停在半空 | +| 这地方很荒凉 | 门口的草长到了窗台 | +| 他很傲慢 | 他没抬眼看那人 | + +### 步骤 2:删除虚词 + +写完后做"虚词清理": + +- "的、了、着、于是、然后" → 能删就删 +- 形容词前的程度副词(很、非常、特别)→ 全删 +- "我看到/我听到" → 直接进入画面 + +### 步骤 3:检验"动作的代表性" + +每个白描动作要能代表**人物整体**: + +- 写驼背巫"唇吻翕辟"——代表她通神的能力 +- 写林冲"靠了门"——代表他忍辱负重的性格 +- 写闰土叫"老爷"——代表他从自然人到奴性的转化 + +**检验问题**:这个动作放在另一个场景、另一个人物身上,还成立吗?如果成立 → 换动作。 + +### 步骤 4:检验"动态"密度 + +一段白描文字里,**至少 1/3 的字是动词或名词性动作**。 + +- 静态白描(全是名词)= 死的描写 +- 动态白描(动词驱动)= 活的描写 + +## 边界 + +- **适合**:人物出场、关键瞬间、氛围营造 +- **不适合**:复杂心理活动(需要内心独白)、意识流 +- **不适合**:长篇大段的场景描写(需要更厚重的笔法) + +## 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 把白描当成"句子短" | 失去密度 | 每个短句都要承重 | +| 写一堆动作但没选择 | 散乱 | 动作必须有代表性 | +| 拒绝一切形容词 | 失去必要修饰 | 该用"鬼魅""青灰色"就用 | + +## 一句话总结 + +> **不写"他很 X",写"他做了一个动作,这个动作等于 X"。** + +## 相关方法点 + +- 与冰山理论(show-and-omission 域 bifeiyu-iceberg)互补:冰山关注"水下",白描关注"水面"。 +- 与人物命运(character-presentation 域 bifeiyu-character-fate)配套:白描是给"性格即命运"提供"性格描写"的技术。 +- 与反常(character-presentation 域 bifeiyu-anti-norm)配合:白描写常态,反常写变态——变态才有戏。 +- 与抒情不抒发(本包 `lyric-restraint.md`)配合:白描是抒情不抒发的主要技法。 +- 与基础体温(本包 `base-temperature.md`)配合:白描是"冷温度"的主要技法。 + +## 激活场景 + +1. 人物第一次出场 → 用 1-2 个具体动作代替 5 个形容词 +2. 群像描写 → 每个人物只用 1 个标识性动作区分 +3. 神秘人物/反派 → 用"动态"代替"介绍" +4. 时间紧/篇幅短(短篇、闪回)→ 白描是最高效的写法 diff --git a/.agent/skills/prose-craft/references/revision-checklist.md b/.agent/skills/writing/prose-craft/references/revision-checklist.md similarity index 100% rename from .agent/skills/prose-craft/references/revision-checklist.md rename to .agent/skills/writing/prose-craft/references/revision-checklist.md diff --git a/.agent/skills/prose-craft/references/rhetoric-density.md b/.agent/skills/writing/prose-craft/references/rhetoric-density.md similarity index 100% rename from .agent/skills/prose-craft/references/rhetoric-density.md rename to .agent/skills/writing/prose-craft/references/rhetoric-density.md diff --git a/.agent/skills/prose-craft/references/sentence-rhythm.md b/.agent/skills/writing/prose-craft/references/sentence-rhythm.md similarity index 100% rename from .agent/skills/prose-craft/references/sentence-rhythm.md rename to .agent/skills/writing/prose-craft/references/sentence-rhythm.md diff --git a/.agent/skills/prose-craft/references/voice-equalizer.md b/.agent/skills/writing/prose-craft/references/voice-equalizer.md similarity index 100% rename from .agent/skills/prose-craft/references/voice-equalizer.md rename to .agent/skills/writing/prose-craft/references/voice-equalizer.md diff --git a/.agent/skills/scene-craft/SKILL.md b/.agent/skills/writing/scene-craft/SKILL.md similarity index 100% rename from .agent/skills/scene-craft/SKILL.md rename to .agent/skills/writing/scene-craft/SKILL.md diff --git a/.agent/skills/scene-craft/references/_coverage.md b/.agent/skills/writing/scene-craft/references/_coverage.md similarity index 100% rename from .agent/skills/scene-craft/references/_coverage.md rename to .agent/skills/writing/scene-craft/references/_coverage.md diff --git a/.agent/skills/scene-craft/references/boundaries-and-pitfalls.md b/.agent/skills/writing/scene-craft/references/boundaries-and-pitfalls.md similarity index 100% rename from .agent/skills/scene-craft/references/boundaries-and-pitfalls.md rename to .agent/skills/writing/scene-craft/references/boundaries-and-pitfalls.md diff --git a/.agent/skills/scene-craft/references/scene-camera.md b/.agent/skills/writing/scene-craft/references/scene-camera.md similarity index 100% rename from .agent/skills/scene-craft/references/scene-camera.md rename to .agent/skills/writing/scene-craft/references/scene-camera.md diff --git a/.agent/skills/scene-craft/references/scene-detail.md b/.agent/skills/writing/scene-craft/references/scene-detail.md similarity index 100% rename from .agent/skills/scene-craft/references/scene-detail.md rename to .agent/skills/writing/scene-craft/references/scene-detail.md diff --git a/.agent/skills/scene-craft/references/scene-entry-exit.md b/.agent/skills/writing/scene-craft/references/scene-entry-exit.md similarity index 100% rename from .agent/skills/scene-craft/references/scene-entry-exit.md rename to .agent/skills/writing/scene-craft/references/scene-entry-exit.md diff --git a/.agent/skills/scene-craft/references/scene-ledger-template.md b/.agent/skills/writing/scene-craft/references/scene-ledger-template.md similarity index 100% rename from .agent/skills/scene-craft/references/scene-ledger-template.md rename to .agent/skills/writing/scene-craft/references/scene-ledger-template.md diff --git a/.agent/skills/scene-craft/references/scene-mission.md b/.agent/skills/writing/scene-craft/references/scene-mission.md similarity index 100% rename from .agent/skills/scene-craft/references/scene-mission.md rename to .agent/skills/writing/scene-craft/references/scene-mission.md diff --git a/.agent/skills/scene-craft/references/scene-mystification.md b/.agent/skills/writing/scene-craft/references/scene-mystification.md similarity index 100% rename from .agent/skills/scene-craft/references/scene-mystification.md rename to .agent/skills/writing/scene-craft/references/scene-mystification.md diff --git a/.agent/skills/scene-craft/references/scene-revision-checklist.md b/.agent/skills/writing/scene-craft/references/scene-revision-checklist.md similarity index 100% rename from .agent/skills/scene-craft/references/scene-revision-checklist.md rename to .agent/skills/writing/scene-craft/references/scene-revision-checklist.md diff --git a/.agent/skills/scene-craft/references/scene-rhythm.md b/.agent/skills/writing/scene-craft/references/scene-rhythm.md similarity index 100% rename from .agent/skills/scene-craft/references/scene-rhythm.md rename to .agent/skills/writing/scene-craft/references/scene-rhythm.md diff --git a/.agent/skills/show-and-omission/SKILL.md b/.agent/skills/writing/show-and-omission/SKILL.md similarity index 100% rename from .agent/skills/show-and-omission/SKILL.md rename to .agent/skills/writing/show-and-omission/SKILL.md diff --git a/.agent/skills/show-and-omission/references/_coverage.md b/.agent/skills/writing/show-and-omission/references/_coverage.md similarity index 100% rename from .agent/skills/show-and-omission/references/_coverage.md rename to .agent/skills/writing/show-and-omission/references/_coverage.md diff --git a/.agent/skills/show-and-omission/references/anti-logic.md b/.agent/skills/writing/show-and-omission/references/anti-logic.md similarity index 100% rename from .agent/skills/show-and-omission/references/anti-logic.md rename to .agent/skills/writing/show-and-omission/references/anti-logic.md diff --git a/.agent/skills/show-and-omission/references/extreme-emotion-body.md b/.agent/skills/writing/show-and-omission/references/extreme-emotion-body.md similarity index 100% rename from .agent/skills/show-and-omission/references/extreme-emotion-body.md rename to .agent/skills/writing/show-and-omission/references/extreme-emotion-body.md diff --git a/.agent/skills/show-and-omission/references/iceberg.md b/.agent/skills/writing/show-and-omission/references/iceberg.md similarity index 100% rename from .agent/skills/show-and-omission/references/iceberg.md rename to .agent/skills/writing/show-and-omission/references/iceberg.md diff --git a/.agent/skills/show-and-omission/references/imagination-anchor.md b/.agent/skills/writing/show-and-omission/references/imagination-anchor.md similarity index 100% rename from .agent/skills/show-and-omission/references/imagination-anchor.md rename to .agent/skills/writing/show-and-omission/references/imagination-anchor.md diff --git a/.agent/skills/show-and-omission/references/pov-knowledge-boundary.md b/.agent/skills/writing/show-and-omission/references/pov-knowledge-boundary.md similarity index 100% rename from .agent/skills/show-and-omission/references/pov-knowledge-boundary.md rename to .agent/skills/writing/show-and-omission/references/pov-knowledge-boundary.md diff --git a/.agent/skills/show-and-omission/references/reader-gap-diagnosis.md b/.agent/skills/writing/show-and-omission/references/reader-gap-diagnosis.md similarity index 100% rename from .agent/skills/show-and-omission/references/reader-gap-diagnosis.md rename to .agent/skills/writing/show-and-omission/references/reader-gap-diagnosis.md diff --git a/.agent/skills/show-and-omission/references/show-omission-checklist.md b/.agent/skills/writing/show-and-omission/references/show-omission-checklist.md similarity index 100% rename from .agent/skills/show-and-omission/references/show-omission-checklist.md rename to .agent/skills/writing/show-and-omission/references/show-omission-checklist.md diff --git a/.agent/skills/show-and-omission/references/show-vs-tell.md b/.agent/skills/writing/show-and-omission/references/show-vs-tell.md similarity index 100% rename from .agent/skills/show-and-omission/references/show-vs-tell.md rename to .agent/skills/writing/show-and-omission/references/show-vs-tell.md diff --git a/.agent/skills/theme-and-stance/SKILL.md b/.agent/skills/writing/theme-and-stance/SKILL.md similarity index 100% rename from .agent/skills/theme-and-stance/SKILL.md rename to .agent/skills/writing/theme-and-stance/SKILL.md diff --git a/.agent/skills/theme-and-stance/references/_coverage.md b/.agent/skills/writing/theme-and-stance/references/_coverage.md similarity index 100% rename from .agent/skills/theme-and-stance/references/_coverage.md rename to .agent/skills/writing/theme-and-stance/references/_coverage.md diff --git a/.agent/skills/theme-and-stance/references/boundaries-and-pitfalls.md b/.agent/skills/writing/theme-and-stance/references/boundaries-and-pitfalls.md similarity index 100% rename from .agent/skills/theme-and-stance/references/boundaries-and-pitfalls.md rename to .agent/skills/writing/theme-and-stance/references/boundaries-and-pitfalls.md diff --git a/.agent/skills/theme-and-stance/references/humor-as-stance.md b/.agent/skills/writing/theme-and-stance/references/humor-as-stance.md similarity index 100% rename from .agent/skills/theme-and-stance/references/humor-as-stance.md rename to .agent/skills/writing/theme-and-stance/references/humor-as-stance.md diff --git a/.agent/skills/theme-and-stance/references/mercy-ruth.md b/.agent/skills/writing/theme-and-stance/references/mercy-ruth.md similarity index 100% rename from .agent/skills/theme-and-stance/references/mercy-ruth.md rename to .agent/skills/writing/theme-and-stance/references/mercy-ruth.md diff --git a/.agent/skills/theme-and-stance/references/stance-by-logic.md b/.agent/skills/writing/theme-and-stance/references/stance-by-logic.md similarity index 100% rename from .agent/skills/theme-and-stance/references/stance-by-logic.md rename to .agent/skills/writing/theme-and-stance/references/stance-by-logic.md diff --git a/.agent/skills/theme-and-stance/references/theme-demonstration.md b/.agent/skills/writing/theme-and-stance/references/theme-demonstration.md similarity index 100% rename from .agent/skills/theme-and-stance/references/theme-demonstration.md rename to .agent/skills/writing/theme-and-stance/references/theme-demonstration.md diff --git a/.agent/skills/theme-and-stance/references/theme-stance-checklist.md b/.agent/skills/writing/theme-and-stance/references/theme-stance-checklist.md similarity index 100% rename from .agent/skills/theme-and-stance/references/theme-stance-checklist.md rename to .agent/skills/writing/theme-and-stance/references/theme-stance-checklist.md diff --git a/AGENTS.md b/AGENTS.md index 09c2a33..161c60d 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,9 +7,9 @@ `agent-example` 的目标定位是物理位于 `oh-my-muse` 内、拥有独立 `.git/` 的单用户缩小版 Muse,以 PostgreSQL 为正式内容权威。目标系统由 ReAct Agent、角色 Agent、Skill 和确定性工具协作,在本地完成作品、实体、范式、规划、正文、审核、用户决策与经验复利;不实现管理员、多用户、租户、市场、计费或资产交易。 -- 完整 Muse 的产品、业务和总体架构 SoT 在 [`../design-docs/`](../design-docs/);本仓只定义单用户、数据库为权威的简化实现合同,发现通用设计问题后回填父仓 SoT。 +- 完整 Muse 的产品、业务和总体架构 SoT 在 [`../design-docs/`](../design-docs);本仓只定义单用户、数据库为权威的简化实现合同,发现通用设计问题后回填父仓 SoT。 - 本仓正式内容的权威是 PostgreSQL(`muse-example` 库):作品、章、正文、实体、范式、用户决策、运行回执和 raw 都在库里。判断“系统里有没有这个东西”,以库里能不能查到为准;不得把库外的文件或临时快照说成正式内容。 -- Git 是代码、Skill、Agent 提示词、`meta/`、文档和 DDL 的权威,并可以对作品相关信息和作品文本留痕(版本历史与备份);但 Git 留痕不是正式内容权威,正式内容以库为准,只读看板只读库,两者冲突时以库为准。库内向量索引是数据库一侧的检索加速,不是独立权威。可恢复性靠数据库备份加快库里代码与 DDL 重建,见 [数据权威与可视化领域 SoT](.agent/docs/architecture/domains/08-数据权威与可视化领域.md)。 +- Git 是代码、Skill、Agent 提示词、`muse/content/meta/`、文档和 DDL 的权威,并可以对作品相关信息和作品文本留痕(版本历史与备份);但 Git 留痕不是正式内容权威,正式内容以库为准,只读看板只读库,两者冲突时以库为准。库内向量索引是数据库一侧的检索加速,不是独立权威。可恢复性靠数据库备份加快库里代码与 DDL 重建,见 [数据权威与可视化领域 SoT](muse/sot/domains/08-数据权威与可视化领域.md)。 - 本仓继续承担真实创作、拆书、回放评测和候选审查;这些活动服务缩小版 Muse 的能力验证,不把开发期 Gate 当作产品主流程。 ## 2. SoT 与职责边界 @@ -20,57 +20,49 @@ SoT 按主题分域,不做跨主题的全局排序。可执行脚本与书面 |---|---| | [`../AGENTS.md`](../AGENTS.md) + 本文件 | 父仓通用规则与本地创作仓工作边界。更具体的本地规则只做收窄,不取消父仓规则。 | | [`CLAUDE.md`](CLAUDE.md) | Claude Code 兼容入口,只引用本文件,不定义独立规则或 SoT。 | -| [`../design-docs/`](../design-docs/) | Muse 的概念、产品、业务和总体架构 SoT。 | -| [`.agent/docs/architecture/domains/`](.agent/docs/architecture/domains/_index.md) | 本仓领域边界、数据权威、落库合同和领域协作的 SoT。 | -| [`.agent/docs/architecture/边界合同.md`](.agent/docs/architecture/边界合同.md) | 组件职责边界与约束归属的唯一事实源:什么约束放提示词、工具、脚本、静态层;智能体/Skill/工具 server/主代理各自不做什么。 | -| [`meta/schemas/`](meta/schemas/) | 23 型结构本体的字段合同;库内 payload 结构以该合同为准。 | -| [`meta/chains/`](meta/chains/) | scenario、purpose、功能 skill、角色槽位和保护节点的链路登记。 | -| [`.agent/skills/`](.agent/skills/) | 每个 `SKILL.md` 定义项目运行时能力的输入、输出、红线、数据库读写合同和输入产出落库;同目录 `scripts/` 是运行时确定性实现与机械门,开发验证和行为评测入口由 `harness/manifests/` 登记。全量 skill 的发现总索引是 [`.agent/skills/_index.md`](.agent/skills/_index.md):只登记 `skill_name` / `skill_file` / `skill_description` 三字段,由 `harness/skills_index.py` 生成,与磁盘、frontmatter、skills.json 机械对账。 | +| [`../design-docs/`](../design-docs) | Muse 的概念、产品、业务和总体架构 SoT。 | +| [`muse/sot/domains/`](muse/sot/domains/_index.md) | 本仓领域边界、数据权威、落库合同和领域协作的 SoT。 | +| [`muse/sot/边界合同.md`](muse/sot/边界合同.md) | 组件职责边界与约束归属的唯一事实源:什么约束放提示词、工具、脚本、静态层;智能体/Skill/工具 server/主代理各自不做什么。 | +| [`muse/content/meta/schemas/`](muse/content/meta/schemas) | 23 型结构本体的字段合同;库内 payload 结构以该合同为准。 | +| [`muse/lifecycle/flow/chains/`](muse/lifecycle/flow/chains) | scenario、purpose、功能 skill、角色槽位和保护节点的链路登记。 | +| [`.agent/skills/`](.agent/skills/) | 只挂载 15 个 `model_routed` 方法 Skill;编排 Skill 的业务源位于 `muse/**/skills/`。所有位置由 `muse/lifecycle/quality/harness/manifests/skills.json` 的 `skill_path` 登记。 | | [`tests/skills/`](tests/skills/) | Skill 的实现测试、集成测试和 fake pipeline 测试;它们提供回归证据,不拥有运行合同,也不等同于 Skill 行为评测。带确定性实现的 Skill 在此回归,纯模型判断的 Skill 靠行为评测。 | -| [`.agent/`](.agent/_index.md) | 跨任务长期知识;领域设计位于 `docs/architecture/domains/`,新增、删除或重命名必须同步各级 `_index.md`。 | -| [`docs/`](docs/) | 单次任务探索、计划、评测资料、样张和历史执行证据;任务完成后把稳定结论蒸馏到 `.agent/`,不得长期拥有领域定义。 | -| [`README.md`](README.md) | 项目背景和历史路线概览。目录、阶段、技能数量和存储方式等描述可能陈旧,不得覆盖本文件、`meta/`、skill 或磁盘事实。 | +| [`.agent/`](.agent/_index.md) | 运行期挂载面与方法 Skill 索引;领域设计位于 `muse/sot/`,新增、删除或重命名必须同步各级 `_index.md`。 | +| [`docs/`](docs) | 单次任务探索、计划、评测资料、样张和历史执行证据;任务完成后把稳定结论蒸馏到 `muse/sot/` 或 `.agent/`,不得长期拥有领域定义。 | +| [`README.md`](README.md) | 项目背景和历史路线概览。目录、阶段、技能数量和存储方式等描述可能陈旧,不得覆盖本文件、`muse/`、skill 或磁盘事实。 | -`.agent/docs/architecture/domains/` 一个领域一份 SoT,索引只登记 owner 和协作关系,不复制字段与流程细节。`.agent/` 内文档增删改名必须同步对应层级 `_index.md`。`docs/` 只记录单次任务过程、评测资料、样张和历史证据,不得覆盖领域 SoT。父仓 `design-docs/` 已拥有的完整产品概念,本仓只引用并定义单用户本地实现差异。 +`muse/sot/domains/` 一个领域一份 SoT,索引只登记 owner 和协作关系,不复制字段与流程细节。`.agent/` 内挂载内容增删改名必须同步对应层级 `_index.md`。`docs/` 只记录单次任务过程、评测资料、样张和历史证据,不得覆盖领域 SoT。父仓 `design-docs/` 已拥有的完整产品概念,本仓只引用并定义单用户本地实现差异。 ## 3. 真实目录与能力 ```text agent-example/ ├── .git/ # 独立 Git 仓元数据 -├── meta/ -│ ├── schemas/ # 23 型结构设计稿与种子 -│ └── chains/ # 功能链登记表 +├── framework/ # FrameworkPort、Pi 适配器与通用执行对象 ├── .agent/ -│ ├── agents/ # 5 个 LLM 角色(子代理身份定义,派发合同见 07 领域 §2) -│ ├── skills/ # 能力合同及其脚本(发现总索引 _index.md) -│ └── docs/ # 跨任务长期知识与领域设计 SoT -├── db/ -│ ├── ddl/ # 可审计 DDL / 迁移文件 -│ ├── 表映射.md -│ └── 连接信息.md -├── humanization/ # 去 AI 味共享运行时库(muse-deai) -├── muse-db/ # 共享连接模块(muse_db:锁死 DSN 与只读/可写会话) -├── muse-llm/ # 受治理模型与角色运行库(muse_llm / muse_role) -├── muse-embed/ # 知识嵌入库(muse_embed:会话、向量请求、draft 写入) -├── dashboard/ # 只读看板;经 muse_db.connect(readonly=True) 读库 -├── harness/ # 项目验证与外部评测索引、清单和调度支架 -├── tests/ # Skill 实现测试(按 Skill 归档) -├── knowledge/ # 仓内参考资产;未经绑定、授权不得进入上下文 -├── docs/ # 设计、评测、样张与历史执行记录 +│ ├── agents/ # 5 个 LLM 角色身份提示 +│ └── skills/ # 15 个方法 Skill 的嵌套源与方法索引 +├── muse/ +│ ├── sot/ # 领域边界、角色合同与架构 SoT +│ ├── content/ # 作品、实体、范式、结构 schema +│ ├── lifecycle/ # 上下文、创作流程、质量、编排与 harness +│ ├── authority/ # DB、证据、只读看板与决策通道 +│ └── platform/ # 连接、模型、嵌入等共享包 +├── tests/ # Skill 实现测试与架构门禁 +├── docs/ # 计划、评测资料、样张与历史执行记录 ├── .venv/ # 本地 Python 运行环境 ├── requirements.txt # Python 依赖清单 ├── CLAUDE.md # Claude Code 兼容入口,只引用 AGENTS.md └── README.md # 历史概览,不是当前运行态 SoT ``` -5 个角色:`writer`、`planner`、`extractor`、`detector`、`judge`。角色身份在 `.agent/agents/*.md`;稳定角色合同唯一事实源是 [角色合同](.agent/docs/architecture/角色合同.md),不把输入边界、模型策略、工具权限和输出合同散落进角色文件。角色是主会话派发的子代理:按 [07-Agent与Skill领域 §2](.agent/docs/architecture/domains/07-Agent与Skill领域.md) 的派发合同起全新会话,注入身份提示、对应角色合同和冻结输入,输出由派发方校验并落证据;不依赖任何宿主的原生角色装载机制(如 Claude Code `--agent`),Claude CLI 不是角色运行底座。 +5 个角色:`writer`、`planner`、`extractor`、`detector`、`judge`。角色身份在 `.agent/agents/*.md`;稳定角色合同唯一事实源是 [角色合同](muse/sot/角色合同.md),不把输入边界、模型策略、工具权限和输出合同散落进角色文件。Muse 先解析角色合同、冻结上下文、模型策略和输出 Schema,再通过 `FrameworkExecutionRequest` 调用 `framework/adapters/`;当前生产适配器是 Pi。本机 DSH 已更新为 `0.1.1-rc.2`,`web`/`headless` profile 配置检查已通过,但真实模型和 Muse 业务旅程尚未形成证据;DSH 只作为无工具 fresh 对照接缝,不把安装或配置痕迹当生产可用事实。角色是主会话派发的子代理:按 [07-Agent与Skill领域 §2](muse/sot/domains/07-Agent与Skill领域.md) 的派发合同起全新会话,注入身份提示、对应角色合同和冻结输入,输出由派发方校验并落证据;不依赖任何宿主的原生角色装载机制(如 Claude Code `--agent`),Claude CLI 不是角色运行底座。 ### Skill 合同责任方索引 -实际清单以 `.agent/skills/*/SKILL.md` 为准。发现总索引见 [`.agent/skills/_index.md`](.agent/skills/_index.md):58 个 skill 按创作生命周期分 9 域,每条只登记 `skill_name` / `skill_file` / `skill_description` 三字段,description 与 SKILL.md frontmatter 逐字一致。索引由 `harness/skills_index.py --write` 生成;skill 增删改名后必须重新生成,一致性由 `tests/architecture/test_skills_index.py` 机械校验。 +实际清单与物理位置以 `muse/lifecycle/quality/harness/manifests/skills.json` 的 `skill_path` 为准。方法发现总索引见 [`.agent/skills/_index.md`](.agent/skills/_index.md),编排发现索引见 [`muse/_skills_index.md`](muse/_skills_index.md)。索引由 `muse/lifecycle/quality/harness/skills_index.py --write` 生成;skill 增删改名后必须重新生成,一致性由架构测试机械校验。 -本表是另一条轴:登记每个 skill 的合同责任方、协作领域和领域 SoT,不复制各 Skill 的完整合同。每个 skill 必须登记一个合同责任方(业务领域或平台领域),但可以同时消费或影响多个协作领域;跨域调用、场景关系和保护节点在 `meta/chains/` 登记。合同责任方表示谁维护该 Skill 的稳定能力合同,不表示 Skill 只能属于一个业务领域。 +本表是另一条轴:登记每个 skill 的合同责任方、协作领域和领域 SoT,不复制各 Skill 的完整合同。每个 skill 必须登记一个合同责任方(业务领域或平台领域),但可以同时消费或影响多个协作领域;跨域调用、场景关系和保护节点在 `muse/lifecycle/flow/chains/` 登记。合同责任方表示谁维护该 Skill 的稳定能力合同,不表示 Skill 只能属于一个业务领域。 | 合同责任方 / 能力域 | 领域 SoT | Skill | |---|---|---| @@ -82,21 +74,21 @@ agent-example/ | 质量与回放评测 | 06-质量与复利、05-创作流程 | `check-content-consistency`、`score-content-quality`、`adjudicate-quality-gate`、`optimize-content-quality`、`evaluate-frozen-replay`、`replay-writer-gate`、`load-replay-reference-work`、`novel-diagnosis` | | 去 AI 味与人感 | 06-质量与复利、父仓专题-09 | `capture-ai-flavor-cases`、`promote-ai-flavor-rule`、`diagnose-ai-flavor`、`establish-voice-baseline`、`prevent-ai-flavor`、`revise-ai-flavor` | -58 个 skill 一律是本仓正式 skill,受同一套合同与门禁约束,不分等级:都须满足 [07-Agent与Skill领域 §3](.agent/docs/architecture/domains/07-Agent与Skill领域.md) 的合同,都在 `_index.md` 与 `skills.json` 登记,都进质量评分。绑创作 scenario 的在 `meta/chains/` 登记;平台与工具类(如 `call-content-model`、`execute-role-task`、`record-run-evidence`)由主会话或其它 Skill 直接调用,不绑 scenario。 +58 个 skill 一律是本仓正式 skill,受同一套合同与门禁约束,不分等级:都须满足 [07-Agent与Skill领域 §3](muse/sot/domains/07-Agent与Skill领域.md) 的合同,都在 `skills.json` 登记,都进质量评分。其中 15 个方法 Skill 挂在 `.agent/skills/{planning,writing,diagnosis}/` 作为 Muse 源;Pi/DSH 的运行期 catalog 由适配层按 manifest 生成扁平投影。其余编排 Skill 的物理位置由 manifest 的 `skill_path` 管理并由 `muse/_skills_index.md` 发现。绑创作 scenario 的在 `muse/lifecycle/flow/chains/` 登记;平台与工具类由主会话或其它 Skill 直接调用。 **不按"是不是系统运行时"分等级。** 一个 Skill 当前有没有 `scripts/`、有没有数据库合同、有没有接入复利,是实现成熟度而非本质:`plan-chapter`、`expand-scene`、`polish-prose` 以模型判断为主、自身不带 Tool,落库由它们调用的 Skill 承担;`story-structure`、`scene-craft` 一类创作方法 Skill 目前只有 `SKILL.md` 与 `references/`,那是**未接入复利的欠账**,不是它们的天然形态(改造方向见下)。把成熟度写成类别,等于给未完成的 Skill 发永久豁免证。 -`humanization/` 是“去 AI 味与人感”Skill 家族的能力域:`src/deai/` 是共享运行时库(包名 `muse-deai`,经 `requirements.txt` 的 `-e ./humanization` 安装)。被两个以上 Skill 或看板消费的确定性实现一律装成顶层可安装包,所属 Skill 只留 CLI:`muse-db`(连接)、`muse-llm`(模型调用、额度窗与 `muse_role` 角色执行)、`muse-embed`(嵌入),均在 `requirements.txt` 以 `-e ./<包>` 安装。调用方 `import` 已安装的包,不得 `sys.path` 指向 `access-database/scripts`、`call-content-model/scripts`、`embed-knowledge/scripts`、`execute-role-task/scripts`、`establish-voice-baseline/scripts` 或 `humanization/src`;门禁见 [`tests/architecture/test_import_boundaries.py`](tests/architecture/test_import_boundaries.py)。规则与样例的运行时权威是 `example_ai_flavor_rule` / `example_ai_flavor_sample`(DDL-111,`humanization/tools/seed_rules_db.py` 种子同步,生产读取失败关闭,不静默回退 Git);案例卡与声音账同样入库。仓内 YAML/JSON 是迁移种子、离线夹具和结构合同;规则生命周期变更经 YAML 评测/激活后同步入库。规则记录不各自注册为 Skill,Skill 负责动作和消费边界。`humanization/tests`、`tools`、`eval` 仍按包内惯例装载源码树。 +`muse/lifecycle/quality/humanization/` 是“去 AI 味与人感”Skill 家族的能力域:`muse/lifecycle/quality/humanization/src/deai/` 是共享运行时库(包名 `muse-deai`,经 `requirements.txt` 的 `-e ./muse/lifecycle/quality/humanization` 安装)。被两个以上 Skill 或看板消费的确定性实现一律装成顶层可安装包,所属 Skill 只留 CLI:`muse-db`(连接)、`muse-llm`(模型调用、额度窗与 `muse_role` 角色执行)、`muse-embed`(嵌入),分别来自 `muse/platform/db`、`muse/platform/llm`、`muse/platform/embed`,由 `requirements.txt` 以 editable 方式安装。调用方 `import` 已安装的包,不得 `sys.path` 指向 `access-database/scripts`、`call-content-model/scripts`、`embed-knowledge/scripts`、`execute-role-task/scripts`、`establish-voice-baseline/scripts` 或 `muse/lifecycle/quality/humanization/src`;门禁见 [`tests/architecture/test_import_boundaries.py`](tests/architecture/test_import_boundaries.py)。规则与样例的运行时权威是 `example_ai_flavor_rule` / `example_ai_flavor_sample`(DDL-111,`muse/lifecycle/quality/humanization/tools/seed_rules_db.py` 种子同步,生产读取失败关闭,不静默回退 Git);案例卡与声音账同样入库。仓内 YAML/JSON 是迁移种子、离线夹具和结构合同;规则生命周期变更经 YAML 评测/激活后同步入库。规则记录不各自注册为 Skill,Skill 负责动作和消费边界。`muse/lifecycle/quality/humanization/tests`、`tools`、`eval` 仍按包内惯例装载源码树。 -其中 15 个创作方法 Skill 由 7 本写作书的方法论单元按创作领域合并而来(`SKILL.md` 入口 + `references/` 全量内容),供 writer、planner、judge 在对应创作阶段取用。蒸馏与裁剪的历史留痕见 `docs/2026-08-19-craft-distillation-trace.md`(原料与旧 SoT 由 git 历史保留)。**`craft` 不再作为 Skill 的分类标签**:该词在本仓只有一个含义,即公共范式库的范式型之一(技法型,见 [03-范式领域 §2](.agent/docs/architecture/domains/03-范式领域.md))。 +其中 15 个创作方法 Skill 由 7 本写作书的方法论单元按创作领域合并而来(`SKILL.md` 入口 + `references/` 全量内容),供 writer、planner、judge 在对应创作阶段取用。蒸馏与裁剪的历史留痕见 `docs/2026-08-19-craft-distillation-trace.md`(原料与旧 SoT 由 git 历史保留)。**`craft` 不再作为 Skill 的分类标签**:该词在本仓只有一个含义,即公共范式库的范式型之一(技法型,见 [03-范式领域 §2](muse/sot/domains/03-范式领域.md))。 -每个 Skill 的分类字段(`lifecycle` / `invocation` / `side_effects` / `compounding`)统一在 [`harness/manifests/skills.json`](harness/manifests/skills.json) 逐个登记,由 `harness/skill_harness.py` 机械校验;取值定义与质量评分口径见 [`harness/specs/skill-quality-rubric.md`](harness/specs/skill-quality-rubric.md)。 +每个 Skill 的分类字段(`lifecycle` / `invocation` / `side_effects` / `compounding`)统一在 [`muse/lifecycle/quality/harness/manifests/skills.json`](muse/lifecycle/quality/harness/manifests/skills.json) 逐个登记,由 `muse/lifecycle/quality/harness/skill_harness.py` 机械校验;取值定义与质量评分口径见 [`muse/lifecycle/quality/harness/specs/skill-quality-rubric.md`](muse/lifecycle/quality/harness/specs/skill-quality-rubric.md)。 -**复利接入是所有创作 Skill 的共同要求,不是少数 Skill 的特权。** 一个创作 Skill 用过一次之后系统应当更强:它的方法要沉淀为库内可被后续运行消费、可被证据修正的资产(范式卡、AI 味规则、声音账、`example_lesson` 登记),走 [06-质量与复利领域 §6](.agent/docs/architecture/domains/06-质量与复利领域.md) 既有的升格链,不新建平行基建。既有闭环范本是去 AI 味五技能。`compounding = none` 是欠账,由评分维度 D8 记账,现存缺口清单见 `docs/2026-08-20-skill-质量审查与复利改造清单.md`。 +**复利接入是所有创作 Skill 的共同要求,不是少数 Skill 的特权。** 一个创作 Skill 用过一次之后系统应当更强:它的方法要沉淀为库内可被后续运行消费、可被证据修正的资产(范式卡、AI 味规则、声音账、`example_lesson` 登记),走 [06-质量与复利领域 §6](muse/sot/domains/06-质量与复利领域.md) 既有的升格链,不新建平行基建。既有闭环范本是去 AI 味五技能。`compounding = none` 是欠账,由评分维度 D8 记账,现存缺口清单见 `docs/2026-08-20-skill-质量审查与复利改造清单.md`。 -Skill 领域列表的新增、删除、改名或主领域调整,必须同时检查 `.agent/skills/`、`meta/chains/README.md` 和相关领域 `_index.md`,并运行 `harness/skills_index.py --write` 重新生成 Skill 发现总索引;不得只改本表造成索引漂移。 +Skill 领域列表的新增、删除、改名或主领域调整,必须同时检查 manifest 的 `skill_path`、`.agent/skills/` 方法挂载面、`muse/lifecycle/flow/chains/README.md` 和相关领域索引,并运行对应索引生成器;不得只改本表造成索引漂移。 -上下文目标合同以 [上下文领域 SoT](.agent/docs/architecture/domains/04-上下文领域.md) 为准:数据库读取器是核心实现,库内检索加速(向量)只做候选召回;任何命中都要回读库行并校验 hash。Skill 对自己读写哪些表负责,并把经手的输入和产出落库;没落库的输入产出在系统视角里等于不存在。 +上下文目标合同以 [上下文领域 SoT](muse/sot/domains/04-上下文领域.md) 为准:数据库读取器是核心实现,库内检索加速(向量)只做候选召回;任何命中都要回读库行并校验 hash。Skill 对自己读写哪些表负责,并把经手的输入和产出落库;没落库的输入产出在系统视角里等于不存在。 ## 4. 反序验证顺序 @@ -125,7 +117,7 @@ Skill 领域列表的新增、删除、改名或主领域调整,必须同时 ## 6. 模型边界 - 清洗、抽卡、范式拆取及其模型调用统一走 `call-content-model` Skill,不裸调 New-API。治理政策固定为 5 小时额度窗:MiniMax 模型累计花费上限 `$24`,全模型成功调用上限 `6000`;运行适配器、正式配置和账本是额度合同的事实源,共享库 `muse_llm` 与 `muse_db.WINDOW_BUDGET_USD` / `WINDOW_CALL_CAP` 是实现,Skill CLI 只做入口,`test_quota.py` 只提供回归证据;模型链切换必须由该治理入口留下日志。 -- 角色模型归属和派发字段以 [角色合同](.agent/docs/architecture/角色合同.md) 为准:`planner`/`writer`/`judge` 固定 `opus`;`extractor`/`detector` 可在合同允许的治理策略内运行。每次框架调用必须显式传入 `provider`、`model` 和 `thinking`,不得从环境变量静默补全。拆书/导入侧抽取经 `call-content-model`/`deconstruct-book` Skill 走 MiniMax-M3,不走角色 model 派发;创作期章后抽取作为角色派发,可用 `opus`。 +- 角色模型归属和派发字段以 [角色合同](muse/sot/角色合同.md) 为准:`planner`/`writer`/`judge` 固定 `opus`;`extractor`/`detector` 可在合同允许的治理策略内运行。每次框架调用必须显式传入 `provider`、`model` 和 `thinking`,不得从环境变量静默补全。拆书/导入侧抽取经 `call-content-model`/`deconstruct-book` Skill 走 MiniMax-M3,不走角色 model 派发;创作期章后抽取作为角色派发,可用 `opus`。 - 确定性脚本、合同校验、快照冻结、泄漏审计和报告生成不调用模型;除非对应 `SKILL.md` 明确声明模型步骤,不得把机械任务升级为模型任务。 - 固定 Opus 角色生成或评测只在对应任务 SoT、显式预算、冻结 profile 和原文用途授权全部满足后运行;自动化调用走 Anthropic 兼容 HTTP 适配器,不读取 Claude Code 配置,不启动模型 CLI。任一前置门失败都关闭执行。 - 角色的模型策略版本、模型别名、完整模型 ID、预算和回执必须与冻结配置一致。`planner`/`writer`/`judge` 不得因模型不可用而降级到内容模型链或更换供应商;需要变更时先取得明确授权并更新角色合同、profile 与探针。 @@ -143,9 +135,9 @@ Skill 领域列表的新增、删除、改名或主领域调整,必须同时 ## 8. 数据与合规边界 - 主代理和业务 agent 不裸连 PostgreSQL 或 New-API。查询、写入和 DDL 走对应 skill 的 `scripts/`;专用导入、嵌入、检索也走各自 skill。 -- 数据库写入、迁移、授权快照变更和批量运行必须先取得明确授权。DDL 先落 `db/ddl/` 的审计文件,再通过 `access-database` Skill 应用;不得用一次性直连命令绕过。 +- 数据库写入、迁移、授权快照变更和批量运行必须先取得明确授权。DDL 先落 `muse/authority/db/ddl/` 的审计文件,再通过 `access-database` Skill 应用;不得用一次性直连命令绕过。 - 原书全文、完整问答、候选正文、标准答案和供应商响应按 raw 规则进库(单独表加访问控制,只读看板可看全文),授权、冻结边界遵守 `evaluate-frozen-replay` 合同。对外或跨任务引用的最终报告仍只保留评分、摘要、章节定位、失败类别和哈希,不直接复制全文。 -- 未绑定、未授权、来源状态无效或超出用途范围的 `knowledge/` 与数据库来源不得进入上下文;失败时明确记录 `not_authorized`、`stale_source` 等原因,不静默降级。 +- 未绑定、未授权、来源状态无效或超出用途范围的 `muse/content/entity/sources/` 与数据库来源不得进入上下文;失败时明确记录 `not_authorized`、`stale_source` 等原因,不静默降级。 ## 9. 候选、改动与提交 @@ -159,7 +151,7 @@ Skill 领域列表的新增、删除、改名或主领域调整,必须同时 - 明确区分**已验证事实**、**推断**和**假设**。报告必须给出证据来源;没有机械输出或运行证据时,不声称完成、修复或通过。 - 禁止从 `n=1` 样本推出普适结论。至少分析假阴、假阳、样本偏差和混淆因素;需要判断卡或模型效果时使用同任务、同模型、同预算、同公共上下文的对照,并把不稳定样本排除在方向结论之外。 -- Python 一律使用仓内解释器 `.venv/bin/python`。先读目标 Skill 的 `SKILL.md`,再按 `harness/manifests/` 登记的类别和依赖选择相关验证;下面命令仅是现有局部验证入口示例: +- Python 一律使用仓内解释器 `.venv/bin/python`。先读目标 Skill 的 `SKILL.md`,再按 `muse/lifecycle/quality/harness/manifests/` 登记的类别和依赖选择相关验证;下面命令仅是现有局部验证入口示例: ```bash .venv/bin/python tests/skills/plan-chapter/test_contract.py @@ -176,7 +168,7 @@ git diff --check ### 11.1 Agent 提示词(`.agent/agents/*.md` 与角色系统提示词) -角色稳定合同见 [角色合同](.agent/docs/architecture/角色合同.md)。角色文件可以包含 Agent-facing 的身份、Skill 路由、推荐工具能力和工作方法;审查硬边界、模型策略、实际工具权限和结构化输出时以中心合同与适配器为准。 +角色稳定合同见 [角色合同](muse/sot/角色合同.md)。角色文件可以包含 Agent-facing 的身份、Skill 路由、推荐工具能力和工作方法;审查硬边界、模型策略、实际工具权限和结构化输出时以中心合同与适配器为准。 逐条问四个问题: @@ -187,13 +179,13 @@ git diff --check > 反例(已纠正):评测写手提示词曾塞入「你是 Gate A 离线回放的 writer…只输出 candidateBody…不输出哈希/身份…不访问 MCP」,把评测支架混进创作提示词——既没有写作指导,又诱导写手照抄细纲概述句。正解:角色文件保留写作方法、Skill 路由和工具用途;输出格式、实际工具权限、盲化和证据绑定交给中心合同、Schema 与适配器。 -### 11.2 Skill(`.agent/skills/*/`) +### 11.2 Skill(以 `muse/lifecycle/quality/harness/manifests/skills.json` 的 `skill_path` 为准) -分类取值、七个评分维度、必备节清单和严重度定义的 Owner 是 [`harness/specs/skill-quality-rubric.md`](harness/specs/skill-quality-rubric.md);本节只规定审查怎么进行。**先跑机械门,再人工审**,不得用机械门跑绿代替人工判断: +分类取值、七个评分维度、必备节清单和严重度定义的 Owner 是 [`muse/lifecycle/quality/harness/specs/skill-quality-rubric.md`](muse/lifecycle/quality/harness/specs/skill-quality-rubric.md);本节只规定审查怎么进行。**先跑机械门,再人工审**,不得用机械门跑绿代替人工判断: ```bash -.venv/bin/python harness/skill_harness.py --strict # 阻断项与质量发现一并必须为零 -.venv/bin/python harness/test_skill_harness.py -q # 审计器回归 +.venv/bin/python muse/lifecycle/quality/harness/skill_harness.py --strict # 阻断项与质量发现一并必须为零 +.venv/bin/python muse/lifecycle/quality/harness/test_skill_harness.py -q # 审计器回归 ``` 人工逐条问七个问题,括号内是对应维度: diff --git a/README.md b/README.md index 63e3713..511cc4e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ `agent-example` 的目标是成为 Muse 的单用户缩小版,以 PostgreSQL 为正式内容权威:ReAct Agent 通过角色 Agent、Skill 和确定性工具,完成长篇小说的作品管理、实体维护、范式复用、规划、写作、审核、用户决策和经验复利。代码与文档在 Git,正式内容在数据库。 -本项目不包含管理员、多用户、租户、市场、计费和资产交易。完整 Muse 产品、业务和总体架构仍以父仓 [`../design-docs/`](../design-docs/) 为准。 +本项目不包含管理员、多用户、租户、市场、计费和资产交易。完整 Muse 产品、业务和总体架构仍以父仓 [`../design-docs/`](../design-docs) 为准。 ## 数据权威 @@ -24,7 +24,7 @@ Git = 代码 / Skill / 文档 / DDL 的权威,并可 能力:Agent + Skill + Tool + 数据库存储 + 只读看板 ``` -领域边界、数据权威和验收合同见 [`.agent/docs/architecture/domains/_index.md`](.agent/docs/architecture/domains/_index.md)。该目录定义目标行为,不代表所有落库写入和只读看板已经完成实现。 +领域边界、数据权威和验收合同见 [`muse/sot/domains/_index.md`](muse/sot/domains/_index.md)。框架执行端口见 [`framework/README.md`](framework/README.md)。该目录定义目标行为,不代表所有落库写入和只读看板已经完成实现。 ## 当前工程入口 @@ -32,13 +32,16 @@ Git = 代码 / Skill / 文档 / DDL 的权威,并可 agent-example/ ├── AGENTS.md # 项目工作入口与规则 ├── CLAUDE.md # 只引用 AGENTS.md 的兼容入口 -├── .agent/ # 跨任务长期知识与领域设计 SoT -├── .agent/agents/ # 角色 Agent -├── .agent/skills/ # Skill 合同与确定性工具(分类索引见 _index.md) -├── meta/schemas/ # 结构本体与本地字段合同 -├── meta/chains/ # 功能链、场景、用途和角色槽位 -├── knowledge/ # 现有参考资产 -├── db/ # PostgreSQL(正式内容权威)的 DDL 与资料 +├── framework/ # 框架无关执行对象与 Pi 适配器 +├── .agent/ # 角色身份与方法 Skill 挂载源 +│ ├── agents/ # 角色 Agent +│ └── skills/ # 15 个方法 Skill 的嵌套源 +├── muse/ # Muse 业务平面 +│ ├── sot/ # 领域与角色合同 SoT +│ ├── content/ # 作品、实体、范式与结构 schema +│ ├── lifecycle/ # 上下文、流程、质量与 harness +│ ├── authority/ # DB、证据、Studio 与只读工具 +│ └── platform/ # 共享连接、模型、嵌入包 └── docs/ # 单次任务资料、评测样张和历史执行证据 ``` @@ -62,9 +65,9 @@ Gate A/B 是开发期离线能力验收,不是正常用户写一章的生产 ## SoT 顺序 1. 父仓 `design-docs/`:完整 Muse 产品、业务和总体架构。 -2. 本仓 `.agent/docs/architecture/domains/`:单用户、数据库为权威的领域边界。 -3. `meta/`:结构本体和功能链登记。 -4. `.agent/agents/` 与 `.agent/skills/`:角色和可执行能力合同。 +2. 本仓 `muse/sot/domains/`:单用户、数据库为权威的领域边界。 +3. `muse/content/meta/` 与 `muse/lifecycle/flow/chains/`:结构本体和功能链登记。 +4. `.agent/agents/`、`.agent/skills/` 与 `muse/_skills_index.md`:角色、方法与编排能力合同。 5. `docs/`:单次任务过程、评测资料与执行证据,不覆盖稳定 SoT。 所有任务从 [`AGENTS.md`](AGENTS.md) 开始。 diff --git a/docs/2026-07-16-升格卡改造设计.md b/docs/2026-07-16-升格卡改造设计.md index 7dca0e3..1573917 100644 --- a/docs/2026-07-16-升格卡改造设计.md +++ b/docs/2026-07-16-升格卡改造设计.md @@ -213,10 +213,10 @@ flowchart TB | `meta/schemas/faction.yaml` `location.yaml` `event.yaml` | 同上(建议同批补,避免二次改;见拍板点) | schema | | `meta/schemas/character.yaml` | 语义对齐:明确「成长弧线」=未来计划,已发生台阶归「演变历程」(是否给 character 也加演变历程见拍板点) | schema | | `meta/schemas/character_relation.yaml` | 「演变轨迹」说明里"章区间"沿用真实章号(本就如此),确认 aiContext 保持 `true` | schema | -| `.agent/skills/deconstruct-book/scripts/parse_upgrade.py` | ①`APPEND_FIELDS` 加「演变历程」②observe/update 提示词改为记台阶+生命周期+真实章号+原文证据、禁窗号相对指代、当前态字段保持干净 ③合并/立卡/撤销逻辑适配里程碑对象(证据绑定、去重按内容、排序按章号)④判重步接语义近邻+M3 终判(P1) | prompt + 逻辑 | -| `.agent/skills/access-database/scripts/seed_schemas.py` | 不改脚本;schema YAML 改完后**需重跑一次**把新字段和 aiContext 灌进库(本稿不跑,实施时跑) | 种子 | -| `.agent/skills/assemble-context/SKILL.md` | Layer 2 知识卡裁剪说明里,点名"演变历程完整层仅一致性检查可见、续写不给"(机制已支持,补一句说明) | skill 文档 | -| `.agent/skills/check-content-consistency/SKILL.md` | 检查项示例表补一行"演变历程 → 演变连续性/跳级穿帮"(实际自动生成,文档补例) | skill 文档 | +| `muse/content/entity/skills/ingest/deconstruct-book/scripts/parse_upgrade.py` | ①`APPEND_FIELDS` 加「演变历程」②observe/update 提示词改为记台阶+生命周期+真实章号+原文证据、禁窗号相对指代、当前态字段保持干净 ③合并/立卡/撤销逻辑适配里程碑对象(证据绑定、去重按内容、排序按章号)④判重步接语义近邻+M3 终判(P1) | prompt + 逻辑 | +| `muse/authority/evidence/skills/access-database/scripts/seed_schemas.py` | 不改脚本;schema YAML 改完后**需重跑一次**把新字段和 aiContext 灌进库(本稿不跑,实施时跑) | 种子 | +| `muse/lifecycle/context/skills/assemble-context/SKILL.md` | Layer 2 知识卡裁剪说明里,点名"演变历程完整层仅一致性检查可见、续写不给"(机制已支持,补一句说明) | skill 文档 | +| `muse/lifecycle/quality/skills/semantic/check-content-consistency/SKILL.md` | 检查项示例表补一行"演变历程 → 演变连续性/跳级穿帮"(实际自动生成,文档补例) | skill 文档 | | 新增一次性迁移脚本(如 `docs/` 或 skill scripts 下) | 存量卡 [窗N] → 真实章号 + 字符串条目 → 里程碑对象 + 清脏(见 6.1) | 迁移 | **不需要改的**:数据库表结构(演变历程/前身/后继都是知识卡 JSON 里的字段,不需要 DDL 建表/改表);语义判重复用现成的 `example_knowledge_embedding` 向量表和 `embed`/`search` skill,不新建表。 diff --git a/docs/2026-07-30-落库与看板设计.md b/docs/2026-07-30-落库与看板设计.md index faa037e..c8d3c12 100644 --- a/docs/2026-07-30-落库与看板设计.md +++ b/docs/2026-07-30-落库与看板设计.md @@ -2,13 +2,13 @@ > 目标读者:创始人。状态:**设计待审(已吸收四路评审),未动代码**。 > 任务:把"一切输入产出必须落库可见"落成具体的表、写路径与只读看板。 -> SoT 去向:本文件是**任务设计**,不是长期 SoT。实现后蒸馏进三处——表结构进 `db/ddl/`、表清单与约定进 `db/表映射.md`、"哪些输入产出进哪类表"进领域文档(08 §3/§7、01、05、04、06)——届时本文件删除。设计期间这三处不提前改,避免把还没建的表写成既成事实。 +> SoT 去向:本文件是**任务设计**,不是长期 SoT。实现后蒸馏进三处——表结构进 `muse/authority/db/ddl/`、表清单与约定进 `muse/authority/db/表映射.md`、"哪些输入产出进哪类表"进领域文档(08 §3/§7、01、05、04、06)——届时本文件删除。设计期间这三处不提前改,避免把还没建的表写成既成事实。 > v2 相对 v1:吸收四路评审(逻辑闭环 / 可实现性 / 合理性 / SoT 父仓一致性)。表从 6 张增至 8 张(新增运行注册 `example_run`、质量结果 `example_quality_result`);改正来源追溯方向与上下文哈希连接;raw 改靠访问控制;质量评判本期记录可见。 ## 1. 背景与口径 -- 数据权威已翻成 PostgreSQL(`muse-example` 库)为正式内容权威,Git 退回代码与文档的家并可留痕。见 [08-数据权威与可视化领域](../.agent/docs/architecture/domains/08-数据权威与可视化领域.md)。 -- 落库原则唯一 owner 是 [领域索引 §3](../.agent/docs/architecture/domains/_index.md);看板合同唯一 owner 是 [可视化模块合同](../.agent/docs/architecture/可视化模块合同.md)。本设计不重复二者,只把它们落成具体表与写路径。 +- 数据权威已翻成 PostgreSQL(`muse-example` 库)为正式内容权威,Git 退回代码与文档的家并可留痕。见 [08-数据权威与可视化领域](../muse/sot/domains/08-数据权威与可视化领域.md)。 +- 落库原则唯一 owner 是 [领域索引 §3](../muse/sot/domains/_index.md);看板合同唯一 owner 是 [可视化模块合同](../muse/sot/可视化模块合同.md)。本设计不重复二者,只把它们落成具体表与写路径。 - **这套东西的两重定位**:记录留痕的验收面(空白处就是缺口,也是后续抽取优化要补的地方)+ 内容与复利原料的浏览面。 - **诚实的工作量判断**:建表不是主体,真正的成本在写路径改造。其中 raw 进库(§4)、正文 Canonical 写入层(§2.9)不是"改现有写点",是新建组件或重定义安全合同;planner 落库(§2.6)是从零建一条管线。第 2/3/4 步工作量按此估计,不当成顺手事。 @@ -34,12 +34,12 @@ 建表约定(照现有 `91/96` 风格): -- 文件名 `db/ddl/<编号>-<中文主题>.sql`,编号从 **97** 起(90–96 已占)。`CREATE TABLE IF NOT EXISTS`;主键 `id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY`。 +- 文件名 `muse/authority/db/ddl/<编号>-<中文主题>.sql`,编号从 **97** 起(90–96 已占)。`CREATE TABLE IF NOT EXISTS`;主键 `id BIGINT GENERATED ALWAYS AS IDENTITY PRIMARY KEY`。 - **公共列分界**(统一口径,文件头各写理由):运行态设施表(`example_llm_call`)**不带**业务公共列(仿 `95`);业务溯源账本(候选/决策/规划/冻结/raw/质量结果)带归属列 `creator/create_time/tenant_id`;**append-only 表一律不带 `updater/update_time/deleted` 三死列**(禁改删时它们永不写入)。 - **append-only 表**(回执/决策/冻结/raw/质量结果)用 BEFORE UPDATE OR DELETE 触发器禁改写(仿 `96`);可变表(候选/规划)带 `trg_*_updated_at`。 - 唯一键含归属、命名 `uk_example_*`;CHECK `chk_example_*`;索引 `idx_example_*`。 - **哈希归一规则**:runtime/CAS 系用 `sha256:`(71 字符),snapshot 系用裸 64 hex。**入库一律剥 `sha256:` 前缀存裸 64 hex**,列统一 `CHAR(64)`;读取按列语义决定是否复原。所有 `*_sha256` 列同此。 -- 一律 `.venv/bin/python .agent/skills/access-database/scripts/db.py apply db/ddl/<文件>`,整文件单事务回滚。 +- 一律 `.venv/bin/python muse/authority/evidence/skills/access-database/scripts/db.py apply muse/authority/db/ddl/<文件>`,整文件单事务回滚。 ## 2. 表设计 @@ -80,7 +80,7 @@ - **用途**:登记 AI 待审候选(Shadow)。今天候选是内存对象 `InMemoryCasStateStore`;关联字段全在 `CandidateEnvelope v2`。 - **形态**:可变表(状态流转),带归属列 + updated_at 触发器。 - **列**:`id` PK;`work_id BIGINT NOT NULL`(→ 作品);`target_chapter INTEGER NOT NULL`;`run_id VARCHAR(64)`(→ run;**merge 候选的 run_id = 复检重跑那次运行**,因为用户改后合并的版本没有生成 run,其"产出"是用户编辑 + 一次重跑检测,见 §2.9 来源说明);`attempt INTEGER`;`run_type VARCHAR(20) NOT NULL`(**production/eval/diagnostic——评测候选不得成正文,05 §8.4 四层机械隔离的第一层;`acceptance_eligible` 是由 run_type 派生的缓存位,以 run_type 为准**);`candidate_version VARCHAR(32) NOT NULL`;`candidate_sha256 CHAR(64) NOT NULL`;`candidate_body TEXT`(候选正文,看板待审视图直接读;候选表整体按 raw 级访问控制——见 §4,**不重复塞 raw 表**);`context_sha256 CHAR(64)`(→ freeze.context_sha256);`quality_policy_version VARCHAR(32)`;`mode VARCHAR(20)`(continuation/rewrite/expansion/polish);`source_role VARCHAR(20)`;`state VARCHAR(20) NOT NULL DEFAULT 'draft'`;`acceptance_eligible BOOLEAN`;归属列 + `update_time`/`deleted`。 -- **状态机**(对齐 [05 §3](../.agent/docs/architecture/domains/05-创作流程领域.md),列名/值与 05 统一): +- **状态机**(对齐 [05 §3](../muse/sot/domains/05-创作流程领域.md),列名/值与 05 统一): ```text draft -> checking -> passed (机械门 + 语义检测 + 质量审核通过) @@ -152,7 +152,7 @@ accepted -> archived (归档,对齐 05 单条 ACCEPTED→ARCHIVE 这是看板"沿来源下钻"立身之本,也是评审最集中的洞,单列前置合同: -- **方向**:来源权威落在**正文块自身**,不是决策表的正向指针。依据父仓 [架构-02 §3](../../../design-docs/架构-02-核心数据结构与双轨模型.md):"正文来源归因是当前正文 revision 的一部分,不能只依赖历史候选 Archive"。父仓正文块来源归因表(`muse_content_block_source_attribution`,主仓 V1 已有、暂空置)存 `decision_id` **反向引用**决策归档。 +- **方向**:来源权威落在**正文块自身**,不是决策表的正向指针。依据父仓 [架构-02 §3](../../design-docs/架构-02-核心数据结构与双轨模型.md):"正文来源归因是当前正文 revision 的一部分,不能只依赖历史候选 Archive"。父仓正文块来源归因表(`muse_content_block_source_attribution`,主仓 V1 已有、暂空置)存 `decision_id` **反向引用**决策归档。 - **用主仓现成表,不另起炉灶**:`muse_content_block_source_attribution`(`block_id + revision + source_type + source_object_id + source_version + lineage_payload JSONB + authorization_snapshot_id`,唯一键 `(tenant_id, block_id, revision)`)天生**按版本归因**——一章可 accept→merge→merge 出多个 revision,每个 revision 一行归因,`lineage_payload` 装候选身份(candidate_id/run_id/candidate_sha256)。这解决了"revision=2 是哪次决策造成的"。 - **`user_decision.canonical_block_id` 降级**为冗余正向指针(看板从决策跳正文用),**不当唯一溯源路径**。 - **写正文 Canonical 写入层**:本设计的前置依赖,不是顺手事,**提为独立子任务并估工**。写入序列(单事务,定死 crash-in-between 形态): @@ -211,13 +211,13 @@ accepted -> archived (归档,对齐 05 单条 ACCEPTED→ARCHIVE 2. **run 成功终态的新定义**:今天 `COMPLETED` 的必要条件是 `raw_disposition_ok`(migrate 成功),CAS 终态记 `cleanup_state=migrated/failed`。raw 常驻库后 migrate 降为**可选仓外备份**,`COMPLETED` 改以"raw 已落库(lease+content 写入成功)"为终态判据;`cleanup_state` 枚举与 manifest 的 `rawDisposition` 相应重定义。连带 `test_raw_vault.py / test_run_writer_replay.py / test_audit_leakage.py` 重写。 3. **授权门简化(不启用 96)**:单用户本地,授权人/使用者/机器是同一人,原"用途授权有效(关联 96 快照)"门改为轻量出处门——raw 须来自已导入参考书(`source_work_id` → `example_reference_work`,出处可溯)且仅本地用途即可;不做版权状态/用途数组/到期重验那套多租户合规仪式。`run_authorization_id` 仅记运行授权出处(运行时对象,不查库)。密钥/token 禁入表的门保留。 -**对账父仓**:raw 全量留存是对 [专题-05 §9.2](../../../design-docs/专题-05-AI统一交互协议与外部AgentAdapter设计.md)"provider 原始响应默认不长期保存"的**刻意覆盖**——单用户锻炉需全量 raw 可见以供走查;密钥/凭据禁入表仍从父仓(§9.1)。此覆盖写明于 08 §5。 +**对账父仓**:raw 全量留存是对 [专题-05 §9.2](../../design-docs/专题-05-AI统一交互协议与外部AgentAdapter设计.md)"provider 原始响应默认不长期保存"的**刻意覆盖**——单用户锻炉需全量 raw 可见以供走查;密钥/凭据禁入表仍从父仓(§9.1)。此覆盖写明于 08 §5。 -**改写落点**(实现第 4 步动):08 §5、runtime `SKILL.md`、[可视化模块合同 §5](../.agent/docs/architecture/可视化模块合同.md)、`db/表映射.md`。§4 旧 raw 清单删"未接受候选正文"、`raw_content.kind` 删 `candidate`(候选正文单存候选表,整表 raw 级访问控制——对齐 08 §3 落库合同表)。 +**改写落点**(实现第 4 步动):08 §5、runtime `SKILL.md`、[可视化模块合同 §5](../muse/sot/可视化模块合同.md)、`muse/authority/db/表映射.md`。§4 旧 raw 清单删"未接受候选正文"、`raw_content.kind` 删 `candidate`(候选正文单存候选表,整表 raw 级访问控制——对齐 08 §3 落库合同表)。 ## 5. 看板模块设计 -合同在 [可视化模块合同](../.agent/docs/architecture/可视化模块合同.md),这里只补实现排序: +合同在 [可视化模块合同](../muse/sot/可视化模块合同.md),这里只补实现排序: - **只读硬约束**(机械门):独立只读连接(`SET TRANSACTION READ ONLY`);全代码 grep 无 `INSERT/UPDATE/DELETE`/DDL;不接写通道;挂了不牵连创作链。 - **技术形态**:纯标准库 HTTP 服务端渲染(仿 open-wenmo hub),无 SPA 框架;查库复用 `.venv` psycopg **只读连接**。 @@ -241,7 +241,7 @@ accepted -> archived (归档,对齐 05 单条 ACCEPTED→ARCHIVE 每步验收(对照各领域 SoT): -1. DDL 先落 `db/ddl/` 再 apply;`db/表映射.md` 同步登记。 +1. DDL 先落 `muse/authority/db/ddl/` 再 apply;`muse/authority/db/表映射.md` 同步登记。 2. 写路径走 db skill 参数化短连接;离线自测覆盖关键路径与失败路径,失败明确失败关闭。 3. 看板对应视图渲染实时数据;未建表显示"无数据/待落库"。 4. 全链路无密钥/token 进表;raw 受访问控制。 @@ -250,15 +250,15 @@ accepted -> archived (归档,对齐 05 单条 ACCEPTED→ARCHIVE ## 7. 关联 SoT 与蒸馏去向 -- 落库原则 owner:[领域索引 §3](../.agent/docs/architecture/domains/_index.md) -- 存储/可恢复/raw/回执字段合同:[08](../.agent/docs/architecture/domains/08-数据权威与可视化领域.md) §3/§5/§7 -- 候选状态机/绑定键/接受语义/评测隔离:[05](../.agent/docs/architecture/domains/05-创作流程领域.md) §3/§5/§8.4 -- 候选/规划存储结构:[01](../.agent/docs/architecture/domains/01-作品领域.md) -- 上下文冻结与取数:[04](../.agent/docs/architecture/domains/04-上下文领域.md) -- 质量评判记录与量表版本:[06](../.agent/docs/architecture/domains/06-质量与复利领域.md) §3/§5/§9 -- 正文来源归因方向:[父仓 架构-02 §3](../../../design-docs/架构-02-核心数据结构与双轨模型.md);归因表 `muse_content_block_source_attribution`(主仓 V1) +- 落库原则 owner:[领域索引 §3](../muse/sot/domains/_index.md) +- 存储/可恢复/raw/回执字段合同:[08](../muse/sot/domains/08-数据权威与可视化领域.md) §3/§5/§7 +- 候选状态机/绑定键/接受语义/评测隔离:[05](../muse/sot/domains/05-创作流程领域.md) §3/§5/§8.4 +- 候选/规划存储结构:[01](../muse/sot/domains/01-作品领域.md) +- 上下文冻结与取数:[04](../muse/sot/domains/04-上下文领域.md) +- 质量评判记录与量表版本:[06](../muse/sot/domains/06-质量与复利领域.md) §3/§5/§9 +- 正文来源归因方向:[父仓 架构-02 §3](../../design-docs/架构-02-核心数据结构与双轨模型.md);归因表 `muse_content_block_source_attribution`(主仓 V1) - 决策归档命名锚定:父仓 后端-04 §7/§11(Candidate Decision Archive);ADR-018(删的是 Decision Envelope) -- raw 留存对账:[父仓 专题-05 §9.2](../../../design-docs/专题-05-AI统一交互协议与外部AgentAdapter设计.md) -- 只读看板合同:[可视化模块合同](../.agent/docs/architecture/可视化模块合同.md) -- 表清单与现状:[`db/表映射.md`](../db/表映射.md) -- 蒸馏去向:实现后表结构→`db/ddl/97–102`;清单约定→`db/表映射.md`;"哪些输入产出进哪类表"具体表名→08 §3。本文件届时删除。 +- raw 留存对账:[父仓 专题-05 §9.2](../../design-docs/专题-05-AI统一交互协议与外部AgentAdapter设计.md) +- 只读看板合同:[可视化模块合同](../muse/sot/可视化模块合同.md) +- 表清单与现状:[`muse/authority/db/表映射.md`](../muse/authority/db/表映射.md) +- 蒸馏去向:实现后表结构→`muse/authority/db/ddl/97–102`;清单约定→`muse/authority/db/表映射.md`;"哪些输入产出进哪类表"具体表名→08 §3。本文件届时删除。 diff --git a/docs/2026-08-19-craft-distillation-trace.md b/docs/2026-08-19-craft-distillation-trace.md index fa15c0e..831317e 100644 --- a/docs/2026-08-19-craft-distillation-trace.md +++ b/docs/2026-08-19-craft-distillation-trace.md @@ -128,7 +128,7 @@ test-prompts.json。 ## 蒸馏来源单元对照(自 SKILL.md frontmatter 迁入,2026-08-20) 原 frontmatter 的 `domain` / `sources` 两个字段无任何代码消费,且 `domain` 已由 -`harness/manifests/skills.json` 的 `lifecycle` 承载。来源出处属历史留痕,不该常驻 +`muse/lifecycle/quality/harness/manifests/skills.json` 的 `lifecycle` 承载。来源出处属历史留痕,不该常驻 运行时提示词,于此保存后从 frontmatter 移除。 | Skill | 原 domain | 来源单元 | diff --git a/docs/2026-08-20-skill-质量审查与复利改造清单.md b/docs/2026-08-20-skill-质量审查与复利改造清单.md index 31f5267..4d5281b 100644 --- a/docs/2026-08-20-skill-质量审查与复利改造清单.md +++ b/docs/2026-08-20-skill-质量审查与复利改造清单.md @@ -1,8 +1,8 @@ # Skill 质量审查与复利改造清单(2026-08-20) > 性质:一次性审查记录与改造方案,不是 SoT。 -> 评分口径 Owner:[`harness/specs/skill-quality-rubric.md`](../harness/specs/skill-quality-rubric.md)。 -> 复利链与升格判据 Owner:[06-质量与复利领域 §6](../.agent/docs/architecture/domains/06-质量与复利领域.md)。 +> 评分口径 Owner:[`muse/lifecycle/quality/harness/specs/skill-quality-rubric.md`](../muse/lifecycle/quality/harness/specs/skill-quality-rubric.md)。 +> 复利链与升格判据 Owner:[06-质量与复利领域 §6](../muse/sot/domains/06-质量与复利领域.md)。 ## 1. 结论摘要 diff --git a/docs/2026-08-20-质量收敛环运行手册.md b/docs/2026-08-20-质量收敛环运行手册.md index 7704768..19ff720 100644 --- a/docs/2026-08-20-质量收敛环运行手册.md +++ b/docs/2026-08-20-质量收敛环运行手册.md @@ -1,6 +1,6 @@ # 质量收敛环运行手册(实验性) -> **状态**:历史实验流程,不是任何 Skill 的现行合同。现行归因入口是 [`optimize-content-quality`](../.agent/skills/optimize-content-quality/SKILL.md)(只出建议);评分归 [`score-content-quality`](../.agent/skills/score-content-quality/SKILL.md);Gate 终态归 [`adjudicate-quality-gate`](../.agent/skills/adjudicate-quality-gate/SKILL.md)。 +> **状态**:历史实验流程,不是任何 Skill 的现行合同。现行归因入口是 [`optimize-content-quality`](../muse/lifecycle/quality/skills/judge/optimize-content-quality/SKILL.md)(只出建议);评分归 [`score-content-quality`](../muse/lifecycle/quality/skills/judge/score-content-quality/SKILL.md);Gate 终态归 [`adjudicate-quality-gate`](../muse/lifecycle/quality/skills/mechanical/adjudicate-quality-gate/SKILL.md)。 ## 目标 diff --git a/docs/design/深渊机神-前期设计.md b/docs/design/深渊机神-前期设计.md index c8f5d03..f299fbb 100644 --- a/docs/design/深渊机神-前期设计.md +++ b/docs/design/深渊机神-前期设计.md @@ -5,7 +5,7 @@ > - 设计定稿后,拆分为各领域数据入库(设定卡 / 规划 / 文风 / 细纲)。 > - 每个小节标注「待定 / 已定」;定稿才标「已定」。 > - 第一章“根设定”只保存作品自身的稳定事实与叙事硬约束,不记录设计过程、工具、方案来源或候选比较。 -> - 可复用流程由 [`design-story-foundation`](../../.agent/skills/design-story-foundation/SKILL.md) 维护;本文只保留本书专属设定与待定内容。 +> - 可复用流程由 [`design-story-foundation`](../../muse/lifecycle/flow/skills/book/design-story-foundation/SKILL.md) 维护;本文只保留本书专属设定与待定内容。 > - 初步设定定稿采用相同的 12 章目录与编号号段,每章按内容编写 10—50 项设定。 ## 目录 diff --git a/docs/plans/2026-08-23-目录分层改造.md b/docs/plans/2026-08-23-目录分层改造.md new file mode 100644 index 0000000..39751e9 --- /dev/null +++ b/docs/plans/2026-08-23-目录分层改造.md @@ -0,0 +1,563 @@ +# 目录分层改造 plan + +日期:2026-08-23 +范围:`agent-example/` 本仓;父仓仅改仍指向本仓旧路径的活文档。 +状态:**已被取代,不再作为执行入口。** + +> **取代**:后续执行以 [2026-08-24-双底座适配接缝](2026-08-24-双底座适配接缝.md) 为准。 +> **原因**:本文件按「尚未有 `framework/`、先把 58 个 Skill 嵌套搬家」起草;工作树已迁出 `muse/` 与 `framework/`,但依赖方向未分开。DSH 默认 Skill Provider 不递归 `**/SKILL.md`,第 4–5 节把方法 Skill 沉到 `planning/` `writing/` 的发现合同不能原样接到 DSH。架构事实见父仓 [DSH / Pi 与 Muse 的框架业务分离研究](../../../docs/research/dsh-pi-muse-framework-business-separation-2026-08-23.md)。 +> 映射表(第 8 节)仍可当「已经搬到哪」的对照,不作为下一阶段工单。 + +--- + +## 1. 意图 + +把现在根上摊开的一排目录,收成路径能读出来的四层: + +```text +L1 framework / .agent / muse / docs 框架、挂载、产品、过程? +L2 primitives|adapters · sot|content|lifecycle|authority|platform +L3 C1–C6 或 八领域 +L4 skills / tools / db / studio / chains +``` + +判定轴不变:`framework/` 拥有 C1–C6(Agent / Skill / MCP / Tool / 可追踪 / 可审计);Muse 拥有书、人闸、库、额度。`.agent/` 只是运行期挂载面,不是所有权。 + +本改造**搬家 + 改发现合同 + 改文档路径**,不改创作状态机、人闸、CAS、表结构。 + +--- + +## 2. 完成的定义 + +每一阶段结束必须同时满足: + +1. **磁盘**按该阶段映射表就位(`git mv`,禁止 copy+delete)。 +2. **活文档**里被本阶段碰到的路径全部改完,点击能到达新位置。 +3. **机械门禁绿**:见该阶段验证命令。无自动化绿证据不得声称该阶段完成。 + +全改造完成的总门禁是阶段 G 的路径扫描:活文档和运行时代码里不得再出现已废弃根路径。 + +--- + +## 3. 明确不做 + +- 不改候选状态机、CAS、raw 三件套、事件账本表结构。 +- 不给智能体写库、不合并只读看板与决策通道。 +- 不把额度、Opus 锁、看板、Gate A/B 写进 `framework/`。 +- 不把 `tests/skills//` 下沉到各 Skill 目录(`parents[N]` 会大面积碎;阶段 G 之后另开)。 +- 不在本改造里拆 Skill 内部为 `schema/` + `scripts/`(那是下一层,不阻塞本次)。 +- 不改 `docs/write-chapter/artifacts/` 运行产物。 +- 不改 git 历史里的旧路径。 + +--- + +## 4. 目标树(压缩) + +```text +agent-example/ +├── AGENTS.md +├── framework/ # C1–C6 原语 + 宿主适配器 +│ ├── primitives/{agent,skill,mcp,tool,trace}/ +│ ├── adapters/{pi,dsh,claude-code,codex}/ +│ └── tests/ +├── .agent/ # 运行期挂载:框架扫、Muse 写 +│ ├── agents/ # 五角色身份 +│ └── skills/{planning,writing,diagnosis}/ # 仅 15 个方法 Skill +├── muse/ +│ ├── sot/ # 现 muse/sot/ +│ ├── content/{meta,work,entity,paradigm}/ +│ ├── lifecycle/{context,flow,quality,dispatch}/ +│ ├── authority/{db,evidence,tools,studio}/ +│ └── platform/{db,embed,llm}/ +└── docs/ # 过程与历史;本 plan 也在这里 +``` + +58 个 Skill 的落点以第 8 节映射表为准。`skills.json` 的 `skill_path` 是位置事实源。 + +--- + +## 5. 发现合同(先改代码,再搬家) + +现状假设 Skill 都在 `.agent/skills//SKILL.md`(`skill_harness.py` 约 891 行:`SKILLS_ROOT / name / "SKILL.md"`)。不先拆掉这个假设,任何嵌套 `git mv` 都会让 58 条 manifest 对账一起红。 + +目标: + +| 面 | 谁读 | 扫哪里 | +|---|---|---| +| 运行期 catalog | 创作智能体 / 框架 Skill 发现 | 只扫 `.agent/skills/**/SKILL.md`(方法 Skill) | +| 编排索引 | 主代理 / 开发者 | `harness/manifests/skills.json` + 生成的 Muse 索引 | +| 位置 SoT | 门禁 | `skills.json` 的 `skill_path`(允许任意相对路径) | + +硬门禁(阶段 C 装上,阶段 D 之后必须绿): + +- `invocation=model_routed` → `skill_path` 必须在 `.agent/skills/` 下。 +- `invocation=orchestrated` → `skill_path` 必须在 `muse/` 下。 +- `name` 仍等于 `SKILL.md` 的父目录名。 +- 框架 catalog 不得列出 orchestrated Skill。 + +方法 Skill 闭集(15 个,其余全部 `orchestrated`): + +`concept-design` `story-planning` `story-structure` `narrative-momentum` `foreshadow-payoff` `story-ending` `scene-craft` `dialogue-craft` `character-design` `character-presentation` `show-and-omission` `narration-pov` `prose-craft` `theme-and-stance` `novel-diagnosis` + +当前误标为 `model_routed`、必须改成 `orchestrated` 再迁出 catalog 的: + +`access-database` `call-content-model` `clean-book-text` `confirm-knowledge-draft` `embed-knowledge` `import-book` `optimize-content-quality` `review-knowledge-cards` `search-knowledge` + +`search-knowledge` 最终进 `muse/lifecycle/context/`(编排)或工具 server;不进方法 catalog。只读五工具的实现进 `muse/authority/tools/read/`,不是 Skill catalog。 + +--- + +## 6. 阶段 + +依赖:A 可先于一切搬家;B 与 A 可并行;C 依赖 A;D 依赖 A+C;E 依赖 D;F 可与 E 同批但提交分开;G 最后。 + +```text +A 发现层去扁平假设 → B 拆出 framework/ → C catalog 收口与方法 Skill 嵌套 + → D 编排 Skill 迁入 muse/ → E 平台与权威目录迁入 muse/ → F SoT 与链接改写 → G 路径门禁收口 +``` + +每阶段一个(或一组紧密)提交。禁止把「尚未改完文档」的搬家标完成。 + +### 阶段 A:发现层去扁平假设(不搬家) + +意图:运行时与门禁按 `skill_path` 找 Skill,不再假定 `.agent/skills//SKILL.md`。 + +改: + +- `harness/skill_harness.py`:删 `expected_path = SKILLS_ROOT / name / "SKILL.md"`;以 manifest `skill_path` 为准;保留「name == 父目录名」。 +- `harness/skills_index.py`:`skill_file` 原样来自 `skill_path`;允许嵌套。 +- `harness/run_selected.py`、`tests/architecture/test_import_boundaries.py`:扫描根改为可配置列表,本阶段仍指向旧根,避免误伤。 +- 增加「从任意子目录走到含 `AGENTS.md` 的仓根」的小函数,后续搬家不再靠 `parents[N]`。`dashboard/`、`tests/skills/*` 里现成的 `parents[1]` / `parents[3]` 本阶段可暂留。 + +文档(本阶段仍是旧路径,只改发现合同的表述): + +- `AGENTS.md` §3:写明「物理目录位置是 `skills.json` 的 `skill_path`,不要求一级子目录」。 +- `harness/README.md`、`harness/specs/skill-quality-rubric.md`、`07-Agent与Skill领域.md` §3:把「`.agent/skills/{name}/SKILL.md`」改成「`skill_path` 指向的 `SKILL.md`」。 + +验证: + +```bash +.venv/bin/python harness/skill_harness.py --strict +.venv/bin/python harness/skills_index.py --check +.venv/bin/python tests/architecture/test_skills_index.py +.venv/bin/python tests/architecture/test_import_boundaries.py +``` + +完成:现有扁平布局下上述全绿;再人为把某个 `skill_path` 写成嵌套路径且文件也在嵌套处时,harness 仍接受(可用临时夹具测,测完还原)。 + +### 阶段 B:拆出 `framework/`(Skill 目录先不动) + +意图:把 C1–C6 从 `dispatch-agent-task/scripts/` 抽到 `framework/`。派发 Skill 仍暂住 `.agent/skills/dispatch-agent-task/`,只改它内部 import。 + +改: + +| 现在 | 目标 | +|---|---| +| `agent_task.py` 中的任务包/白名单/事件归一 | `framework/primitives/{agent,tool,trace}/` | +| `pi_runner.py` | `framework/adapters/pi/runner.py` | +| `muse_read_tools_extension.ts` | `framework/adapters/pi/mcp_bridge.ts` | +| `read_tools.py` | **先**迁到 `framework/` 的旁路?**否**。本阶段仍留在 dispatch 目录,阶段 E 再进 `muse/authority/tools/read/` | +| `dispatch_agent_task.py` | 仍留 Skill 内,改为调用 `framework` | + +`FRAMEWORK_ADAPTER_ALLOWLIST` 改为 `framework/adapters/pi/runner.py`。 + +协议暂不删除 `SUPPORTED_AGENT_ROLES` 对五角色的绑定(那是行为收缩,另开);本阶段只搬家与 import。 + +文档: + +- `dispatch-agent-task/SKILL.md` 模块表改指向 `framework/…` +- `边界合同.md` 工具 server / 框架派发的「结构」列补 `framework/adapters/` +- `07` §2 执行底座:写明「唯一碰框架二进制的位置是 `framework/adapters/`」 + +验证: + +```bash +.venv/bin/python tests/architecture/test_import_boundaries.py +.venv/bin/python tests/skills/dispatch-agent-task/test_dispatch_agent_task.py +``` + +(dispatch 测试若依赖真实 pi,按现有离线项跑;不把真实模型调用算进本阶段。) + +### 阶段 C:catalog 收口 + 方法 Skill 嵌套 + +意图:运行期 catalog 只剩 15 个方法 Skill;它们按规划/写作/诊断嵌套。误标 `model_routed` 的改成 `orchestrated`(必须与搬家同提交,否则新门禁自相矛盾)。 + +改: + +```text +git mv .agent/skills/concept-design .agent/skills/planning/ +git mv .agent/skills/story-planning .agent/skills/planning/ +git mv .agent/skills/story-structure .agent/skills/planning/ +git mv .agent/skills/narrative-momentum .agent/skills/planning/ +git mv .agent/skills/foreshadow-payoff .agent/skills/planning/ +git mv .agent/skills/story-ending .agent/skills/planning/ +git mv .agent/skills/scene-craft .agent/skills/writing/ +git mv .agent/skills/dialogue-craft .agent/skills/writing/ +git mv .agent/skills/character-design .agent/skills/writing/ +git mv .agent/skills/character-presentation .agent/skills/writing/ +git mv .agent/skills/show-and-omission .agent/skills/writing/ +git mv .agent/skills/narration-pov .agent/skills/writing/ +git mv .agent/skills/prose-craft .agent/skills/writing/ +git mv .agent/skills/theme-and-stance .agent/skills/writing/ +git mv .agent/skills/novel-diagnosis .agent/skills/diagnosis/ +``` + +`skills.json`:15 条 `skill_path` 改嵌套;9 条误标改为 `orchestrated`。生成索引。装上门禁:`model_routed` ⊆ `.agent/skills/`。 + +文档: + +- `AGENTS.md`:发现入口改为「方法 Skill → `.agent/skills/_index.md`;编排 Skill 仍以 `skills.json` 为总账(阶段 D 后再加 Muse 索引)」。 +- `创作周期与Skill导读.md`:15 个方法 Skill 的链接改到新路径。 +- 各方法 Skill 的 `SKILL.md` 若写了兄弟路径(`../scene-craft`),改成新相对路径。 +- `.agent/skills/_index.md` 用生成器重写,不得手改。 + +验证: + +```bash +.venv/bin/python harness/skills_index.py --write && \ +.venv/bin/python harness/skills_index.py --check +.venv/bin/python harness/skill_harness.py --strict +.venv/bin/python tests/architecture/test_skills_index.py +``` + +另加(本阶段落地):`model_routed` 路径前缀断言。15 个方法 Skill 的 frontmatter 仍是 `model_routed`。 + +### 阶段 D:编排 Skill 迁入 `muse/` + +意图:43 个 orchestrated Skill 离开 `.agent/skills/`。之后框架即使全量扫挂载面,也看不见写库通道。 + +按第 8 节表 `git mv`。同步: + +- `harness/manifests/skills.json` 全部 `skill_path` +- `tests/skills//` **不迁**(仍按 Skill 名平铺);测试内的 `Path(".agent") / "skills" / ""` 改为读 manifest 或仓根查找函数 +- `dashboard/decision_channel.py`、`dashboard/lesson_confirm.py` 的 `SKILLS = ROOT / ".agent" / "skills"` 改为新路径(或经 manifest 解析) +- `test-inventory.json` 里写死的 `.agent/skills/...` 路径 +- 生成第二份索引:`muse/sot/skills-index.md` 或 `muse/_skills_index.md`(编排发现);`.agent/skills/_index.md` 只含 15 个方法 Skill + +文档: + +- `AGENTS.md` §3 目录树与 Skill 责任方表:编排 Skill 的路径改 `muse/…` +- `meta/chains/README.md`(此时仍在旧处):功能 Skill 链接改新路径 +- `07` §3:系统能力 Skill 的磁盘位置改为 `muse/…/skills//SKILL.md` +- 每只被迁 Skill 的 `SKILL.md`、其它 Skill 对它的相对链接 +- `创作周期与Skill导读.md` 全部编排 Skill 卡片链接 +- `harness/README.md`、`harness/specs/*` + +验证:同上 harness 三条 + import boundaries + 抽跑 `tests/skills/decide-candidate`、`write-next-chapter`、`assemble-context`、`dispatch-agent-task` 这些硬编码过路径的测试。 + +完成:`.agent/skills/` 下只剩 `planning/` `writing/` `diagnosis/` `_index.md`。 + +### 阶段 E:平台与权威目录迁入 `muse/` + +```text +git mv db muse/authority/db +git mv dashboard muse/authority/studio # 随后在 studio 内再分成 read/ 与 write/ +git mv meta/schemas muse/content/meta/schemas +git mv meta/chains muse/lifecycle/flow/chains +git mv knowledge muse/content/entity/sources +git mv humanization muse/lifecycle/quality/humanization +git mv harness muse/lifecycle/quality/harness +git mv muse-db muse/platform/db +git mv muse-llm muse/platform/llm +git mv muse-embed muse/platform/embed +``` + +`dashboard/` 进 `studio/` 后立刻拆: + +```text +muse/authority/studio/read/ # 现 server.py :8765 +muse/authority/studio/write/decision # 现 decision_channel.py :8767 +muse/authority/studio/write/lesson # 现 lesson_confirm.py :8766 +``` + +`read_tools.py` 从 dispatch Skill 迁到 `muse/authority/tools/read/`(可按五工具分子目录,本阶段至少落到 `read/` 包)。Pi 的 `mcp_bridge.ts` 只保留桥,SQL 不回去。 + +`requirements.txt`: + +```text +-e ./muse/platform/db +-e ./muse/platform/llm +-e ./muse/platform/embed +-e ./muse/lifecycle/quality/humanization +``` + +包名 `muse-db` / `muse-llm` / `muse-embed` / `muse-deai` 不变。迁完后 `uv pip install -r requirements.txt` 重装 editable。 + +`test_import_boundaries.py` 的 `ACTIVE_RUNTIME_ROOTS`、`FORBIDDEN_PATHS`、扫描范围改新根。`run_selected.py` 扫描根改新路径。humanization 测试里 `parents[2]` / `sys.path` 指向 `humanization/src` 的,改到新树(或继续靠已安装包 `import deai`,与现门禁一致)。 + +文档:凡写 `db/` `dashboard/` `humanization/` `harness/` `meta/` `muse-db/` `knowledge/` 作为**仓内路径**的活文档,全部改。包括 `db/表映射.md`、`可视化模块合同.md`、`08`、看板 docstring、`harness/README.md`(此时已在 quality/harness 下,相对链接要重算)。 + +验证: + +```bash +uv pip install --python .venv/bin/python -r requirements.txt +.venv/bin/python -c "import muse_db, muse_llm, muse_embed, deai" +.venv/bin/python tests/architecture/test_import_boundaries.py +.venv/bin/python muse/lifecycle/quality/harness/skill_harness.py --strict +.venv/bin/python muse/authority/studio/read/test_server_display.py +``` + +(具体测试文件随 `git mv` 走;命令以搬完后的真实路径为准。) + +### 阶段 F:SoT 迁到 `muse/sot/` + 全量链接 + +```text +git mv muse/sot muse/sot +``` + +`.agent/docs/` 若空则删;`.agent/_index.md` 只保留挂载面(agents / skills),SoT 指针改 `muse/sot/`。 + +代码: + +- `muse_role_contract.py`:`ROLE_CONTRACT_RELATIVE_PATH = Path("muse") / "sot" / "角色合同.md"` +- dispatch 测试里 `roleContractSource` 断言同步 +- `dashboard/server.py` 头部合同路径 + +**相对链接**:SoT 从 `muse/sot/` 迁走后,所有 `../muse/sot/…` 和 SoT 内部链到 `../../../.agent/skills`、`../../../../docs/` 的链接按新深度重写。这是本阶段主工作量。 + +活文档清单见第 7 节。本阶段结束时第 7 节每一条都指向新路径。 + +父仓:`design-docs/流程-02B-普通用户系统处理流程(系统视角).md` 中 + +`../agent-example/muse/sot/domains/02-实体领域.md` + +改为 + +`../agent-example/muse/sot/domains/02-实体领域.md` + +(父仓单独提交,不和本仓混。) + +验证:阶段 G 的扫描在本阶段应已接近全绿;允许本 plan 文件和「旧路径」对照表暂时命中。 + +### 阶段 G:路径门禁收口 + +装常驻门禁 `tests/architecture/test_layout_paths.py`(名称可改,职责不可改): + +1. 根目录只允许:`AGENTS.md` `CLAUDE.md` `README.md` `requirements.txt` `.agent/` `framework/` `muse/` `docs/` `tests/` 以及既有的 `.git` `.venv` `.gitignore` 等仓务。不得再出现 `db/` `dashboard/` `harness/` `humanization/` `meta/` `muse-db/` `muse-llm/` `muse-embed/` `knowledge/`。 +2. `.agent/skills/` 下除 `_index.md` 外只有 `planning/` `writing/` `diagnosis/`。 +3. `invocation` 与路径前缀符合第 5 节。 +4. 活文档与运行时代码扫描:下列字符串不得作为路径出现(排除 `docs/plans/` 本文件、`docs/write-chapter/artifacts/`): + +```text +muse/sot +.agent/skills/dispatch-agent-task +.agent/skills/decide-candidate +.agent/skills/access-database +.agent/skills/write-next-chapter +humanization/src +-e ./muse-db +-e ./humanization +dashboard/server.py +db/ddl/ +harness/manifests/skills.json +meta/chains/ +``` + +(列表以搬完后的废弃前缀为准,装门禁时用生成器从「映射表旧路径」收,避免手写漏项。) + +5. Markdown 链接目标文件必须存在(死链失败关闭)。覆盖:`muse/sot/**/*.md` `AGENTS.md` `README.md` `.agent/**/*.md` `muse/**/*.md` 中仍被 SoT 引用的 `docs/*.md`。 + +全量验证(阶段 G 完成判据): + +```bash +.venv/bin/python tests/architecture/test_layout_paths.py +.venv/bin/python tests/architecture/test_import_boundaries.py +.venv/bin/python tests/architecture/test_skills_index.py +.venv/bin/python muse/lifecycle/quality/harness/skill_harness.py --strict +``` + +再按 `test-inventory.json` 跑与路径相关的离线实现测试(至少 dispatch、decide-candidate、assemble-context、write-next-chapter、看板 display)。不把真实模型 / 真库写入当成本次改造的完成证据;碰到因路径而找不到夹具的,修路径后再跑原来的离线项。 + +--- + +## 7. 文档更新清单(活文档,必须改) + +「活」= 现在仍被当作合同、入口或教学地图阅读。过程 plan 与运行产物不在此列。 + +### 7.1 入口(阶段 C–F 随目录改,F 收齐) + +| 文件 | 改什么 | +|---|---| +| `AGENTS.md` | 目录树、SoT 表、Skill 发现入口(两份索引)、责任方表路径、§3/§11 中的 `.agent/skills` 假设 | +| `README.md` | 目录树、SoT 顺序 | +| `.agent/_index.md` | 挂载面 vs `muse/sot` | +| `.agent/docs/_index.md` | 若目录删除则本文件删除或改为跳转 | + +### 7.2 SoT(阶段 F 为主,此前被碰到的链接提前改) + +| 文件 | 改什么 | +|---|---| +| `muse/sot/_index.md`(现 architecture/_index.md) | 相对链接深度 | +| `边界合同.md` | 结构列:`framework/`、`muse/authority/tools`、`muse/authority/studio` | +| `角色合同.md` | `promptFile` 仍是 `.agent/agents/*.md`;其它仓内路径 | +| `可视化模块合同.md` | `dashboard/` → studio;`db/表映射.md` | +| `创作周期与Skill导读.md` | 全部 Skill 链接 + 导语里的 58 只平铺假设;方法 / 编排两份索引 | +| `domains/_index.md` | Git 权威那一行的 `meta/`、相对链到 `docs/` | +| `domains/01`–`08` | 文中磁盘路径与交叉链接深度 | +| `07` §3 | `{name}` 扁平公式 | + +### 7.3 规范与登记 + +| 文件 | 改什么 | +|---|---| +| `harness/README.md` 及 specs(迁后在 quality/harness) | 适用范围、Owner 路径 | +| `skills.json` / 生成的两份 `_index.md` | 每条 `skill_path` | +| `meta/chains/README.md`(迁后 flow/chains) | humanization 链接、05 链接、功能 Skill 路径 | +| `db/表映射.md` `连接信息.md` | 自身相对位置;`db/ddl/` 字面 | +| 各 `SKILL.md` | 入口命令、相对 `scripts/`、兄弟 Skill 链接 | +| `.agent/agents/*.md` | 若写了 Skill 路径则改(现多为名字不带路径,抽查) | + +### 7.4 仍被 SoT 引用的 `docs/` 设计稿 + +这些不是领域 SoT,但链还活着,不改就是死链: + +- `docs/2026-07-14-参考书作品面数据入库方案.md` +- `docs/2026-07-16-升格卡改造设计.md` +- `docs/2026-07-30-落库与看板设计.md` +- `docs/2026-08-01-评测harness改造设计.md` +- `docs/2026-08-19-craft-distillation-trace.md` +- `docs/2026-08-20-skill-质量审查与复利改造清单.md` +- `docs/2026-08-20-质量收敛环运行手册.md` +- `docs/acceptance/` 下仍引用旧路径的验收记录 + +### 7.5 父仓 + +| 文件 | 改什么 | +|---|---| +| `design-docs/流程-02B-普通用户系统处理流程(系统视角).md` | `agent-example/muse/sot/domains/02-实体领域.md` → `muse/sot/domains/…` | + +开工前再扫一遍: + +```bash +rg -n 'agent-example/\.agent/docs|agent-example/\.agent/skills|agent-example/db/|agent-example/dashboard' \ + --glob '!agent-example/docs/plans/**' --glob '!**/artifacts/**' +``` + +新命中补进本表,禁止口头「应该没有了」。 + +### 7.6 不改 + +- 本文件(对照表需要旧路径) +- `docs/write-chapter/artifacts/` +- 已删除的整体收敛 plan(git 历史) + +--- + +## 8. Skill 映射表(阶段 C/D 执行 SoT) + +### 8.1 方法 Skill → `.agent/skills/`(catalog) + +| name | 目标 | +|---|---| +| concept-design | `.agent/skills/planning/concept-design/` | +| story-planning | `.agent/skills/planning/story-planning/` | +| story-structure | `.agent/skills/planning/story-structure/` | +| narrative-momentum | `.agent/skills/planning/narrative-momentum/` | +| foreshadow-payoff | `.agent/skills/planning/foreshadow-payoff/` | +| story-ending | `.agent/skills/planning/story-ending/` | +| scene-craft | `.agent/skills/writing/scene-craft/` | +| dialogue-craft | `.agent/skills/writing/dialogue-craft/` | +| character-design | `.agent/skills/writing/character-design/` | +| character-presentation | `.agent/skills/writing/character-presentation/` | +| show-and-omission | `.agent/skills/writing/show-and-omission/` | +| narration-pov | `.agent/skills/writing/narration-pov/` | +| prose-craft | `.agent/skills/writing/prose-craft/` | +| theme-and-stance | `.agent/skills/writing/theme-and-stance/` | +| novel-diagnosis | `.agent/skills/diagnosis/novel-diagnosis/` | + +### 8.2 编排 Skill → `muse/` + +| name | 目标 | +|---|---| +| write-next-chapter | `muse/content/work/skills/generate/write-next-chapter/` | +| expand-scene | `muse/content/work/skills/generate/expand-scene/` | +| polish-prose | `muse/content/work/skills/generate/polish-prose/` | +| rewrite-selection | `muse/content/work/skills/generate/rewrite-selection/` | +| decide-candidate | `muse/content/work/skills/sovereignty/decide-candidate/` | +| import-book | `muse/content/entity/skills/ingest/import-book/` | +| clean-book-text | `muse/content/entity/skills/ingest/clean-book-text/` | +| deconstruct-book | `muse/content/entity/skills/ingest/deconstruct-book/` | +| extract-work-knowledge | `muse/content/entity/skills/ingest/extract-work-knowledge/` | +| inspect-parse-health | `muse/content/entity/skills/ingest/inspect-parse-health/` | +| backup-work-extraction | `muse/content/entity/skills/ingest/backup-work-extraction/` | +| repair-work-extraction | `muse/content/entity/skills/ingest/repair-work-extraction/` | +| reset-work-extraction | `muse/content/entity/skills/ingest/reset-work-extraction/` | +| extract-chapter-knowledge | `muse/content/entity/skills/extract/extract-chapter-knowledge/` | +| review-knowledge-cards | `muse/content/entity/skills/review/review-knowledge-cards/` | +| confirm-knowledge-draft | `muse/content/entity/skills/sovereignty/confirm-knowledge-draft/` | +| freeze-context | `muse/lifecycle/context/skills/freeze-context/` | +| assemble-context | `muse/lifecycle/context/skills/assemble-context/` | +| search-knowledge | `muse/lifecycle/context/skills/search-knowledge/` | +| embed-knowledge | `muse/lifecycle/context/skills/embed-knowledge/` | +| design-story-foundation | `muse/lifecycle/flow/skills/book/design-story-foundation/` | +| merge-story-candidates | `muse/lifecycle/flow/skills/book/merge-story-candidates/` | +| plan-story | `muse/lifecycle/flow/skills/book/plan-story/` | +| plan-chapter | `muse/lifecycle/flow/skills/chapter/plan-chapter/` | +| adjudicate-quality-gate | `muse/lifecycle/quality/skills/mechanical/adjudicate-quality-gate/` | +| check-content-consistency | `muse/lifecycle/quality/skills/semantic/check-content-consistency/` | +| score-content-quality | `muse/lifecycle/quality/skills/judge/score-content-quality/` | +| optimize-content-quality | `muse/lifecycle/quality/skills/judge/optimize-content-quality/` | +| evaluate-frozen-replay | `muse/lifecycle/quality/skills/replay/evaluate-frozen-replay/` | +| replay-writer-gate | `muse/lifecycle/quality/skills/replay/replay-writer-gate/` | +| load-replay-reference-work | `muse/lifecycle/quality/skills/replay/load-replay-reference-work/` | +| establish-voice-baseline | `muse/lifecycle/quality/humanization/skills/establish-voice-baseline/` | +| prevent-ai-flavor | `muse/lifecycle/quality/humanization/skills/prevent-ai-flavor/` | +| diagnose-ai-flavor | `muse/lifecycle/quality/humanization/skills/diagnose-ai-flavor/` | +| revise-ai-flavor | `muse/lifecycle/quality/humanization/skills/revise-ai-flavor/` | +| capture-ai-flavor-cases | `muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/` | +| promote-ai-flavor-rule | `muse/lifecycle/quality/humanization/skills/promote-ai-flavor-rule/` | +| dispatch-agent-task | `muse/lifecycle/dispatch/skills/dispatch-agent-task/` | +| record-run-evidence | `muse/authority/evidence/skills/record-run-evidence/` | +| access-database | `muse/authority/evidence/skills/access-database/` | +| call-content-model | `muse/platform/llm/skills/call-content-model/` | +| execute-role-task | `muse/platform/llm/skills/execute-role-task/` | +| refresh-runtime-probe | `muse/platform/llm/skills/refresh-runtime-probe/` | + +15 + 43 = 58。增删 Skill 先改本表再 `git mv`。 + +### 8.3 非 Skill 目录 + +| 现在 | 目标 | +|---|---| +| `.agent/agents/` | 不动 | +| `muse/sot/` | `muse/sot/` | +| `db/` | `muse/authority/db/` | +| `dashboard/server.py` | `muse/authority/studio/read/` | +| `dashboard/decision_channel.py` | `muse/authority/studio/write/decision/` | +| `dashboard/lesson_confirm.py` | `muse/authority/studio/write/lesson/` | +| `meta/schemas/` | `muse/content/meta/schemas/` | +| `meta/chains/` | `muse/lifecycle/flow/chains/` | +| `knowledge/` | `muse/content/entity/sources/` | +| `humanization/` | `muse/lifecycle/quality/humanization/` | +| `harness/` | `muse/lifecycle/quality/harness/` | +| `muse-db/` | `muse/platform/db/` | +| `muse-llm/` | `muse/platform/llm/` | +| `muse-embed/` | `muse/platform/embed/` | +| `dispatch …/read_tools.py` | `muse/authority/tools/read/` | +| `dispatch …/pi_runner.py` | `framework/adapters/pi/runner.py` | +| `tests/skills/` `tests/architecture/` | 不动 | +| `docs/` | 不动 | + +--- + +## 9. 约束 + +1. **先改发现,再搬家。** 违反则 harness 会用旧公式打红 58 条,看起来像「目录改造失败」,其实是门禁还停在扁平假设。 +2. **文档跟提交走。** 不允许「代码已迁、README 下一批再改」。阶段完成清单含第 7 节被本阶段碰到的行。 +3. **`git mv`。** 需要嵌套时先 `mkdir -p` 再 `git mv`。 +4. **invocation 与目录同提交**(阶段 C)。 +5. **包名稳定、路径变。** `import muse_db` 不变;变的是 `-e ./…`。 +6. **测试按 Skill 名平铺留下**,避免本次范围膨胀。 +7. 阶段 G 的路径门禁是本改造的完成牙齿;没有它只能算「搬过」,不能算完成。 + +--- + +## 10. 开工顺序(执行时从这里抄) + +1. 阶段 A:harness 去扁平 + 三份发现文档。 +2. 阶段 B:`framework/` + allowlist + dispatch SKILL.md。 +3. 阶段 C:15 个 `git mv` + 9 条 invocation + 生成索引 + catalog 门禁 + 导读链接。 +4. 阶段 D:43 个 `git mv` + manifest + 看板/测试里的 Skill 根 + AGENTS.md 双索引。 +5. 阶段 E:平台/权威 `git mv` + requirements + 重装 + 工具 server 迁出 dispatch。 +6. 阶段 F:`muse/sot` + `ROLE_CONTRACT_RELATIVE_PATH` + 第 7 节全表 + 父仓 流程-02B。 +7. 阶段 G:`test_layout_paths.py` 绿。 diff --git a/docs/plans/2026-08-24-双底座适配接缝.md b/docs/plans/2026-08-24-双底座适配接缝.md new file mode 100644 index 0000000..383e330 --- /dev/null +++ b/docs/plans/2026-08-24-双底座适配接缝.md @@ -0,0 +1,304 @@ +# 双底座适配接缝 plan + +日期:2026-08-24 +范围:`agent-example/`;父仓仅改仍指向本仓旧路径的活文档。 +状态:取代 [2026-08-23-目录分层改造](2026-08-23-目录分层改造.md),作为当前执行入口;阶段 0、阶段 1 与阶段 2 的无宿主门禁已落地,DSH 配置与无凭据失败闭环已核实,真实模型、只读工具闭集和 Muse 业务旅程仍未验收。 +架构事实:[DSH / Pi 与 Muse 的框架业务分离研究](../../../docs/research/dsh-pi-muse-framework-business-separation-2026-08-23.md)(2026-08-23;DSH 上游 `0.1.1-rc.2` / Pi 本机 `0.84.2`)。 + +--- + +## 1. 意图 + +上一轮目录分层抓住了主权边界,但不能再按「把 58 个 Skill 搬进嵌套目录」当主路径执行。 + +正确合同: + +> **DSH / Pi 负责一次 Agent 如何运行;Muse 负责作品现在是什么、候选能否进正典、用户做了什么决定。** +> 代码上可以只有 `muse/` 与 `framework/`,中间必须有一条适配接缝。适配器不是第三个业务所有者。 + +目标结构: + +```text +Muse 业务层 + 作品 / 正文 / 实体 / 范式 + Context Freeze / asOf / 候选 CAS / 人闸 / 额度 / 证据 + Studio / 决策通道 + │ + │ FrameworkPort + ▼ +framework/ + RoleTaskRequest 由 Muse 解析之后,只进下面三类对象: + FrameworkExecutionRequest / FrameworkEvent / FrameworkExecutionResult + ┌────┴────┐ + ▼ ▼ + adapters/pi adapters/dsh + │ │ + Pi DSH + Cordis +``` + +本改造先把**依赖方向**拆开,再用同一份冻结任务接 DSH 最小切片。不再把剩余 `git mv` 当主工单。 + +--- + +## 2. 对上一份 plan 的修正 + +| 旧 plan 假设 | 核对后的事实 | +|---|---| +| `framework/` 还不存在,从拆 dispatch 五文件开始 | `framework/primitives/agent` 与 `framework/adapters/pi` 已在盘上 | +| 目录分开 ≈ 框架业务分开 | 目录已分开;`runner.py` 仍 `import agent_trace`,`agent_task.py` 仍加载 Muse 角色合同,`dispatch_agent_task.py` 仍做 `fixed-opus` 检查 | +| 方法 Skill 沉到 `.agent/skills/{planning,writing,diagnosis}/` 即可被任何宿主发现 | 嵌套已经发生。DSH 默认 Skill Provider **不支持**递归 `**/SKILL.md`。不能回滚嵌套,必须加扁平投影或自定义 `SkillProvider` | +| 「插件 / Skill / Agent」是 DSH 原生三层 | DSH 原生是 Cordis service、scope、event waterfall、Session、Agent preset、subagent provider。Muse 的三层是上层约定,不能把 Skill 文本当权限 | +| `dsh-llm-pi-ai` 能复用 Pi coding agent | 它只用 `@earendil-works/pi-ai`。DSH 与 Pi coding agent 仍是两个适配器 | +| session log 投影进库可以当原子审计 | DSH `session/event` 观察与持久化异步分开;session log 是执行事实,不是内容权威 | +| 用 `agent/turn-stopping` 当 JSON Schema 门 | 结构化输出由 Muse 任务宿主或明确声明该能力的 Provider 校验 | + +旧 plan 第 8 节映射表描述的 **muse/ 落点大体已经在盘上**。剩余缺口是 SoT 仍在 `muse/sot/`、入口文档目录树仍写旧根、以及框架反向依赖业务。 + +--- + +## 3. 当前磁盘(执行起点,不是目标) + +根上已是 `framework/` + `muse/` + `.agent/`(方法 Skill 嵌套)+ `docs/` + `tests/`。`requirements.txt` 已指向 `muse/platform/*` 与 `muse/lifecycle/quality/humanization`。 + +仍未拆开的耦合(本轮已读源码,不是推断): + +| 位置 | 问题 | +|---|---| +| `framework/adapters/pi/runner.py` | `from agent_trace import AgentTraceWriter` | +| `framework/primitives/agent/agent_task.py` | `import muse_role` / `muse_role_contract`;`SUPPORTED_AGENT_ROLES` 绑死五个 Muse 角色 | +| `muse/lifecycle/dispatch/skills/dispatch-agent-task/scripts/dispatch_agent_task.py` | 在派发前做 `fixed-opus` 模型策略检查 | +| `tests/architecture/test_import_boundaries.py` | 适配器白名单已是 `framework/adapters/pi/runner.py`,**不**禁止框架 import 业务证据脚本 | + +Skill 发现: + +- Muse harness 已扫 `.agent/skills` 与 `muse` 下 `**/SKILL.md`,以 `skills.json` 的 `skill_path` 为位置 SoT。 +- 15 个方法 Skill 已在 `.agent/skills/{planning,writing,diagnosis}//`。 +- 编排 Skill 已在 `muse/**/skills//`。 +- DSH 默认发现器对这套嵌套布局会漏掉方法 Skill,除非自定义 Provider 或生成扁平投影。 + +本机运行基线(2026-08-24)已核实:`dsh --version` 为 `0.1.1-rc.2`;`dsh --profile web --dump-config` 与 `dsh --profile headless --dump-config` 退出码为 0;无 API key 的 headless 任务按 `MISSING_CREDENTIAL` 失败关闭。该事实只证明 profile 可组合和错误路径可达,不证明真实模型或 Muse 业务旅程可用。`framework/adapters/dsh/` 已补无工具 fresh 对照适配器与 session JSONL 归一测试,生产默认仍是 Pi。 + +Skill strict 门禁在研究采样点为 9 个 `blocking` + 2 个 `major`,迁移稳定后必须重跑;采样数字不构成当前完成证据。 + +--- + +## 4. 稳定对象(先固化,再写适配器) + +```text +Muse RoleTaskRequest + 角色、业务任务、冻结上下文、模型策略、输出 Schema + │ Muse 解析(角色合同、额度、fixed-opus / governed-chain) + ▼ +FrameworkExecutionRequest + system prompt、user content、工具闭集、已解析模型、超时、会话模式 + │ 适配器 + ▼ +FrameworkEvent + framework、session、sourceSeq、kind、payload hash + │ + ▼ +FrameworkExecutionResult + final output、actual model、usage、stop reason、artifact locator + │ 回到 Muse + ▼ +Schema 门 → 一致性检测 → 质量审核 → 人闸 +``` + +框架只处理后三类。`workId` / `targetChapter` / `candidateStatus` / `acceptanceEligible` 不得成为框架判断条件。 + +插件可以做:只读 Context Tools、角色 Prompt Provider、工具准入与 asOf 防护、事件观察与 raw 导出、可选 Trajectory / TUI。 +不得做成模型可喊 Skill:`decide-candidate`、`confirm-knowledge-draft`、`record-run-evidence`、`freeze-context`、`assemble-context`、Canonical 写入、CAS、人闸、额度结算。 + +--- + +## 5. Skill 挂载:不回滚嵌套,补发现投影 + +方法 Skill 的**所有权**留在 `.agent/skills/{planning,writing,diagnosis}/`(Muse 源)。 +DSH / Pi 只消费同一源的**扁平投影**,禁止复制第二份正文: + +```text +.agent/skills/planning/scene-craft/SKILL.md # 源(已在盘上;scene-craft 实际在 writing/) +framework/catalog/dsh/skills/scene-craft/SKILL.md # 生成物:单层 /SKILL.md +framework/catalog/pi/… # 若 Pi 也需要显式 override,同样生成 +``` + +生成器读 `skills.json` 里 `invocation=model_routed` 的条目,写出 DSH 能发现的 `/SKILL.md`(链接或渲染,不是手改副本)。编排 Skill 不进该投影。 + +机械门: + +- `model_routed` 必须在 `.agent/skills/` 下;`orchestrated` 必须在 `muse/` 下。 +- 业务 manifest、Pi catalog、DSH catalog 三方对账。 +- DSH 默认发现器扫到的名字集合 = `model_routed` 闭集;漏发现失败关闭。 + +二选一实现,阶段三开工前裁定,不允许「嵌套了就算 DSH 能用」: + +1. 生成扁平投影(推荐,零运行时插件)。 +2. 自定义 DSH `SkillProvider` 读 `skills.json`。 + +--- + +## 6. 阶段 + +依赖:0 可与 1 并行;2 依赖 1;3 依赖 0+1+2 且本机有可执行 `dsh`(或 CI 固定版本);4 依赖 3 的同源对照证据。 + +```text +0 活文档与 Skill 门禁基线 +1 收紧 Pi 接缝(对象拆分 + 依赖方向) +2 跨框架协议、工件与门禁 +3 DSH 最小切片:writer / planner +4 detector / extractor / judge → 再决定生产主宿主 +``` + +不把「迁完剩余目录 / 把 SoT 搬到 muse/sot」做成前置。那些跟提交走,不单独开搬家阶段。 + +### 阶段 0:活文档与 Skill 门禁基线 + +意图:入口文档不再描述已不存在的根目录;Skill strict 失败项先清成后续迁移基线。 + +改: + +- `AGENTS.md` §3 目录树改成当前 `framework/` + `muse/` + `.agent/skills/{planning,writing,diagnosis}`。 +- `README.md`、`.agent/_index.md` 同步。 +- 研究采样点的 9 个 `blocking` + 2 个 `major`:先重跑 `muse/lifecycle/quality/harness/skill_harness.py --strict`,按**当场输出**修 invocation / 死链,不沿用采样数字。 +- `test_import_boundaries.py` 扫描范围去掉已不存在的根(若仍列 `dashboard/` 作 ACTIVE root,改成 `muse/authority/studio` 或删除空根)。 + +验证: + +```bash +.venv/bin/python muse/lifecycle/quality/harness/skill_harness.py --strict +.venv/bin/python tests/architecture/test_skills_index.py +.venv/bin/python tests/architecture/test_import_boundaries.py +``` + +文档:本阶段只改入口树与发现合同表述,不改领域 SoT 正文。 + +### 阶段 1:收紧当前 Pi 接缝 + +意图:Pi 行为与回执字段不变;框架不再拥有 Muse 合同。 + +改: + +1. 拆 `AgentTaskSpec`: + - Muse:`RoleTaskRequest`(角色、冻结输入、`modelPolicyRef`、`outputSchemaRef`、`toolPolicyRef`、`contextRef`)。 + - framework:`FrameworkExecutionRequest`(已拼好的 system/user、工具闭集、已解析 model id、超时、`fresh|continue`、仅 `runId` 关联)。 +2. `AgentTraceWriter` 改为注入的 `TraceSink` 协议;`framework/adapters/pi/runner.py` 删除 `import agent_trace`。 +3. `fixed-opus` / `governed-chain` 校验移出 dispatch 里「看起来像框架」的位置,回到 Muse 角色策略(dispatch 在调用 adapter **之前**解析模型;adapter 只记账 requested/actual)。 +4. `agent_task.py` 不再 `import muse_role_contract`。角色文件与角色合同的装配留在 `muse/lifecycle/dispatch/`。 +5. 端口纯度门:`framework/` 不得 import `agent_trace`、Postgres、候选状态机、`muse_role_contract`、额度常量。 + +验证(必须证明「重构不改业务结果」): + +```bash +.venv/bin/python tests/architecture/test_import_boundaries.py +.venv/bin/python tests/skills/dispatch-agent-task/test_dispatch_agent_task.py +.venv/bin/python tests/skills/record-run-evidence/test_agent_trace.py +``` + +新增:`tests/architecture/test_framework_port_purity.py`(扫描 `framework/` 的 forbidden import)。现有 dispatch 离线项全绿;不把真实模型调用算完成。 + +文档:`framework/README.md`、`dispatch-agent-task/SKILL.md`、`边界合同.md` 结构列、`07` §2 执行底座——写明三类框架对象与 Muse 解析职责。 + +### 阶段 2:跨框架协议与真实工件 + +意图:Pi 与未来 DSH 共用同一套 Event / Result,而不是各自发明业务含义。 + +改: + +- 固化 `FrameworkExecutionRequest` / `FrameworkEvent` / `FrameworkExecutionResult` Schema(Draft 2020-12),放 `framework/primitives/`。 +- 事件必须带 `framework`、`frameworkVersion`、`sessionId`、`sourceSeq`、`payloadSha256`;未知事件进 raw,不得丢弃后声称轨迹完整。 +- 定义 Pi JSONL / 运行目录 transcript 与(预留)DSH session artifact 的定位、hash、flush 规则。flush 前 = live view;flush 后完整工件 = 审计证据。投影幂等、可检测 seq gap。 +- 只读五工具输出保持结构化 JSON;Pi 与 DSH 只做工具适配,SQL 仍在 `muse/authority/tools/read/`。 +- Skill 扁平投影生成器(或记录「阶段 3 用自定义 Provider」的书面裁定)落地,并加三方对账测试。 + +验证:flush / 崩溃重放 / seq gap / 重复投影的离线测试;catalog 对账测试。无 `dsh` 二进制时,DSH artifact 规则用夹具,不假装跑过 DSH。 + +文档:协议 Schema 本身是合同;`08` 只引用「执行日志 ≠ 正典」,不复制字段。 + +### 阶段 3:DSH 最小切片(writer / planner) + +前置:本机或 CI 有**可执行**的固定版本 `dsh`。本机已满足该安装前置(`0.1.1-rc.2`),但真实模型、只读工具插件和同源业务旅程仍未验收;没有这些证据不得把阶段 3 或 DSH 生产接入标记完成。 + +只做: + +- `framework/adapters/dsh/`:唯一碰 `dsh` 二进制/SDK 的位置,列入适配器白名单。 +- 一个 profile:只读工具插件 + 角色 preset/prompt section + `tools.guard` + 事件观察 + 最终工件导出。 +- 自定义 `SkillProvider` **或**消费阶段 2 的扁平投影。 +- 能力矩阵:角色 × 场景 × Provider 声明 `toolFilter` / `persona` / `outputSchema` / continuable;不支持则**启动前失败**,禁止静默降级。 +- 评委不在本阶段。子代理默认 `spawn` 新会话。 + +对照: + +```text +同一 RoleTaskRequest(冻结输入 + 角色合同 + 模型策略) + ├── Pi Adapter + └── DSH Adapter + ↓ +同一 Schema 门 / 一致性检测 / 质量审核 / 人闸 +``` + +对照指标:Schema 合规、工具越权、asOf 泄漏、超时与恢复、轨迹完整性。质量分数是观察项,不代替机械门。 + +不做:迁 58 个 Skill、DSH 内嵌正文台、Canonical 写入插件、detector/extractor/judge。 + +文档:`framework/adapters/dsh/README.md`、`docs/research/2026-08-24-dsh-local-runtime-baseline.md`;`07` 补「双适配器、单一业务门」;AGENTS.md 写明生产默认仍是 Pi,直到阶段 4 有证据。 + +### 阶段 4:其余角色与生产主宿主 + +- 先 detector / extractor,再 judge。评委必须 fresh spawn,禁止 fork 父历史;进程外 Provider 缺能力则启动失败。 +- Trajectory / Conversation Node 只投影执行;Studio 仍读库。节点必须带稳定业务 ID。 +- 以同源对照的机械指标 + 标注为 external-live 的旅程证据,决定 DSH 是否成为默认执行宿主。没有回放和失败恢复证据前,Pi 保留为可用适配器。 +- 两者都不得写 Canonical。 + +--- + +## 7. 机械门(阶段 1 起逐条装,阶段 3 齐) + +1. **端口纯度**:`framework/` 不得 import 业务证据、库、候选状态机、角色合同、额度。 +2. **能力矩阵**:Provider 不支持的能力启动前失败。 +3. **Canonical 写入**:模型可见工具闭集无写正典动作;写者白名单。 +4. **冻结与泄漏**:只读工具核验 `workId` / `asOf`;未来章、oracle、其他评委结果不可见。 +5. **结构化输出**:Draft 2020-12,不用 turn-stopping 冒充。 +6. **轨迹完整性**:源 session、sourceSeq、hash;flush 后才算审计;投影幂等。 +7. **Skill 发现**:manifest / Pi 投影 / DSH 投影对账;嵌套源不得被当成 DSH 已发现。 +8. **双框架黄金旅程**:同一冻结任务两臂,后续统一进 Muse 门。adapter fake 不算宿主证据。 +9. **版本**:DSH、Pi、业务合同、角色合同、输出 Schema 各有版本和哈希。 + +--- + +## 8. 文档同步(跟阶段走,不是收尾) + +| 阶段 | 必须改的活文档 | +|---|---| +| 0 | `AGENTS.md` §3 树、`README.md`、`.agent/_index.md` | +| 1 | `framework/README.md`、`dispatch-agent-task/SKILL.md`、`边界合同.md`、`07` §2 | +| 2 | 框架 Schema 文件本身;`08` 仅引用执行日志边界 | +| 3 | DSH adapter README、`07` 双适配器、AGENTS.md 默认宿主 | +| 4 | 角色合同里评委 spawn 纪律(若尚未写死为机械门) | + +仍被 SoT 引用、路径会随阶段 0 入口树一起对账的:`创作周期与Skill导读.md`、`可视化模块合同.md`、`muse/authority/db/表映射.md`、父仓 `design-docs/流程-02B`(若仍指向 `muse/sot`)。死链失败关闭;不改 `docs/write-chapter/artifacts/` 与本文件对照用的旧路径。 + +SoT 已位于 `muse/sot/`:**不阻塞**阶段 1–3。后续若调整归属需单独提交,并同步 `ROLE_CONTRACT_RELATIVE_PATH` 与相对链接。 + +--- + +## 9. 明确不做 + +- 不把业务做成 DSH 插件全集。 +- 不回滚方法 Skill 嵌套;用投影或自定义 Provider 兼容 DSH。 +- 不把 `dsh-llm-pi-ai` 当成 Pi coding agent 适配器。 +- 不把 session log 当正典,不把 DSH Session 与 PostgreSQL 当同一事务。 +- 不先做 DSH 正文台、不先接评委、不先让两个框架各写一套写作逻辑。 +- 无独立可执行 `dsh` 时,不声称 DSH 集成完成。 +- 不改候选状态机、CAS、人闸通道、表结构。 + +--- + +## 10. 完成的定义 + +- 阶段 0:入口文档与磁盘一致;当场 `skill_harness.py --strict` 绿。 +- 阶段 1:端口纯度门绿;既有 Pi 派发离线测试绿;框架不再 import `agent_trace` / `muse_role_contract`。 +- 阶段 2:三类对象有 Schema 与离线重放测试;Skill 投影或 Provider 裁定已落盘并有对账测试。 +- 阶段 3:可执行 DSH 上 writer/planner 与 Pi 同源对照有机械证据(Schema / 越权 / asOf / 轨迹)。 +- 阶段 4:未获对照证据前,生产默认宿主不得改口。 + +无自动化绿证据不得声称阶段完成。研究记录里的采样数字只证明当时,不构成本 plan 的完成证据。 diff --git a/docs/research/2026-08-24-dsh-local-runtime-baseline.md b/docs/research/2026-08-24-dsh-local-runtime-baseline.md new file mode 100644 index 0000000..95c625e --- /dev/null +++ b/docs/research/2026-08-24-dsh-local-runtime-baseline.md @@ -0,0 +1,36 @@ +# DSH 本机运行基线 + +> 核对日期:2026-08-24 +> 范围:本机 DSH 安装、官方 headless 入口、`agent-example` DSH 适配接缝。 + +## 结论 + +- 本机此前只有 `0.1.0-rc.6` 的 npx 缓存和 `~/.dsh` 旧 profile;当前已安装官方 `@deepseek-ai/dsh@0.1.1-rc.2`,命令为 `dsh`。 +- npm `latest` 当前为 `0.1.1-rc.2`;官方仓库 `master` 当前提交为 `b150a551b8d465e31e418e1b2eaf5e79bbb7d28e`,与该版本对应。 +- `dsh --profile web --dump-config` 与 `dsh --profile headless --dump-config` 在无 API key 条件下通过。`dsh --profile headless "..."` 在无凭据时按 `MISSING_CREDENTIAL` 失败关闭。 +- DSH headless bundle 是一次性任务入口:创建新 Agent/session,等待空闲,flush session,再输出最后一条非空 assistant 文本;它没有交互式续接入口。 +- `agent-example/framework/adapters/dsh/` 当前只开放无工具 fresh 对照运行。Muse 的只读工具白名单尚未在 DSH 中形成执行前闭集,因此非空白名单拒绝启动。生产默认仍为 Pi。 + +## 一手来源 + +- [DSH 官方 README](https://github.com/deepseek-ai/deepseek-harness/blob/b150a551b8d465e31e418e1b2eaf5e79bbb7d28e/README.md):npm 运行方式、Node 前置和 developer preview 边界。 +- [DSH Architecture](https://github.com/deepseek-ai/deepseek-harness/blob/b150a551b8d465e31e418e1b2eaf5e79bbb7d28e/docs/architecture.md):Cordis 插件树、profile/bundle、session/event 和 capability seam。 +- [DSH Headless bundle README](https://github.com/deepseek-ai/deepseek-harness/blob/b150a551b8d465e31e418e1b2eaf5e79bbb7d28e/packages/bundle/headless/README.md):headless 生命周期、flush 和退出码。 +- [DSH Session Persistence JSONL README](https://github.com/deepseek-ai/deepseek-harness/blob/b150a551b8d465e31e418e1b2eaf5e79bbb7d28e/packages/session/session-persistence-jsonl/README.md):会话目录、`session.jsonl`/`session.jsonl.zstd` 编码和 append-only 约束。 +- [公众号文章《从0到1带你速通DeepSeek Harness》](https://mp.weixin.qq.com/s/xkC1aenHFNSH2BxyzLDfcA):二手产品介绍,核对到的主题是“一切皆插件”、标准/PTC/极简/创造模式和只追加会话日志;不作为代码 API 事实源。 + +## 本机命令证据 + +```text +dsh --version -> 0.1.1-rc.2 +dsh --profile web --dump-config -> exit 0 +dsh --profile headless --dump-config -> exit 0 +env -u DEEPSEEK_API_KEY dsh --profile headless "print exactly OK" + -> exit 1, MISSING_CREDENTIAL +``` + +这些证据只证明安装、profile 组合和无凭据失败路径;没有 API key、预算授权和真实任务回执时,不升级为模型质量、工具能力或 Muse 业务可用性结论。 + +## 实现决策 + +DSH 的“标准模式”适合交互式开发者使用,但 Muse 的框架适配器选择 `headless`,原因是业务层已经负责生成冻结任务包,适配器只需要一次可追踪执行。`creative`/Cordis 自修改能力不进入生产角色会话;插件自修改不能替代 Muse 的角色合同、工具白名单、Schema 门和 Canonical 主权门。 diff --git a/framework/README.md b/framework/README.md new file mode 100644 index 0000000..ad02052 --- /dev/null +++ b/framework/README.md @@ -0,0 +1,15 @@ +# Agent 框架层 + +`framework/` 只拥有可替换 Agent 宿主需要的执行接缝:可移植任务包、宿主适配器和框架事件归一入口。它不拥有作品、角色业务、数据库事实、额度或用户决策。 + +```text +framework/ +├── primitives/ # FrameworkExecutionRequest/Event/Result 与工件工具 +├── adapters/pi/ # Pi argv、事件流和显式扩展桥 +├── adapters/dsh/ # DSH headless、session JSONL 和通用事件归一 +└── catalog/ # 由 Muse manifest 生成的 Pi/DSH 扁平 Skill 投影 +``` + +Muse 业务侧先解析角色合同、模型策略、冻结输入和输出 Schema,再把通用执行请求交给端口;框架适配器不直接决定创作流程,也不绕过 Muse 的证据与主权链。`catalog/generate_skill_projections.py` 只生成宿主发现投影,Skill 正文的所有权仍在 Muse 源目录。 + +当前生产默认仍是 Pi。DSH 适配器是 opt-in 的 headless 对照接缝:它只开放无工具 fresh 任务,读取 flush 后的 append-only session 工件;尚未形成 Muse 只读工具闭集和真实业务旅程证据前,不得把 DSH 当作生产宿主。 diff --git a/framework/__init__.py b/framework/__init__.py new file mode 100644 index 0000000..043be7b --- /dev/null +++ b/framework/__init__.py @@ -0,0 +1 @@ +"""可替换宿主的 Agent 框架层。""" diff --git a/framework/adapters/__init__.py b/framework/adapters/__init__.py new file mode 100644 index 0000000..c37e89f --- /dev/null +++ b/framework/adapters/__init__.py @@ -0,0 +1 @@ +"""Agent 宿主适配器。""" diff --git a/framework/adapters/dsh/README.md b/framework/adapters/dsh/README.md new file mode 100644 index 0000000..e024d37 --- /dev/null +++ b/framework/adapters/dsh/README.md @@ -0,0 +1,34 @@ +# DSH 适配器 + +`framework/adapters/dsh/` 是 DeepSeek Harness 的 headless 宿主适配器。它只消费已经由 Muse 派发层解析好的 `FrameworkExecutionRequest`,不读取角色合同、数据库、额度或候选状态。 + +## 当前支持面 + +- DSH profile:`headless`。 +- 会话:每次新建 fresh session;不接受 `continue`。 +- 工具:只接受空 `toolAllowlist`。当前 DSH 内建工具没有与 Muse 五个只读工具形成可证明的闭集,因此非空白名单在启动前失败。 +- 轨迹:通过一次性 patch 把会话持久化切到本次运行私有的 `compression=none` JSONL;flush 后再归一为 `FrameworkEvent` 工件。stdout 不是审计事实源。 +- 模型:provider/model 必须由调用方显式传入,适配器只把它们写入 DSH 的 `agent-default-model` patch 并记录实际 session route。 +- 权限:默认 `read-only`;适配器关闭 headless profile 中未经过 Muse 授权证明的工具、Skill 自动注入和会话标题模型调用。 + +这条路径是 DSH 对照臂和宿主接缝,不改变当前生产默认 Pi,也不允许 DSH 直接写 Canonical 或数据库。 + +## 本机验证 + +当前本机安装的官方 DSH 版本是 `0.1.1-rc.2`,与 npm `latest` 和官方仓库 `b150a551b8d465e31e418e1b2eaf5e79bbb7d28e` 一致。无 API key 时只做配置与失败关闭检查: + +```bash +dsh --version +dsh --profile web --dump-config +dsh --profile headless --dump-config +``` + +真实模型运行还需要由用户显式提供 DSH 自己的凭据和预算;上述命令不构成真实模型或 Muse 业务旅程证据。 + +## 代码入口 + +- `runner.py`:启动 DSH、生成一次性 patch、超时/非零退出失败关闭、读取 session artifact。 +- `normalization.py`:保留未知事件并将 DSH append-only session 映射为通用事件工件。 +- `tests/architecture/test_dsh_adapter.py`:无网络、无模型、无数据库的协议回归。 + +外部事实以 DSH 官方 README、Architecture、Headless bundle README 为准;公众号文章只作为产品模式的二手说明,不作为 API 合同。 diff --git a/framework/adapters/dsh/__init__.py b/framework/adapters/dsh/__init__.py new file mode 100644 index 0000000..ab7de91 --- /dev/null +++ b/framework/adapters/dsh/__init__.py @@ -0,0 +1,39 @@ +"""DeepSeek Harness 宿主适配器。""" + +from .normalization import ( + DshModelCall, + DshNormalizationError, + DshSessionOutcome, + DshToolCall, + normalize_dsh_session, +) +from .runner import ( + DEFAULT_DSH_BIN, + DEFAULT_DSH_PROFILE, + DshError, + DshExecutionPolicy, + DshHeadlessRunner, + DshProcessResult, + DshRunOutcome, + TraceSink, + build_dsh_argv, + build_dsh_patch, +) + +__all__ = [ + "DshModelCall", + "DshNormalizationError", + "DshSessionOutcome", + "DshToolCall", + "normalize_dsh_session", + "DEFAULT_DSH_BIN", + "DEFAULT_DSH_PROFILE", + "DshError", + "DshExecutionPolicy", + "DshHeadlessRunner", + "DshProcessResult", + "DshRunOutcome", + "TraceSink", + "build_dsh_argv", + "build_dsh_patch", +] diff --git a/framework/adapters/dsh/normalization.py b/framework/adapters/dsh/normalization.py new file mode 100644 index 0000000..7fb4450 --- /dev/null +++ b/framework/adapters/dsh/normalization.py @@ -0,0 +1,347 @@ +"""DeepSeek Harness 会话 JSONL 到通用 FrameworkEvent 的确定性归一。""" + +from __future__ import annotations + +import json +from dataclasses import dataclass, field +from datetime import datetime, timezone +from pathlib import Path +from typing import Any, Mapping + +from framework.primitives.artifacts import payload_sha256, write_jsonl_atomic + + +class DshNormalizationError(ValueError): + """DSH 会话工件不可安全解析或缺少必要身份。""" + + +@dataclass(frozen=True) +class DshModelCall: + """DSH 会话中一条 assistant/message 的模型回合摘要。""" + + actual_model_id: str + provider: str + usage: Mapping[str, Any] = field(default_factory=dict) + stop_reason: str | None = None + cost_usd: float | None = None + + +@dataclass +class DshToolCall: + """DSH 会话中一条顶层 tool/call 的依赖摘要。""" + + tool_call_id: str + name: str + args: Mapping[str, Any] | None = None + is_error: bool = False + + +@dataclass(frozen=True) +class DshSessionOutcome: + """归一后的 DSH 会话事实,不包含 Muse 业务裁决。""" + + session_id: str + final_text: str | None + model_calls: tuple[DshModelCall, ...] + tool_calls: tuple[DshToolCall, ...] + turns: int + unknown_event_types: tuple[str, ...] + event_count: int + artifact_path: str + artifact_sha256: str + + +def _mapping(value: Any) -> Mapping[str, Any]: + return value if isinstance(value, Mapping) else {} + + +def _text_from_content(content: Any) -> str: + if isinstance(content, str): + return content + if not isinstance(content, list): + return "" + parts: list[str] = [] + for block in content: + if isinstance(block, Mapping) and block.get("type") == "text": + parts.append(str(block.get("text") or "")) + return "".join(parts) + + +def _route_from_header(data: Mapping[str, Any]) -> tuple[str, str] | None: + header = _mapping(data.get("header")) + config = _mapping(header.get("config")) + provider = str(config.get("provider") or "").strip() + model = str(config.get("model") or "").strip() + if provider and model: + return provider, model + return None + + +def _route_from_message(data: Mapping[str, Any]) -> tuple[str, str] | None: + message = _mapping(data.get("message")) + source = _mapping(message.get("source")) + provider = str(source.get("provider") or "").strip() + model = str(source.get("model") or "").strip() + if provider and model: + return provider, model + return None + + +def _usage_cost(usage: Mapping[str, Any]) -> float | None: + for value in (usage.get("costUsd"), usage.get("cost_usd")): + if value is None: + continue + try: + parsed = float(value) + except (TypeError, ValueError): + continue + if parsed >= 0: + return parsed + cost = usage.get("cost") + if isinstance(cost, Mapping): + try: + parsed = float(cost.get("total")) + except (TypeError, ValueError): + return None + return parsed if parsed >= 0 else None + return None + + +def _tool_result_is_error(data: Mapping[str, Any]) -> bool: + message = _mapping(data.get("message")) + for block in message.get("content") or []: + if not isinstance(block, Mapping): + continue + for nested in block.get("content") or []: + if isinstance(nested, Mapping) and bool(nested.get("isError")): + return True + if bool(block.get("isError")): + return True + return False + + +def _safe_details(raw: Mapping[str, Any]) -> dict[str, Any]: + """只保留轨迹摘要,禁止把 prompt、response 或工具正文复制进通用事件。""" + + event_type = str(raw.get("type") or "unknown") + data = _mapping(raw.get("data")) + details: dict[str, Any] = {"type": event_type} + for key in ("turn", "step", "callId", "name", "rootCallId", "parentCallId", "subCallId"): + if key in data and isinstance(data[key], (str, int, float, bool)): + details[key] = data[key] + if event_type == "request/context": + for key in ("provider", "model"): + if isinstance(data.get(key), str): + details[key] = data[key] + if event_type == "request/header": + route = _route_from_header(data) + if route is not None: + details.update({"provider": route[0], "model": route[1]}) + if event_type == "turn/end": + reason = _mapping(data.get("reason")) + if isinstance(reason.get("kind"), str): + details["reason"] = reason["kind"] + if event_type == "tool/result": + details["isError"] = _tool_result_is_error(data) + if event_type == "tool/code-dispatch": + details["isError"] = bool(data.get("isError")) + return details + + +def _kind_phase(raw: Mapping[str, Any]) -> tuple[str, str]: + event_type = str(raw.get("type") or "unknown") + if event_type == "session": + return "session", "started" + if event_type in {"turn/start", "step/start"}: + return ("turn" if event_type.startswith("turn") else "step"), "started" + if event_type in {"turn/end", "step/end"}: + data = _mapping(raw.get("data")) + reason = _mapping(data.get("reason")) + failed = reason.get("kind") in {"error", "interrupted", "cancelled"} + return ("turn" if event_type.startswith("turn") else "step"), "failed" if failed else "completed" + if event_type == "assistant/message": + return "model", "completed" + if event_type == "assistant/chunk": + return "model", "progress" + if event_type == "tool/call" or event_type.endswith("/start") and event_type.startswith("tool/"): + return "tool", "started" + if ( + event_type in {"tool/result", "tool/code-dispatch"} + or event_type.endswith("/end") and event_type.startswith("tool/") + ): + data = _mapping(raw.get("data")) + failed = event_type == "tool/result" and _tool_result_is_error(data) + if event_type == "tool/code-dispatch": + failed = bool(data.get("isError")) + return "tool", "failed" if failed else "completed" + if event_type in {"user/message", "agent/inbox/spliced"} or event_type.startswith("agent/"): + return "agent", "progress" + if event_type.startswith(("request/", "permission/", "sandbox/", "approval/", "session/", "compaction/")): + return "transport", "progress" + if event_type in {"todo/write"} or event_type.startswith(("goal/", "workflow/", "tool-workflow/")): + return "transport", "progress" + return "unknown", "progress" + + +def _source_event_id(raw: Mapping[str, Any], line_number: int) -> str: + data = _mapping(raw.get("data")) + for candidate in (raw.get("id"), data.get("callId"), data.get("subCallId"), raw.get("seq")): + if candidate is not None and str(candidate).strip(): + return str(candidate) + return f"line:{line_number}" + + +def _observed_at() -> str: + return datetime.now(timezone.utc).isoformat().replace("+00:00", "Z") + + +def normalize_dsh_session( + session_path: str | Path, + artifact_path: str | Path, + *, + run_id: str | None = None, + framework_version: str = "unknown", +) -> DshSessionOutcome: + """读取 DSH 明文 JSONL 会话,写出通用事件工件并返回执行摘要。""" + + source = Path(session_path) + if source.suffix != ".jsonl": + raise DshNormalizationError( + "DSH_COMPRESSED_ARTIFACT_UNSUPPORTED: 适配器要求 compression=none 的明文会话" + ) + try: + lines = source.read_text(encoding="utf-8").splitlines() + except (OSError, UnicodeError) as exc: + raise DshNormalizationError(f"DSH 会话不可读: {source}") from exc + if not lines: + raise DshNormalizationError("DSH_SESSION_EMPTY: 会话工件为空") + + raw_events: list[dict[str, Any]] = [] + for line_number, line in enumerate(lines, start=1): + if not line.strip(): + continue + try: + raw = json.loads(line) + except json.JSONDecodeError as exc: + raise DshNormalizationError( + f"DSH_SESSION_INVALID: 第 {line_number} 行不是合法 JSON" + ) from exc + if not isinstance(raw, Mapping): + raise DshNormalizationError(f"DSH_SESSION_INVALID: 第 {line_number} 行不是对象") + raw_events.append(dict(raw)) + if not raw_events or raw_events[0].get("type") != "session": + raise DshNormalizationError("DSH_SESSION_INVALID: 首条记录不是 session header") + session_id = str(raw_events[0].get("id") or "").strip() + if not session_id: + raise DshNormalizationError("DSH_SESSION_INVALID: session header 缺少 id") + + events: list[dict[str, Any]] = [] + model_calls: list[DshModelCall] = [] + tool_calls: list[DshToolCall] = [] + pending_tools: dict[str, DshToolCall] = {} + current_route: tuple[str, str] | None = None + finish_reasons: dict[tuple[Any, Any], str] = {} + final_text: str | None = None + turns: set[int] = set() + unknown: set[str] = set() + + for line_number, raw in enumerate(raw_events, start=1): + event_type = str(raw.get("type") or "unknown") + data = _mapping(raw.get("data")) + if event_type == "request/header": + current_route = _route_from_header(data) or current_route + elif event_type == "assistant/chunk": + chunk = _mapping(data.get("chunk")) + if chunk.get("type") == "finish": + reason = _mapping(chunk.get("reason")) + kind = reason.get("kind") + if isinstance(kind, str): + finish_reasons[(data.get("turn"), data.get("step"))] = kind + elif event_type == "assistant/message": + route = _route_from_message(data) or current_route + if route is None: + raise DshNormalizationError( + "DSH_MODEL_ID_MISSING: assistant/message 缺少 provider/model 路由" + ) + message = _mapping(data.get("message")) + usage = _mapping(data.get("usage")) + model_calls.append( + DshModelCall( + actual_model_id=f"{route[0]}/{route[1]}", + provider=route[0], + usage=dict(usage), + stop_reason=finish_reasons.get((data.get("turn"), data.get("step"))), + cost_usd=_usage_cost(usage), + ) + ) + text = _text_from_content(message.get("content")) + if text: + final_text = text + elif event_type == "tool/call": + call_id = str(data.get("callId") or "").strip() + name = str(data.get("name") or "").strip() + if not call_id or not name: + raise DshNormalizationError("DSH_TOOL_EVENT_INVALID: tool/call 缺 callId/name") + args: Mapping[str, Any] | None = None + raw_args = data.get("arguments") + if isinstance(raw_args, str): + try: + parsed = json.loads(raw_args) + except json.JSONDecodeError: + parsed = None + if isinstance(parsed, Mapping): + args = dict(parsed) + call = DshToolCall(tool_call_id=call_id, name=name, args=args) + tool_calls.append(call) + pending_tools[call_id] = call + elif event_type == "tool/result": + message = _mapping(data.get("message")) + source = _mapping(message.get("source")) + call_id = str(source.get("callId") or "").strip() + if call_id in pending_tools: + pending_tools[call_id].is_error = _tool_result_is_error(data) + elif event_type == "turn/start": + turn = data.get("turn") + if isinstance(turn, int): + turns.add(turn) + + kind, phase = _kind_phase(raw) + if kind == "unknown": + unknown.add(event_type) + events.append( + { + "framework": "dsh", + "frameworkVersion": framework_version, + "sessionId": session_id, + "sourceSeq": len(events) + 1, + "sourceEventId": _source_event_id(raw, line_number), + "runId": run_id, + "kind": kind, + "phase": phase, + "safeDetails": _safe_details(raw), + "payloadSha256": payload_sha256(raw), + "observedAt": _observed_at(), + } + ) + + artifact_sha256 = write_jsonl_atomic(artifact_path, events) + return DshSessionOutcome( + session_id=session_id, + final_text=final_text, + model_calls=tuple(model_calls), + tool_calls=tuple(tool_calls), + turns=len(turns), + unknown_event_types=tuple(sorted(unknown)), + event_count=len(events), + artifact_path=str(artifact_path), + artifact_sha256=artifact_sha256, + ) + + +__all__ = [ + "DshModelCall", + "DshNormalizationError", + "DshSessionOutcome", + "DshToolCall", + "normalize_dsh_session", +] diff --git a/framework/adapters/dsh/runner.py b/framework/adapters/dsh/runner.py new file mode 100644 index 0000000..fcee9af --- /dev/null +++ b/framework/adapters/dsh/runner.py @@ -0,0 +1,468 @@ +"""DeepSeek Harness headless 适配器。""" + +from __future__ import annotations + +import json +import os +import re +import signal +import subprocess +import time +from dataclasses import dataclass +from pathlib import Path +from typing import Any, Callable, Mapping, Protocol, Sequence + +from framework.primitives.execution import FrameworkExecutionRequest, FrameworkExecutionResult + +from .normalization import ( + DshSessionOutcome, + normalize_dsh_session, +) + + +DEFAULT_DSH_BIN = "dsh" +DEFAULT_DSH_PROFILE = "headless" +_MAX_STDERR_BYTES = 64 * 1024 +_SECRET_PATTERN = re.compile(r"sk-[A-Za-z0-9_-]{12,}") + +# 这些行是 DSH 当前 headless bundle 的模型可见工具或上下文自动注入入口。 +# 适配器现在只承诺无工具任务;未知/新增能力不应默默进入 Muse 角色。 +_DISABLED_HEADLESS_ROWS = ( + "session-title-llm", + "agent-instructions", + "skill", + "skill-filesystem", + "tool-skill", + "tool-bash", + "tool-pwsh", + "tool-jobs", + "tool-fs", + "tool-fs-search", + "web", + "web-search-deepseek", + "tool-web", + "goal", + "goal-round-driver", + "command-goal", + "subagent", + "subagent-spawn-in-process", + "subagent-fork-in-process", + "tool-subagent-control", + "tool-subagent-list-agents", + "tool-subagent", + "tool-subagent-fork", + "tool-subagent-report", + "workflow-worker-thread", + "tool-workflow", + "tool-todo", + "tool-goal", + "tool-ralph", + "tool-str-replace-editor", +) + + +class TraceSink(Protocol): + """Muse 注入的旁路事件接收端;框架不拥有持久化实现。""" + + def emit(self, event_type: str, **kwargs: Any) -> int: ... + + +class DshError(RuntimeError): + """DSH 启动、会话回放或执行失败。""" + + def __init__( + self, + error_code: str, + message: str, + *, + outcome: "DshRunOutcome | None" = None, + ) -> None: + super().__init__(message) + self.error_code = error_code + self.outcome = outcome + + +@dataclass(frozen=True) +class DshExecutionPolicy: + """DSH 运行策略;模型路由由 Muse 派发方显式解析后传入。""" + + provider: str | None = None + model: str | None = None + dsh_bin: str = DEFAULT_DSH_BIN + profile: str = DEFAULT_DSH_PROFILE + cwd: str | None = None + dsh_home: str | None = None + permission_mode: str = "read-only" + + def __post_init__(self) -> None: + if not isinstance(self.provider, str) or not self.provider.strip(): + raise ValueError("provider 必须显式传入") + if not isinstance(self.model, str) or not self.model.strip(): + raise ValueError("model 必须显式传入") + if self.profile != DEFAULT_DSH_PROFILE: + raise ValueError("当前 DSH 适配器只支持 headless profile") + if self.permission_mode not in {"read-only", "workspace-write", "danger-full-access"}: + raise ValueError("permission_mode 不受支持") + + @property + def framework(self) -> str: + return "dsh" + + @property + def requested_model_id(self) -> str: + return f"{self.provider}/{self.model}" + + +@dataclass(frozen=True) +class DshProcessResult: + """一次 dsh 子进程的无正文进程结果;正文从会话日志读取。""" + + returncode: int + stdout: bytes = b"" + stderr: bytes = b"" + timed_out: bool = False + + +@dataclass(frozen=True) +class DshRunOutcome: + """DSH 执行结果与已发布通用事件工件。""" + + session: DshSessionOutcome + requested_model: str + exit_code: int + duration_ms: int + stderr_summary: str = "" + + @property + def session_id(self) -> str: + return self.session.session_id + + @property + def final_text(self) -> str | None: + return self.session.final_text + + @property + def model_calls(self): + return self.session.model_calls + + @property + def tool_calls(self): + return self.session.tool_calls + + @property + def turns(self) -> int: + return self.session.turns + + @property + def unknown_event_types(self): + return self.session.unknown_event_types + + def as_framework_result(self) -> FrameworkExecutionResult: + """转换为框架通用结果;不代表 Muse 候选已通过任何业务门。""" + + return FrameworkExecutionResult( + status="completed", + final_text=self.final_text, + requested_model=self.requested_model, + actual_models=tuple(call.actual_model_id for call in self.session.model_calls), + session_id=self.session_id, + artifact_locator=self.session.artifact_path, + trace_digest=self.session.artifact_sha256, + ) + + +def build_dsh_patch( + request: FrameworkExecutionRequest, + policy: DshExecutionPolicy, + *, + session_root: str | Path, +) -> list[dict[str, Any]]: + """生成一次性 JSON/YAML patch;JSON 是 YAML 的安全子集,避免标量注入。""" + + if request.tool_allowlist: + raise DshError( + "DSH_TOOL_POLICY_UNSUPPORTED", + "当前 DSH headless 适配器尚未接入 Muse 只读工具插件,非空工具白名单拒绝启动", + ) + cwd = Path(policy.cwd or os.getcwd()).resolve() + return [ + { + "id": "agent-default-model", + "config": {"provider": policy.provider, "model": policy.model}, + }, + { + "id": "system-prompt", + "config": {"persona": request.system_prompt}, + }, + { + "id": "session-persistence-jsonl", + "config": { + "root": str(Path(session_root).resolve()), + "compression": "none", + "packChunks": False, + }, + }, + { + "id": "sandbox-policy", + "config": { + "mode": policy.permission_mode, + "workspaceRoot": str(cwd), + }, + }, + { + "id": "tools", + "config": {"mode": "native"}, + }, + *({"id": row_id, "disabled": True} for row_id in _DISABLED_HEADLESS_ROWS), + ] + + +def build_dsh_argv( + request: FrameworkExecutionRequest, + policy: DshExecutionPolicy, + patch_path: str | Path, +) -> list[str]: + """构造 headless argv;任务只作为一个 app-owned positional 参数传入。""" + + if request.session_mode != "fresh": + raise DshError( + "DSH_SESSION_CONTINUE_UNSUPPORTED", + "当前 DSH headless 适配器不支持 continue,会话续接需接入 DSH resume 入口后再开放", + ) + if request.tool_allowlist: + raise DshError( + "DSH_TOOL_POLICY_UNSUPPORTED", + "当前 DSH headless 适配器尚未接入 Muse 只读工具插件,非空工具白名单拒绝启动", + ) + return [ + policy.dsh_bin, + "--profile", + policy.profile, + "--patch", + str(Path(patch_path).resolve()), + "--", + request.user_content, + ] + + +def _redact_stderr(raw: bytes) -> str: + text = raw[:_MAX_STDERR_BYTES].decode("utf-8", errors="replace") + text = _SECRET_PATTERN.sub("", text) + return text.strip() + + +def _run_subprocess( + argv: Sequence[str], + *, + timeout_seconds: float, + cwd: str | None, + env: Mapping[str, str], +) -> DshProcessResult: + try: + process = subprocess.Popen( + list(argv), + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + cwd=cwd, + env=dict(env), + start_new_session=(os.name != "nt"), + ) + except OSError as exc: + raise DshError("DSH_START_FAILED", f"DSH 进程启动失败: {type(exc).__name__}") from exc + try: + stdout, stderr = process.communicate(timeout=timeout_seconds) + except subprocess.TimeoutExpired: + if os.name != "nt": + try: + os.killpg(process.pid, signal.SIGKILL) + except ProcessLookupError: + pass + else: + process.kill() + stdout, stderr = process.communicate() + return DshProcessResult( + returncode=process.returncode if process.returncode is not None else -9, + stdout=stdout or b"", + stderr=stderr or b"", + timed_out=True, + ) + return DshProcessResult( + returncode=process.returncode, + stdout=stdout or b"", + stderr=stderr or b"", + ) + + +class DshHeadlessRunner: + """启动 DSH headless,并以 flush 后的会话日志作为唯一轨迹输入。""" + + def __init__( + self, + launcher: Callable[..., DshProcessResult] | None = None, + *, + framework_version: str = "unknown", + ) -> None: + self._launcher = launcher + self._framework_version = framework_version + + def _launch( + self, + argv: Sequence[str], + *, + timeout_seconds: float, + cwd: str | None, + env: Mapping[str, str], + ) -> DshProcessResult: + if self._launcher is not None: + return self._launcher(argv, timeout_seconds, cwd, env) + return _run_subprocess( + argv, + timeout_seconds=timeout_seconds, + cwd=cwd, + env=env, + ) + + @staticmethod + def _find_session(session_root: Path) -> Path: + candidates = sorted(session_root.rglob("session.jsonl")) + if len(candidates) != 1: + raise DshError( + "DSH_SESSION_MISSING" if not candidates else "DSH_SESSION_AMBIGUOUS", + "DSH 未产生唯一的明文 session.jsonl 工件", + ) + return candidates[0] + + def run( + self, + request: FrameworkExecutionRequest, + policy: DshExecutionPolicy, + sink: TraceSink, + *, + artifact_dir: str | Path, + timeout_seconds: float | None = None, + run_id: str | None = None, + ) -> DshRunOutcome: + """执行一次 DSH 任务;模型、工具和业务 Schema 由上层合同负责。""" + + if request.session_mode != "fresh": + raise DshError( + "DSH_SESSION_CONTINUE_UNSUPPORTED", + "当前 DSH headless 适配器不支持 continue", + ) + if request.tool_allowlist: + raise DshError( + "DSH_TOOL_POLICY_UNSUPPORTED", + "当前 DSH headless 适配器尚未接入 Muse 只读工具插件,非空工具白名单拒绝启动", + ) + root = Path(artifact_dir).resolve() + root.mkdir(parents=True, mode=0o700, exist_ok=True) + root.chmod(0o700) + session_root = root / "dsh-sessions" + session_root.mkdir(parents=True, mode=0o700, exist_ok=True) + session_root.chmod(0o700) + patch_path = root / "dsh.patch.json" + patch = build_dsh_patch(request, policy, session_root=session_root) + patch_path.write_text(json.dumps(patch, ensure_ascii=False, indent=2) + "\n", encoding="utf-8") + patch_path.chmod(0o600) + argv = build_dsh_argv(request, policy, patch_path) + env = os.environ.copy() + env["DSH_PERMISSION_MODE"] = policy.permission_mode + env["DSH_TELEMETRY_DISABLED"] = "1" + if policy.dsh_home: + env["DSH_HOME"] = str(Path(policy.dsh_home).resolve()) + cwd = str(Path(policy.cwd).resolve()) if policy.cwd else None + timeout = float(timeout_seconds if timeout_seconds is not None else request.timeout_seconds) + started = time.monotonic() + sink.emit( + "agent.started", + status="ok", + requested_model_id=policy.requested_model_id, + details={"framework": "dsh", "profile": policy.profile}, + ) + process_result = self._launch( + argv, + timeout_seconds=timeout, + cwd=cwd, + env=env, + ) + duration_ms = int((time.monotonic() - started) * 1000) + stderr_summary = _redact_stderr(process_result.stderr) + if process_result.timed_out: + raise DshError( + "DSH_TIMEOUT", + f"DSH 执行超时(>{timeout}s)", + ) + if process_result.returncode != 0: + suffix = f": {stderr_summary[:256]}" if stderr_summary else "" + raise DshError( + "DSH_EXIT_NONZERO", + f"DSH 进程退出码 {process_result.returncode}{suffix}", + ) + session_path = self._find_session(session_root) + try: + session = normalize_dsh_session( + session_path, + root / "framework-events.jsonl", + run_id=run_id, + framework_version=self._framework_version, + ) + except ValueError as exc: + raise DshError("DSH_SESSION_INVALID", str(exc)) from exc + if not session.model_calls: + raise DshError("DSH_NO_MODEL_RESPONSE", "DSH 会话没有 assistant/message 模型回合") + if session.final_text is None or not session.final_text.strip(): + raise DshError("DSH_EMPTY_FINAL_MESSAGE", "DSH 会话没有最终文本") + + for call in session.model_calls: + sink.emit( + "model.completed", + status="error" if call.stop_reason in {"error", "interrupted"} else "ok", + requested_model_id=policy.requested_model_id, + actual_model_id=call.actual_model_id, + usage=dict(call.usage), + cost_usd=call.cost_usd, + details={"stopReason": call.stop_reason, "provider": call.provider}, + ) + for call in session.tool_calls: + sink.emit( + "tool.completed", + status="error" if call.is_error else "ok", + tool_name=call.name, + details={"toolCallId": call.tool_call_id}, + ) + outcome = DshRunOutcome( + session=session, + requested_model=policy.requested_model_id, + exit_code=process_result.returncode, + duration_ms=duration_ms, + stderr_summary=stderr_summary, + ) + sink.emit( + "agent.completed", + status="ok", + requested_model_id=policy.requested_model_id, + actual_model_id=session.model_calls[-1].actual_model_id, + details={ + "sessionId": session.session_id, + "turns": session.turns, + "modelCalls": len(session.model_calls), + "toolCalls": len(session.tool_calls), + "unknownFrameworkEvents": list(session.unknown_event_types), + "durationMs": duration_ms, + }, + ) + return outcome + + +__all__ = [ + "DEFAULT_DSH_BIN", + "DEFAULT_DSH_PROFILE", + "DshError", + "DshExecutionPolicy", + "DshHeadlessRunner", + "DshProcessResult", + "DshRunOutcome", + "TraceSink", + "build_dsh_argv", + "build_dsh_patch", +] diff --git a/framework/adapters/pi/__init__.py b/framework/adapters/pi/__init__.py new file mode 100644 index 0000000..d0be2b4 --- /dev/null +++ b/framework/adapters/pi/__init__.py @@ -0,0 +1 @@ +"""Pi Agent 框架适配器。""" diff --git a/.agent/skills/dispatch-agent-task/scripts/muse_read_tools_extension.ts b/framework/adapters/pi/mcp_bridge.ts similarity index 100% rename from .agent/skills/dispatch-agent-task/scripts/muse_read_tools_extension.ts rename to framework/adapters/pi/mcp_bridge.ts diff --git a/framework/adapters/pi/normalization.py b/framework/adapters/pi/normalization.py new file mode 100644 index 0000000..eba18f9 --- /dev/null +++ b/framework/adapters/pi/normalization.py @@ -0,0 +1,102 @@ +"""Pi JSONL 到通用 FrameworkEvent 工件的确定性归一。""" + +from __future__ import annotations + +import json +from datetime import datetime, timezone +from pathlib import Path +from typing import Any + +from framework.primitives.artifacts import payload_sha256, write_jsonl_atomic + + +_KIND_PHASE: dict[str, tuple[str, str]] = { + "session": ("session", "started"), + "turn_start": ("turn", "started"), + "turn_end": ("turn", "completed"), + "message_end": ("model", "completed"), + "tool_execution_start": ("tool", "started"), + "tool_execution_end": ("tool", "completed"), + "agent_start": ("agent", "started"), + "agent_end": ("agent", "completed"), + "agent_settled": ("agent", "completed"), +} + + +def _safe_details(event: dict[str, Any]) -> dict[str, Any]: + """只保留执行观察字段,不把消息正文复制进通用事件。""" + + keys = ( + "type", + "provider", + "model", + "stopReason", + "toolName", + "toolCallId", + "isError", + "exitCode", + ) + return {key: event[key] for key in keys if key in event} + + +def normalize_pi_transcript( + transcript_path: str | Path, + artifact_path: str | Path, + *, + run_id: str | None = None, + framework_version: str = "unknown", +) -> dict[str, Any]: + """把 Pi 原始 JSONL 归一为可重放的通用事件工件。""" + + source = Path(transcript_path) + try: + lines = source.read_text(encoding="utf-8").splitlines() + except (OSError, UnicodeError) as exc: + raise ValueError(f"Pi transcript 不可读: {source}") from exc + + events: list[dict[str, Any]] = [] + session_id: str | None = None + unknown: list[str] = [] + observed_at = datetime.now(timezone.utc).isoformat().replace("+00:00", "Z") + for raw_line in lines: + if not raw_line.strip(): + continue + try: + raw = json.loads(raw_line) + except json.JSONDecodeError as exc: + raise ValueError("Pi transcript 含不可解析 JSON 行") from exc + if not isinstance(raw, dict): + raise ValueError("Pi transcript 事件必须是对象") + event_type = str(raw.get("type") or "unknown") + if event_type == "session": + session_id = str(raw.get("id") or "") or session_id + kind, phase = _KIND_PHASE.get(event_type, ("unknown", "progress")) + if kind == "unknown": + unknown.append(event_type) + events.append( + { + "framework": "pi", + "frameworkVersion": framework_version, + "sessionId": session_id, + "sourceSeq": len(events) + 1, + "sourceEventId": str(raw.get("id") or "") or None, + "runId": run_id, + "kind": kind, + "phase": phase, + "safeDetails": _safe_details(raw), + "payloadSha256": payload_sha256(raw), + "observedAt": observed_at, + } + ) + if not events: + raise ValueError("Pi transcript 为空") + digest = write_jsonl_atomic(artifact_path, events) + return { + "path": str(artifact_path), + "sha256": digest, + "eventCount": len(events), + "unknownEventTypes": sorted(set(unknown)), + } + + +__all__ = ["normalize_pi_transcript"] diff --git a/.agent/skills/dispatch-agent-task/scripts/pi_runner.py b/framework/adapters/pi/runner.py similarity index 92% rename from .agent/skills/dispatch-agent-task/scripts/pi_runner.py rename to framework/adapters/pi/runner.py index 253a5e0..6a8a7cf 100644 --- a/.agent/skills/dispatch-agent-task/scripts/pi_runner.py +++ b/framework/adapters/pi/runner.py @@ -4,11 +4,11 @@ 这是全仓唯一直接调用 Agent 框架二进制的位置(架构门禁 tests/architecture/test_import_boundaries.py 白名单)。适配器只做三件事: 构造 argv(角色 prompt 注入 + 工具白名单 + 隔离上下文)、逐行消费框架事件流、 -把事件归一转发给 TraceWriter。它不含任何业务决策:补证、重写、下一步做什么 +把事件归一转发给注入的 TraceSink。它不含任何业务决策:补证、重写、下一步做什么 全部属于框架里的模型,不属于本模块。 执行策略(provider/model/thinking)由派发方给定并如实记账;框架把模型模式解析为 -完整模型 ID,匹配口径见 agent_trace.model_ids_match。超时用看门狗线程杀进程: +完整模型 ID;业务侧负责把 requested/actual 结果投影到自己的证据账本。超时用看门狗线程杀进程: 阻塞读 stdout 不会自己抛超时,挂死的框架进程必须被强制终止才能失败关闭。 """ from __future__ import annotations @@ -18,10 +18,15 @@ import subprocess import threading import time from dataclasses import dataclass, field -from typing import Any, Callable, Iterable, Iterator, Mapping, Sequence +from typing import Any, Callable, Iterable, Iterator, Mapping, Protocol, Sequence -from agent_task import TaskPackage -from agent_trace import AgentTraceWriter +from framework.primitives.execution import FrameworkExecutionRequest + + +class TraceSink(Protocol): + """Muse 注入的事件接收端;框架不拥有其持久化实现。""" + + def emit(self, event_type: str, **kwargs: Any) -> int: ... DEFAULT_FRAMEWORK = "pi" DEFAULT_PI_BIN = "pi" @@ -113,11 +118,12 @@ class AgentStreamOutcome: tool_calls: list[ToolCallRecord] = field(default_factory=list) turns: int = 0 parse_error_lines: int = 0 + unknown_event_types: list[str] = field(default_factory=list) duration_ms: int = 0 -def build_pi_argv(package: TaskPackage, policy: ExecutionPolicy) -> list[str]: - """构造 pi 子代理 argv:system prompt 注入、工具白名单、上下文隔离。""" +def build_pi_argv(request: FrameworkExecutionRequest, policy: ExecutionPolicy) -> list[str]: + """构造 Pi argv:只消费通用执行请求,不读取 Muse 业务合同。""" argv = [policy.pi_bin, "--print", "--mode", "json"] if policy.session_id: @@ -132,12 +138,12 @@ def build_pi_argv(package: TaskPackage, policy: ExecutionPolicy) -> list[str]: argv += ["--no-context-files", "--no-skills", "--no-extensions", "--no-approve"] if policy.extension_path: argv += ["-e", policy.extension_path] - allowlist = package.spec.tool_allowlist + allowlist = request.tool_allowlist if allowlist: argv += ["--tools", ",".join(allowlist)] else: argv += ["--no-tools"] - argv += ["--system-prompt", package.system_prompt, package.user_message] + argv += ["--system-prompt", request.system_prompt, request.user_content] return argv @@ -236,9 +242,9 @@ class PiAgentRunner: def run( self, - package: TaskPackage, + request: FrameworkExecutionRequest, policy: ExecutionPolicy, - sink: AgentTraceWriter, + sink: TraceSink, *, timeout_seconds: float, raw_sink: Callable[[bytes], None] | None = None, @@ -248,7 +254,7 @@ class PiAgentRunner: raw_sink 逐行接收框架原始事件流字节(转录 tap),供派发器固定全量原始证据。 """ - argv = build_pi_argv(package, policy) + argv = build_pi_argv(request, policy) outcome = AgentStreamOutcome() started = time.monotonic() sink.emit( @@ -264,7 +270,7 @@ class PiAgentRunner: "FRAMEWORK_START_FAILED", f"框架进程启动失败: {type(exc).__name__}" ) from exc final_message: Mapping[str, Any] | None = None - allowed_tools = frozenset(package.spec.tool_allowlist) + allowed_tools = frozenset(request.tool_allowlist) stream_error: FrameworkError | None = None try: try: @@ -345,7 +351,7 @@ class PiAgentRunner: def _consume( self, event: Mapping[str, Any], - sink: AgentTraceWriter, + sink: TraceSink, policy: ExecutionPolicy, outcome: AgentStreamOutcome, allowed_tools: frozenset[str], @@ -439,6 +445,10 @@ class PiAgentRunner: tool_name=name, details={"toolCallId": tool_call_id}, ) + else: + # 原始 JSONL 已由 raw_sink 保存;显式记录未知类型,避免把轨迹完整性误报为已知闭集。 + unknown = str(kind or "") + outcome.unknown_event_types.append(unknown) __all__ = [ @@ -450,4 +460,5 @@ __all__ = [ "PiAgentRunner", "ToolCallRecord", "build_pi_argv", + "TraceSink", ] diff --git a/framework/catalog/catalog.json b/framework/catalog/catalog.json new file mode 100644 index 0000000..787034d --- /dev/null +++ b/framework/catalog/catalog.json @@ -0,0 +1,97 @@ +{ + "invocation": "model_routed", + "schemaVersion": "framework-skill-catalog-v1", + "skills": { + "character-design": { + "dsh": "framework/catalog/dsh/skills/character-design/SKILL.md", + "pi": "framework/catalog/pi/skills/character-design/SKILL.md", + "sha256": "sha256:c0ce6a1790365406450091a5b4018945d540a9b53ec2f8455a384ec8ef855f83", + "source": ".agent/skills/writing/character-design/SKILL.md" + }, + "character-presentation": { + "dsh": "framework/catalog/dsh/skills/character-presentation/SKILL.md", + "pi": "framework/catalog/pi/skills/character-presentation/SKILL.md", + "sha256": "sha256:168dda60b0f79bef795eca0584e106251d246e97faa8a5b3080ecc125c2384e5", + "source": ".agent/skills/writing/character-presentation/SKILL.md" + }, + "concept-design": { + "dsh": "framework/catalog/dsh/skills/concept-design/SKILL.md", + "pi": "framework/catalog/pi/skills/concept-design/SKILL.md", + "sha256": "sha256:3ba8ec19eed013f2d3b754fc62b165cc5c604705619248efcc6b32deaa2b623c", + "source": ".agent/skills/planning/concept-design/SKILL.md" + }, + "dialogue-craft": { + "dsh": "framework/catalog/dsh/skills/dialogue-craft/SKILL.md", + "pi": "framework/catalog/pi/skills/dialogue-craft/SKILL.md", + "sha256": "sha256:cbdfc65fc237e34ceca01452e94472a5f0efdb0921cf4647b7616d5a8d140224", + "source": ".agent/skills/writing/dialogue-craft/SKILL.md" + }, + "foreshadow-payoff": { + "dsh": "framework/catalog/dsh/skills/foreshadow-payoff/SKILL.md", + "pi": "framework/catalog/pi/skills/foreshadow-payoff/SKILL.md", + "sha256": "sha256:ce7b8a1636339ceb65ec9acf2094af4e03a7323250cc89644405c5f2aa345fdb", + "source": ".agent/skills/planning/foreshadow-payoff/SKILL.md" + }, + "narration-pov": { + "dsh": "framework/catalog/dsh/skills/narration-pov/SKILL.md", + "pi": "framework/catalog/pi/skills/narration-pov/SKILL.md", + "sha256": "sha256:b4860863d72d816c2d597562b91c8ef55d5d33a1311d7a94227533ae341aea8d", + "source": ".agent/skills/writing/narration-pov/SKILL.md" + }, + "narrative-momentum": { + "dsh": "framework/catalog/dsh/skills/narrative-momentum/SKILL.md", + "pi": "framework/catalog/pi/skills/narrative-momentum/SKILL.md", + "sha256": "sha256:67ae4dbb3fb75d6410066cae5ed3a49f1071d91aba569ad45276d97770e7c86a", + "source": ".agent/skills/planning/narrative-momentum/SKILL.md" + }, + "novel-diagnosis": { + "dsh": "framework/catalog/dsh/skills/novel-diagnosis/SKILL.md", + "pi": "framework/catalog/pi/skills/novel-diagnosis/SKILL.md", + "sha256": "sha256:8561d4ac36f4b3e9759508cc9515bfdbf5e563e8a3a7df5ab96b582509dc4f30", + "source": ".agent/skills/diagnosis/novel-diagnosis/SKILL.md" + }, + "prose-craft": { + "dsh": "framework/catalog/dsh/skills/prose-craft/SKILL.md", + "pi": "framework/catalog/pi/skills/prose-craft/SKILL.md", + "sha256": "sha256:26d5ae99d68e653b0b31bd4ca9c61e566ec119b09a0c9ed4e4cc3d645e530ac9", + "source": ".agent/skills/writing/prose-craft/SKILL.md" + }, + "scene-craft": { + "dsh": "framework/catalog/dsh/skills/scene-craft/SKILL.md", + "pi": "framework/catalog/pi/skills/scene-craft/SKILL.md", + "sha256": "sha256:d395248301db177ea1686bc0b86feb918151c6e0e69830ab2c0e4b12b900a602", + "source": ".agent/skills/writing/scene-craft/SKILL.md" + }, + "show-and-omission": { + "dsh": "framework/catalog/dsh/skills/show-and-omission/SKILL.md", + "pi": "framework/catalog/pi/skills/show-and-omission/SKILL.md", + "sha256": "sha256:eccb8b64326a39338013a96303bd8dfcd7afe807626b0aded8a9d11e4fbbd4e4", + "source": ".agent/skills/writing/show-and-omission/SKILL.md" + }, + "story-ending": { + "dsh": "framework/catalog/dsh/skills/story-ending/SKILL.md", + "pi": "framework/catalog/pi/skills/story-ending/SKILL.md", + "sha256": "sha256:95af5f33b2476b09f96a2ca19a94176c848e5d5d652f29316de8159c08c8edde", + "source": ".agent/skills/planning/story-ending/SKILL.md" + }, + "story-planning": { + "dsh": "framework/catalog/dsh/skills/story-planning/SKILL.md", + "pi": "framework/catalog/pi/skills/story-planning/SKILL.md", + "sha256": "sha256:567bffd51ef8b8e290a570dca1bf646f0119d61ad645f8fb058a40bbac8cfb1c", + "source": ".agent/skills/planning/story-planning/SKILL.md" + }, + "story-structure": { + "dsh": "framework/catalog/dsh/skills/story-structure/SKILL.md", + "pi": "framework/catalog/pi/skills/story-structure/SKILL.md", + "sha256": "sha256:057750fcf9cd7e49fc8028d7d35fa1858c0e7ff501d1d49d6da8eae8f2aefb9f", + "source": ".agent/skills/planning/story-structure/SKILL.md" + }, + "theme-and-stance": { + "dsh": "framework/catalog/dsh/skills/theme-and-stance/SKILL.md", + "pi": "framework/catalog/pi/skills/theme-and-stance/SKILL.md", + "sha256": "sha256:f4cd0119642597c64dbf98ed91464195e1f52a99725672997d3df7ebe6aa4e36", + "source": ".agent/skills/writing/theme-and-stance/SKILL.md" + } + }, + "sourceManifest": "muse/lifecycle/quality/harness/manifests/skills.json" +} diff --git a/framework/catalog/dsh/skills/character-design/SKILL.md b/framework/catalog/dsh/skills/character-design/SKILL.md new file mode 100644 index 0000000..95e44dd --- /dev/null +++ b/framework/catalog/dsh/skills/character-design/SKILL.md @@ -0,0 +1,102 @@ +--- +name: character-design +description: | + 小说写作的人物设计方法:用 7 变量全维度建角色,用表层/内层/深层三层信息让角色立体, + 用内在恶魔给角色驱动力和角色弧,用一句话测试给人物选扁平/圆形形态,把人物站在叙事原型上做反转。 + 激活场景:创建新角色(包括"AI 协作建角色,给我一份清单")、角色库管理(很多角色要系统化区分)、 + 角色不鲜明/脸谱化/一维、角色感觉飘或假、角色工具人没驱动力没弧、读者不关心主角、 + 两个角色撞型、群像分不清、配角和主角怎么分配深度、人物太单薄或太符号化、 + 想用原型/神话母题但不想俗套、网文主角类型设计、历史人物重写、主题象征想用但用力过猛。 + 关键 trigger:"角色设计 / 角色构建 / 角色要素 / character profile / 角色 sheet / 角色清单 / 角色怎么写 / + 角色背景 / 角色目标 / 角色动机 / 7 变量 / 角色旋钮 / 角色维度 / + 立体 / 角色深度 / 角色层次 / 表层 / 内层 / 深层 / 3 维角色 / 一维 / 主角是 1 维 / 怎么让角色活 / + 扁平 / 圆形 / flat / round / 一句话概括 / 人物太单薄 / 如何让人物丰满 / + 内在恶魔 / inner demon / 内在冲突 / 角色弧 / 工具人 / 角色是搬运工 / 没有驱动力 / 没有灵魂 / + 为什么读者不关心我的主角 / 原型 / archetype / 刻板印象 / stereotype / 人物塑造 / 主题象征 / symbol / + 中国小说原型 / 本土原型 / 东方母题 / father horst / 墙不只是墙 / 象征不必是钹 / + 如何用原型又不套路 / 用原型别让原型用你"。 + 不适用于:对真实人物的全面评价(道德问题,不是方法问题);无人物的纯信息文本; + 后现代解构作品故意反原型、反母题时(原型定位合法缺席)。 + 与 character-presentation 交接:7 变量/弧线/扁圆/原型归本 Skill;定型后的登场细节、关系网、 + 反常瞬间呈现归 character-presentation。 + 与 dialogue-craft / narration-pov 交接:正文对话声音与视角执行归后两者,本 Skill 不写对话课。 +--- + +# 人物设计 + +人物设计分五个动作:**建**(7 变量全维度配置)、**立体**(三层信息造维度)、**驱动**(内在恶魔造引擎)、**定形**(扁平/圆形选形态)、**打底**(原型定位做反转)。《Story Engineering》三个单元管建/立体/驱动,福斯特管定形,克拉克管打底。方法细节、案例、引文全部在 references 里,这里只给一句话和指针。 + +## 方法索引 + +按创作动作组织,不按书组织。 + +### 建:全维度配置角色 + +- 角色不是一个形容词、一个职业,是 7 个可独立调节的变量 → references/seven-variables.md +- 前 6 个变量是输入,行为是输出兼测试:前 6 一致则行为一致,前 6 矛盾则行为出 bug → references/seven-variables.md +- 每个变量拨 1-10 档,千万级组合不重样;群像撞型就逐项对比、把极端值推开 → references/seven-variables.md + +### 立体:三层信息让角色活起来 + +- 表层(面具)/ 内层(脱下面具的自己)/ 深层(连自己都不知道的核心),多数角色只被写出表层 → references/three-dimensions.md +- 戏剧来自错位:三层互相矛盾,关键场景里让错位暴露或转移;三层完全一致就是一维 → references/three-dimensions.md +- 深层就是内在恶魔——角色自己都未必意识到的驱动力,两本书在说同一件事 → references/three-dimensions.md、references/inner-demon.md + +### 驱动:内在恶魔是引擎 + +- 外部冲突 + 内在恶魔必须同时运作;只有外部冲突,角色是剧情的运输车辆,不是有意义的参与者 → references/inner-demon.md +- 恶魔是根本性的、有早期根源、是角色弧的引擎、是读者共鸣的来源 → references/inner-demon.md +- 共振检查:外部任务必须激活那个怕;内外平行不触碰,不是故事 → references/inner-demon.md +- 角色弧 = 故事结束时他对恶魔做了什么;克服/接受/失败/部分克服都行,但必须明确 → references/inner-demon.md + +### 定形:扁平还是圆形 + +- 一句话测试:说得清的大概率扁平,说不清的大概率圆形 → references/flat-vs-round.md +- 圆形公式 = 出人意料 × 仍然可信,缺一即伪圆形 → references/flat-vs-round.md +- 扁平不是缺陷:喜剧/群像优先扁平,严肃/悲剧必须圆形 → references/flat-vs-round.md +- 高级技巧:扁平人物在紧急时刻骤然鼓胀成圆形,之后又回到扁平(贝特伦夫人案例) → references/flat-vs-round.md + +### 打底:原型与反转 + +- 用原型,别让原型用你:站在母题上,在读者期待的位置反转、挫败、变形 → references/archetype-reversal.md +- 11 个西方叙事原型供参考;中文小说优先从章回、戏曲、神话、文言笔记、现代文学提取本土母题(中文适配) → references/archetype-reversal.md +- Father Horst 两条:墙不只是墙(显著元素承载象征),象征不必是钹(轻敲不宣告) → references/archetype-reversal.md +- 原型 ≠ 刻板印象:原型是可反转、有内部矛盾的母题,刻板印象是固化标签 → references/archetype-reversal.md + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|---------| +| references/seven-variables.md | 7 变量全表、输入输出关系、1-10 档组合、建/诊断/对比三用法、懦弱士兵完整表案例、执行步骤、失败模式与盲点 | +| references/three-dimensions.md | 三层信息(表层/内层/深层)、错位与戏剧、3 维 vs 1 维、深层=恶魔合并点、Walter White/Don Draper 案例、执行步骤、失败模式与盲点 | +| references/inner-demon.md | 两层冲突、恶魔四特征、操作问法、共振检查、弧的引擎与四种结局、完美英雄反例与《末路狂花》案例、执行步骤、失败模式与盲点 | +| references/flat-vs-round.md | 一句话测试、圆形公式、扁平功能分工、悲剧必须圆形、动态切换(圆盘鼓胀)、贝特伦夫人/摩尔·弗兰德斯/狄更斯案例、写作外应用场景、与 visible-private-life 的区分(形式层 vs 本体论层)、失败模式与盲点 | +| references/archetype-reversal.md | 11 个叙事原型、反转规则、Father Horst 两条、越南退伍兵与盖茨比绿光案例、本土原型库(中文适配)、失败模式与盲点 | +| references/_coverage.md | 五个源单元的覆盖对照表 | + +## 脚本 + +| 脚本 | 用途 | +|------|------| +| references/character-worksheet.md | 建角色台账:7 变量 → 3 维度 → 内在恶魔与共振 → 角色弧 → 定形 → 原型打底,一份填完,每节有过关线 | +| references/character-diagnosis.md | 成型角色按症状诊断:不鲜明/工具人/撞型/没弧/伪圆形/刻板印象/象征讲课,症状 → 检查 → 处方 | + +## 红线 + +- 只给当前创作阶段的建议,不越权改设定主权、不绕过检测链、不复制粘贴其它 Skill 的 owner 定义。 +- 无用户明确授权不得替用户定稿或提交 Git。 + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/dsh/skills/character-design/references/_coverage.md b/framework/catalog/dsh/skills/character-design/references/_coverage.md new file mode 100644 index 0000000..3be2794 --- /dev/null +++ b/framework/catalog/dsh/skills/character-design/references/_coverage.md @@ -0,0 +1,11 @@ +# character-design 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| aspects-of-the-novel/flat-vs-round-character | references/flat-vs-round.md | +| story-engineering/character-inner-demon | references/inner-demon.md | +| story-engineering/character-seven-variables | references/seven-variables.md | +| story-engineering/character-three-dimensions | references/three-dimensions.md | +| writing-tools-clark/archetype-toolkit | references/archetype-reversal.md | diff --git a/framework/catalog/dsh/skills/character-design/references/archetype-reversal.md b/framework/catalog/dsh/skills/character-design/references/archetype-reversal.md new file mode 100644 index 0000000..faba094 --- /dev/null +++ b/framework/catalog/dsh/skills/character-design/references/archetype-reversal.md @@ -0,0 +1,141 @@ +# 打底:原型工具箱——站在叙事原型上做反转 + +来源:(Roy Peter Clark,*Writing Tools: 55 Essential Strategies for Every Writer*,Tool 38 · Prefer archetypes to stereotypes) + +## 原文摘录 + +> Good writers strive for originality, and they can achieve it by standing on a foundation of narrative +> archetypes, a set of story expectations that can be manipulated, frustrated, or fulfilled in novel +> ways. Examples include: the journey there and back, winning the prize, winning or losing the loved +> one, loss and restoration, the blessing becomes the curse, overcoming obstacles, the wasteland +> restored, rising from the ashes, the ugly duckling, the emperor has no clothes, descent into the underworld. +> +> — Roy Peter Clark, *Writing Tools* (Tool 38) + +() + +## 方法规则 + +### 11 个西方叙事原型 + +Clark 提出 11 个西方叙事原型作为"工具箱": + +1. 去过-回来(Journey There and Back) +2. 赢得奖赏(Winning the Prize) +3. 赢得/失去爱人(Winning or Losing the Loved One) +4. 丧失与恢复(Loss and Restoration) +5. 祝福成诅咒(The Blessing Becomes the Curse) +6. 克服障碍(Overcoming Obstacles) +7. 荒原恢复(The Wasteland Restored) +8. 灰烬重生(Rising from the Ashes) +9. 丑小鸭(The Ugly Duckling) +10. 皇帝的新衣(The Emperor Has No Clothes) +11. 深入冥界(Descent into the Underworld) + +() + +### 核心规则:用原型,但不被原型用 + +**Use archetypes. Don't let them use you.**(用原型,但不被原型用。)站在这些"基础结构"上做反转、挫败、变形,让读者**既感到熟悉又感到惊讶**。() + +### Father Horst 的两条原则 + +Clark 配套 Father Horst 的两条原则: + +1. **"墙在故事中往往不只是墙"**——显著元素往往有象征意义。 +2. **"象征不必是钹"(A symbol need not be a cymbal)**——微妙为好,用细节的轻敲,不用宣言的重击。 + +这是**反转 + 微妙**的复合框架。() + +### 原型 ≠ 刻板印象,原型 ≠ 主题 + +- **与"刻板印象"的区别**:原型是"可反转的母题",刻板印象是"固化的标签"。原型有内部矛盾,刻板印象没有。 +- **与"主题"的区别**:原型是"叙事模式"(how),主题是"思想内容"(what)。《王子复仇记》是"深入冥界"原型 + "为父报仇"主题。 +- **术语澄清**:本单元的"原型"指克拉克的叙事母题原型;与 references/three-dimensions.md 易混节提到的 Christopher Vogler 12 角色原型、references/flat-vs-round.md 易混节提到的荣格"集体无意识"原型(英雄/智者/阴影)都不是一回事——后两者是人物类型分类,本单元是故事母题基础。 + +() + +## 案例全文 + +### 案例 1:John Pilger 越南退伍军人抗议(William Wyman) + +- **问题**:如何用原型处理"战争反思"主题? +- **方法论的使用**:19 岁双截肢退伍军人把奖章撕下扔到国会台阶——站在"去过-回来"原型上做反转:"去过战场 - 回来 - 不再相信国家赋予的意义"。"祝福变诅咒"原型的当代实例。 +- **结论**:原型的力量不在于"复制"而在于"反转"——把原型推到极致,然后让读者看见其内部裂缝。 +- **结果**:Clark 用来证"站在原型上做反转"的方法论。 + +() + +### 案例 2:Clark 引用 Fitzgerald《了不起的盖茨比》"绿光" + +- **问题**:西方原型(美国梦的破灭)如何在中国/东方语境下迁移? +- **方法论的使用**:Gatsby 的"绿光"原型 = "荒原恢复"+"灰烬重生"的扭曲版本——盖茨比相信"过去可以重造",但绿光最终是"不可挽回"。Clark 用此例说明:**站在原型上做反转,让原型从"希望"变成"反讽"**。 +- **结论**:原型 + 反转 = 西方文学的核心结构。 +- **结果**:成为了"用原型"的金标准案例——但是这个例子是西方文学,中文小说需要本地化原型库。 + +() + +## 操作步骤 + +1. **从 11 个原型中选 1-2 个作为基础** + - 完成标准:选定 1-2 个原型作为人物 / 主题的基础。 + - 判停条件:不强制选;但若不选,人物容易"无类型感"。中文小说可从 11 西方原型中选用,也可本地化(见下方中文适配节)。 +2. **找出"反转点"** + - 在原型流程中,标出"读者期待"的位置,然后让叙事在那个位置**反转 / 挫败 / 变形**。 + - 完成标准:反转点至少 1 个,且与人物 / 主题的核心冲突直接相关。 + - 判停条件:反转必须有意义;不是为了"反"而反。 +3. **Father Horst 检验** + - 检验 1:墙 / 树 / 水等显著元素是否"不只是物"?若有象征意义,保留。 + - 检验 2:象征是否"敲锣打鼓"?若是,改用"轻敲"——细节、动作、对话暗示,而不是作者直接宣告。 + - 完成标准:每个显著元素(墙、树、礼物、伤口)有 1 个轻敲的象征表达,无"宣告"段落。 + +() + +## 边界与失败模式 + +### 不要在以下情况使用 + +- **后现代解构作品**——故意"反原型 / 反母题",不需要工具箱。 +- **完全无类型的实验文本**——拒绝任何"模式"的作品。 +- **刻意反类型的反讽作品**——站在"反原型"上,本身也是一种原型。 +- **完全西化的中文小说**——中文小说更适合用本土原型(见下方中文适配节)。 + +() + +### 作者在书中警告的失败模式 + +- **"墙上挂墙"过度象征**:失败模式是每个元素都被作者宣告"这是象征"。信号:读者读完后觉得"作者在讲课"。机制:把 Father Horst 原则 1 推到极端,忽略原则 2(微妙)。预警:每段都有"作者旁白"或"主题宣告"。 +- **"刻板印象"代替原型**:失败模式是"亚裔女性就温顺 / 退伍军人就暴力"等固定搭配。信号:人物被简化成标签。机制:把"原型"误用为"刻板印象",失去"反转"空间。预警:人物没有内部矛盾。 +- **"反转无意义"**:失败模式是"为反而反"——原型走到一半突然反转,但反转与主题无关。信号:读者觉得"莫名其妙"。机制:作者想要"原创"但没找到真正属于自己的反转。预警:反转点无法用一句话解释"为什么这里反转"。 + +() + +## 中文适配:本土原型库(源单元本地化核心,全量保留) + +**Clark 的 11 个原型是西方的**。中文小说作者需要**本地化补全**: + +- **章回原型**:忠义两难(《水浒》)、冤冤相报(《三国》)、因果轮回(《西游记》)、才子佳人(《红楼》)。 +- **戏曲原型**:生旦净末丑的角色配置(主角、配角、反派、师爷、媒婆等);折子戏的"高潮单折"(类似西方"incident")。 +- **神话原型**:嫦娥奔月 / 牛郎织女 / 愚公移山 / 哪吒闹海 / 八仙过海 / 白蛇传——这些是中国小说的母题来源。 +- **文言笔记**:《聊斋》的人狐之恋 / 《阅微》的因果报应——是短篇小说的原型库。 +- **现代汉语新文学**:鲁迅的"看客"、张爱玲的"倾城之恋"、莫言的"丰乳肥臀"母题——百年新文学已有自己的"现代化原型"。 + +**这一条是 cangjie 蒸馏的本地化核心**——Clark 的西方原型不能直接套用,必须**从中国 / 东亚叙事传统中提取本土原型**,并配 Father Horst 的"微妙"原则。 + +本地化提示(源单元审计注记保留):Clark 的 11 个原型仅作"参考",中文写作者应优先从章回、戏曲、神话、文言笔记中提取本土原型。 + +() + +## 中文落地 + +- 网文主角类型设计(战神归来、灰烬重生、丑小鸭逆袭)是原型反转最直接的用武之地:读者对母题预期极熟,"又是这个"的抱怨就是没做反转;反转点必须挂在全书核心冲突上。 +- 历史人物重写(如诸葛亮、林黛玉):先问"他/她站在哪个原型上",再决定在哪里反转。 +- 中文诗学"象外之象""不着一字,尽得风流"的传统与"象征不必是钹"天然同路;落地方法就是操作步骤里的 Father Horst 检验:显著元素各给一个细节轻敲,删掉一切宣告段落。 + +## 与其他方法的关系 + +- **mosaic-of-detail**(综合 skill character-presentation):那个是"用具体物显示人物"(细节拼贴),这个是"用原型定位人物"(母题基础)。前者是物品语言,后者是叙事母题。 +- **back-off-show-off**(综合 skill prose-craft):那个是"修辞密度校准"(反比主题),这个是"原型选择 + 微妙处理"(主题母题层)。前者管"如何说",后者管"说什么"。 +- **story-engine**(综合 skill concept-design):那个是"贯穿全书的核心问题"(问题),这个是"贯穿叙事的母题"(意象)。前者是叙事骨架,后者是叙事意象。 +- **voice-equalizer**(综合 skill prose-craft):母题的语言表达。 +- **本包内部**:原型反转通常落在人物弧与恶魔上——反转点常是角色深层(恶魔)浮出水面的位置 → references/inner-demon.md、references/three-dimensions.md;圆形人物的"出人意料"也常由原型反转给出 → references/flat-vs-round.md diff --git a/framework/catalog/dsh/skills/character-design/references/character-diagnosis.md b/framework/catalog/dsh/skills/character-design/references/character-diagnosis.md new file mode 100644 index 0000000..daff234 --- /dev/null +++ b/framework/catalog/dsh/skills/character-design/references/character-diagnosis.md @@ -0,0 +1,96 @@ +# 角色诊断流程(角色已成型) + +用法:角色已经在稿子里(写了一半或写完了),按症状查。每条症状:检查 → 判定 → 处方。处方指向本包 references/ 落点;方法细节、案例见落点文件。 + +--- + +## 症状 1:角色不鲜明、一维、脸谱化 + +检查: + +1. 用一句话概括这个角色,说得清吗? +2. 表层/内层/深层各有没有具体内容? +3. 三层之间有没有矛盾? + +判定:一句话说清 + 无错位 = 一维(扁平)。 + +处方: + +- 先问扁平是不是刻意的:喜剧/群像的扁平合法,严肃/悲剧必须圆形 → references/flat-vs-round.md +- 要补立体:补内层和深层,造错位 → references/three-dimensions.md +- 检查世界观(变量 5)是否写成了哲学标签,改成他具体信什么 → references/seven-variables.md + +## 症状 2:工具人、没驱动力、读者不关心主角 + +检查: + +1. 恶魔是不是 0?(只有打怪任务,没有"他为什么做不到") +2. 恶魔是不是太社会议题("害怕贫穷")或太流行病("他抑郁")? +3. 外部任务激活恶魔吗?共振一句话写得出吗? + +判定:恶魔 = 0 或内外平行,就是"剧情的运输车辆,不是有意义的参与者",拒稿常见原因。 + +处方: + +- 补恶魔:问"他最怕什么",追到童年/早期根源 → references/inner-demon.md +- 不共振:改外部任务或改恶魔,让任务正好触碰那个怕 → references/inner-demon.md +- 完美英雄反例为戒:外部冲突再强,恶魔 = 0 读者也不关心 → references/inner-demon.md + +## 症状 3:两个角色撞型、群像分不清 + +检查:两个角色逐项对比 7 变量,列出相同的项。 + +处方: + +- 把其中一方的 2-3 个变量推到极端(如 Backstory 1 vs 9、Goal 5 vs 9)→ references/seven-variables.md +- 群像按 1+7 多份填表逐个处理,不批量 → references/seven-variables.md + +## 症状 4:没弧、没成长 + +检查: + +1. 故事开始和结束时的角色差异,列得出 3 个吗? +2. 角色有没有要克服的恶魔? + +处方: + +- 没差异 = 弧缺失,用恶魔找他要克服什么 → references/inner-demon.md +- 弧的结局:克服/接受/失败(悲剧)/部分克服都行,但必须明确 → references/inner-demon.md +- 深层浮出水面的场景安排成关键节拍 → references/three-dimensions.md + +## 症状 5:伪圆形——反转了但不可信 + +检查:角色的"出人意料"之举,事后能让读者觉得"对,这才是他"吗? + +判定:只意外不可信 = 硬充圆形("暗黑角色"强行反转的常见病);只可信不意外 = 扁平装圆。 + +处方: + +- 给反转行为补三层依据(深层动机),让意外落到可信上 → references/three-dimensions.md +- 补不出来就退回扁平形态,放到喜剧/群像位置 → references/flat-vs-round.md + +## 症状 6:人物刻板印象、标签化 + +检查:人物有内部矛盾吗?他的行为可以被反转吗? + +判定:无矛盾、无反转空间 = 刻板印象,不是原型("亚裔女性就温顺/退伍军人就暴力"这类固定搭配)。 + +处方: + +- 把他放到一个原型上(西方 11 原型或本土母题),在读者期待的位置留反转点 → references/archetype-reversal.md + +## 症状 7:象征讲课、主题宣告 + +检查:显著元素(墙、树、伤口、礼物)是不是靠作者旁白宣告"这是象征"?读者读完觉得"作者在讲课"? + +处方: + +- 宣告改轻敲:用细节、动作、对话暗示;每个显著元素一个轻敲,删掉宣告段落 → references/archetype-reversal.md(Father Horst 检验) + +## 交稿前总检 + +- [ ] 一句话测试做过,形态与主题匹配(严肃/悲剧必须圆形) +- [ ] 主角恶魔在场,内外共振一句话写得出来 +- [ ] 弧的结局明确(克服/接受/失败/部分克服四选一) +- [ ] 群像逐项对比过变量,无撞型 +- [ ] 无"这是象征"式宣告段落,无刻板印象式人物 diff --git a/framework/catalog/dsh/skills/character-design/references/character-worksheet.md b/framework/catalog/dsh/skills/character-design/references/character-worksheet.md new file mode 100644 index 0000000..19ab2b1 --- /dev/null +++ b/framework/catalog/dsh/skills/character-design/references/character-worksheet.md @@ -0,0 +1,91 @@ +# 建角色台账 + +用法:新角色从 0 到 7 顺着填。每节有"过关线",达标进下一节,不达标按标注回退。判断标准全部来自本包 references/ 各文件,这里只是填写骨架;方法细节与案例见各节标注的落点。 + +--- + +## 0. 角色定位 + +角色一句话定位:____ +在故事中的分量:□ 主角 □ 反派 □ 重要配角 □ 小配角 + +- 小配角:填完第 1 节(只填 1-2 个变量)+ 第 5 节定形即可收工,不必全填。 +- 群像:每个主角各填一份台账,不批量处理。 + +## 1. 7 变量(→ references/seven-variables.md) + +| 变量 | 档位(1-10) | 具体内容(3-5 句,不抄变量名) | +|------|------|------| +| 1 表层人格 | | | +| 2 背景故事 | | | +| 3 角色弧 | | | +| 4 内在恶魔 | | | +| 5 世界观 | | | +| 6 目标与动机 | | | +| 7 决策/行动/行为 | | | + +- 至少 2-3 个变量取极端(1-3 或 8-10),全在 4-5 档 = 没特色 □ +- 一致性:第 7 项行为能从前 6 项推出 □;矛盾时改前 6 中的一项,不直接改行为 □ +- 世界观写的是他具体信什么,不是哲学标签 □ + +过关线:7 项都有具体内容,行为与前 6 一致。小配角到此为止。 + +## 2. 3 维度(→ references/three-dimensions.md) + +表层(别人眼中的他):____ +内层(独处时的他):____ +深层(连他自己都不知道的驱动):____ + +- 没把表层复制进内层 □ +- 深层不是修辞("她是个追寻自由的人"不通过),也不是内层的延伸 □ +- 错位清单:表层 vs 内层的矛盾____;内层 vs 深层的矛盾____ +- 3 维都会露馅的关键场景(≥2 个):在____场景露馅;在____场景深层浮出水面 + +过关线:3 维各有具体内容且彼此矛盾。3 维一样 = 角色还在 1 维,回第 1 节补变量。 + +## 3. 内在恶魔与共振(→ references/inner-demon.md) + +- 外部冲突(他在故事里要完成什么):____ +- 恶魔(他最怕什么):____ +- 早期根源(为什么怕,追到童年/早期):____ +- 关键问:如果他成功了,他会失去什么?____ +- 共振一句话:外部任务____正好激活恶魔____ + +过关线:共振一句话写得出来。内外平行不触碰 → 改恶魔或改外部任务,直到咬合。恶魔别写成社会议题("害怕贫穷"太大)或流行病("他抑郁"太泛)。 + +## 4. 角色弧(→ references/inner-demon.md) + +- 故事开始时的他:____ +- 故事结束时的他:____ +- 3 个变化:1.____ 2.____ 3.____ +- 结局时对恶魔做了什么:□ 克服 □ 接受 □ 失败(悲剧) □ 部分克服 + +过关线:列得出 3 个变化;四种弧结局都行,但必须明确选一个。没变化 = 弧缺失,回第 3 节找恶魔。 + +## 5. 定形(→ references/flat-vs-round.md) + +一句话测试:"____" + +- 能一句话说清吗?□ 能(偏扁平) □ 不能(偏圆形) +- 这个形态是刻意选的吗?主题类型:□ 喜剧/群像(扁平合法) □ 严肃/悲剧(必须圆形) +- 圆形公式检查(圆形角色填):出人意料的点____□;事后仍然可信□;缺一 = 伪圆形,回第 2 节补深层或退回扁平 +- 动态切换机会(可选高级项):他在____场景从扁平鼓胀成圆形,用____(一句否定句/一个反常动作)呈现 + +过关线:形态与主题匹配。给修改建议要具体到场景和话,不写"让人物更立体"这类空话。 + +## 6. 原型打底(→ references/archetype-reversal.md) + +- 基础原型(1-2 个,西方 11 原型或本土母题):____ +- 读者期待的位置:____ +- 反转点(≥1,挂在核心冲突上):____ +- 为什么在这里反转(一句话,答不出 = 为反而反):____ +- Father Horst 检验:显著元素____"不只是物"□;象征呈现用细节/动作/对话轻敲,无"这是象征"宣告段落□ +- 人物无内部矛盾 = 刻板印象不是原型 □ + +过关线:反转点一句话说得清;象征靠轻敲不靠宣告。刻意反原型的解构作品跳过本节。 + +## 7. 总评 + +- 角色一句话:____ +- 判定:□ 通过 □ 弱项补救清单:____ □ 回炉 +- 下一步:场景内呈现(见综合 skill character-presentation)/结构规划(见综合 skill story-structure) diff --git a/framework/catalog/dsh/skills/character-design/references/flat-vs-round.md b/framework/catalog/dsh/skills/character-design/references/flat-vs-round.md new file mode 100644 index 0000000..f999077 --- /dev/null +++ b/framework/catalog/dsh/skills/character-design/references/flat-vs-round.md @@ -0,0 +1,141 @@ +# 定形:扁平人物与圆形人物 + +## 原文摘录 + +> "我们可以把人物分为'扁平的'和'圆形的'两种。扁平人物在 17 世纪被称为'幽默性的', 有时指代类型, 有时指夸张的手法。最纯粹的扁平人物只围绕单一的理念或性格特质构建 …… 真正的扁平人物可以只用一句话表达。" + +> "圆形人物拥有自身的无尽生命力 …… 考验一个人物是否算得上圆形人物, 标准在于他能否出人意料, 并同时做到令人信服。" + +> "我们必须承认, 扁平人物本身无法达成圆形人物那样的成就, 而且他们的最佳状态仅存在于喜剧人物中。严肃或悲剧性的扁平人物很容易变得乏味。" + +> — E. M. 福斯特, 《小说面面观》第三讲 / 第四讲 + +## 方法规则 + +### 一句话测试 + +任何人物,试着写一句话概括他(例:"米考伯太太永远不会背弃米考伯先生","贝特伦夫人性子很好,但千万别把她惹急了")。如果一句话能说清,大概率是扁平;如果一句话说不清,大概率是圆形。 + +合并点:布鲁克斯说的"1 维角色:一个形容词就能概括"(references/three-dimensions.md)与本测试是同一把尺子,互相对应。 + +### 圆形公式 = 出人意料 × 仍然可信 + +圆形人物的公式:出人意料(作者给我们"没想到")× 仍然可信(事后觉得"对,这才是他")。两者缺一就不算真圆形。 + +### 扁平人物不是缺陷 + +在喜剧 / 群像 / 节奏中,扁平人物是必要的"轮盘",容易辨认,不会随环境变化,让读者快速进入场景。狄更斯笔下几乎全是扁平人物,但他仍是"最伟大的作家之一"。 + +### 圆形人物是严肃/悲剧的必要条件 + +福斯特明示:"任何时间维度内的悲剧都只能通过圆形人物加以呈现"。严肃/悲剧的扁平人物"很容易变得乏味"。 + +### 扁平 ↔ 圆形可动态切换 + +福斯特举贝特伦夫人为例:平时是扁平("我性子很好,但千万别把我惹急了"),紧急时刻鼓胀成圆形("她完全明白眼下发生的事情有多严重,并不试图劝说自己看轻其中的罪恶与耻辱"),之后又回到扁平。**奥斯汀的"圆盘骤然鼓胀"是写作的高级技巧**。 + +### 关键认识 + +扁平与圆形不是"好 vs 坏",是"功能不同"。严肃主题优先圆形;喜剧/群像优先扁平;复杂主题可以混用——让扁平与圆形的反差冲突比纯写实更尖锐。 + +## 案例全文 + +### 案例 1:简·奥斯汀《曼斯菲尔德庄园》贝特伦夫人——扁平到圆形的动态切换 + +- **问题**:贝特伦夫人平时是扁平人物,紧急时刻能圆形吗? +- **方法论的使用**:福斯特分析她"两个女儿遭遇人生的惨败"时的反应——"她完全明白眼下发生的事情有多严重,并不试图劝说自己看轻其中的罪恶与耻辱,也不向范妮寻求建议" +- **结论**:圆盘骤然鼓胀,现了球形——这是奥斯汀的高级技巧,一段否定句就让扁平 → 圆形 +- **结果**:借此福斯特说"简·奥斯汀是多么会写啊"——圆形人物的"鼓胀"是写作的标志 + +### 案例 2:笛福《摩尔·弗兰德斯》对比简·奥斯汀《爱玛》贝茨小姐 + +- **问题**:同样是人物,摩尔·弗兰德斯能单独成立,贝茨小姐不能单独成立 +- **方法论的使用**:福斯特比较——摩尔像"空地上唯一的树",兀然独立,"我们忍不住要问自己,如果在生活中遇到,我们能不能把她给认出来";贝茨小姐"与海伯里有着千丝万缕的联系",不能与简·费尔法克斯、弗兰克·丘吉尔分开 +- **结论**:摩尔 = 极端的圆形(孤树型);贝茨小姐 = 圆形 + 复杂关系网 +- **结果**:借此说明,圆形的"成立方式"可以是孤树型(笛福)也可以是关系网型(奥斯汀) + +### 案例 3:狄更斯笔下的扁平人物群 + +- **问题**:狄更斯的人物几乎全是扁平,凭什么他是"最伟大的作家之一"? +- **方法论的使用**:福斯特诊断——狄更斯"善于运用类型化和夸张的笔法,让我们能够在人物再次出现时立刻认出他们,同时又能够确保所呈现的效果不流于机械化的套路,对人性的观察也不流于肤浅" +- **结论**:狄更斯的扁平人物群不是缺陷,是"扁平之中蕴含的东西远比严肃的批评家们所认可的更丰富" +- **结果**:借此反驳诺曼·道格拉斯的"小说家的笔法是对现实的篡改"——扁平人物在喜剧/群像中是合法的 + +## 操作步骤 + +1. **对每个人物做"一句话测试"** + - 完成标准:至少为 3 个人物写出"一句话概括",标出哪些能一句话说清,哪些不能 + - 判停条件:如果全部能一句话说清,人物都是扁平;如果全部不能,人物都是圆形 +2. **应用圆形公式** + - 完成标准:对至少 1 个被识别为圆形的人物,检查"出人意料" + "仍然可信"两个条件是否都满足 + - 不满足:标为"硬充圆形的扁平人物"(只意外不可信,或只可信不意外) +3. **诊断主题-类型的匹配** + - 完成标准:判断当前主题是喜剧/群像(→ 优先扁平)还是严肃/悲剧(→ 必须圆形) + - 不匹配:严肃主题用了扁平 → 危险,可能变得乏味 +4. **评估"扁平-圆形动态切换"的可能** + - 完成标准:至少 1 个人物是否有"扁平→圆形→扁平"的可能?如有,这是写作的高级机会 + - 福斯特举贝特伦夫人(奥斯汀)的紧急时刻"鼓胀"为例 +5. **给出修改建议** + - 完成标准:至少 1 条具体修改(如"给配角 X 加一个'鼓胀'瞬间,让他在 Y 场景中说出 Z 的话,显示他平时掩盖的一面") + - 不要空话(如"让人物更立体")——给可操作修改 + +## 应用场景(写作之外) + +其他适用场景,作为方法延伸保留: + +- **角色设计(产品/品牌)**——品牌人格是单一理念(扁平)还是多面性(圆形)? +- **人物评论(读后感/影评/产品评测)**——评估人物"丰满度"和"可信度" +- **面试候选人评估**——候选人是否能"出人意料又令人信服"? +- **历史人物/公众人物评估**——简化叙事 vs 多面性叙事的取舍 +- **教学/培训人物塑造**——教学生"如何让人物丰满" + +注意:对真实人的全面评价不是方法应用,见下方边界。 + +## 边界与失败模式 + +### 不要在以下情况使用 + +- **真实人的全面评价**——这是道德问题,不是方法论;"X 是个圆形人物"在真实人身上可能不公平 +- **纯信息传递(没有人物)**——如新闻报道,不需要人物分类 +- **必须用单一标签的场景**——如数据库标记,扁/圆是写作概念,不是标签 +- **道德评价**——"X 是扁平人物"不等于"X 不好" + +### 作者在书中警告的失败模式 + +- **严肃/悲剧用了扁平人物**——"我永远不会背弃米考伯先生"在喜剧中成立,在悲剧中变成口号(ce07: 司各特式"会讲故事"的单维胜利;ce02: 文学是天才崇拜) +- **追求"绝对写实"反对扁平**——道格拉斯式"非黑即白"的人物观,福斯特批为过激(ce06) +- **过度扁平**——把人物简化为标签,失去"人之为生灵所做出的努力"(ce10: 哈代式命运凌驾) +- **硬充圆形**——出人意料但不可信,是"伪圆形"(如某些"暗黑角色"强行反转) + +### 作者的盲点 / 时代局限 + +- **西方文学中心的视角**——引用的几乎全是英美欧陆小说;非西方叙事传统(如中国章回小说的"扁平人物群")未被充分讨论 +- **现代主义巅峰期的视角**——1927 年;当时还没有"人物弧(Character Arc)"等现代叙事学术语,但"出人意料又令人信服"已经是这个意思 +- **对女性人物的特殊性**——福斯特分析奥斯汀、勃朗特时,似乎把女性人物的"鼓胀"当成特殊现象,没有正面讨论"女性气质"在人物塑造中的作用 + +## 易混方法论 + +- **vs MBTI / 16Personalities**——MBTI 是"性格类型",扁/圆是"作者对人物的呈现方式";X 是 INTJ 不等于 X 是圆形人物 +- **vs 大五人格(Big Five)**——同上,是科学心理学,不是写作方法论 +- **vs 人物原型(Archetype,Jung)**——原型是"集体模式",扁/圆是"呈现方式";X 是英雄原型不等于 X 是圆形。本包 references/archetype-reversal.md 的"原型"是叙事母题原型,三者都要区分开 + +## 冲突标注:扁平是缺陷还是功能? + +- 布鲁克斯(references/three-dimensions.md):一维/扁平 = 缺陷,要补层修复。 +- 福斯特(本文):扁平 = 合法功能,放对位置(喜剧/群像/节奏)就是好人物;只有严肃/悲剧里用扁平才危险。 +- 两条规则都保留,合起来的判断顺序:先问形态是否刻意(喜剧/群像的扁平合法),再看主题是否严肃(严肃/悲剧必须圆形)。 + +## 中文适配 + +- **章回小说的扁平人物群**是福斯特盲点里点名没讨论的传统,正好是中文写作者的现成资源:《水浒》一百零八将多数一人一个鲜明特征(一句话测试天然适用),说书传统和章回体靠"容易辨认、不随环境变化"的扁平人物维持群像节奏。写中文群像,可以理直气壮地用扁平。 +- **戏曲行当**(生旦净末丑)本质是类型化配置,和狄更斯的"类型化和夸张的笔法"同路:观众要的就是再次出现时立刻认出。 +- 圆形公式"出人意料 × 仍然可信"在中文语境完全适用:《红楼梦》主要人物是圆形的范本(宝钗的冷与热、王熙凤的狠与谑都能出人意料又令人信服)。 +- 动态切换的"鼓胀"技巧对应中文写法:平时一句话立住的配角,在家破人亡、生死抉择一场戏里突然说出/做出超出自身定式的事,一段否定句或一个反常动作就够,不必铺垫整章。 + +## 与其他方法的关系 + +- **建**:配角原则四书一致——扁平形态 + 1-2 个变量即可 → references/seven-variables.md +- **立体**:3 维无错位的一维角色 = 一句话扁平 → references/three-dimensions.md +- **打底**:圆形人物的"出人意料"常靠站在原型上反转实现 → references/archetype-reversal.md +- **与 visible-private-life(隐秘生活可见性,框架本体归综合 skill character-presentation)的区别**:扁/圆是**人物形式层**的分类——一句话测试问的是人物的呈现方式(单一特质还是多面、能否出人意料);可见性是**人物本体论层**的框架——问的是作者是否对人物了如指掌、小说是否提供了"隐秘的内在人生是可见的"这种现实给不了的可见性。扁/圆管"这个人物是什么形态",可见性管"人物的内在是否可知",一个分类人物,一个划分小说与现实人,是两个独立的问题,不要混用。 +- **跨域指针**(不展开):圆形人物的"出人意料"需要作者对人物了如指掌,呈现层技法(可见的私生活)见综合 skill character-presentation;"出人意料"是蒙蔽读者的高级形式,蒙蔽技法见综合 skill scene-craft(mystification);扁/圆管单个人物分类,多个人物 vs 情节的拉锯见综合 skill novel-diagnosis(plot-character-tug) diff --git a/.agent/skills/character-design/references/inner-demon.md b/framework/catalog/dsh/skills/character-design/references/inner-demon.md similarity index 100% rename from .agent/skills/character-design/references/inner-demon.md rename to framework/catalog/dsh/skills/character-design/references/inner-demon.md diff --git a/framework/catalog/dsh/skills/character-design/references/seven-variables.md b/framework/catalog/dsh/skills/character-design/references/seven-variables.md new file mode 100644 index 0000000..748992e --- /dev/null +++ b/framework/catalog/dsh/skills/character-design/references/seven-variables.md @@ -0,0 +1,117 @@ +# 建角色:角色 7 大变量 + +## 原文摘录 + +> "Surface affectations and personality... Backstory... Character arc... Inner demons and conflicts... Worldview... Goals and motivations... Decisions, actions, and behaviors... seven major categories of character possibility... With seven knobs on the control panel, there are no less than ten million totally unique settings for any character you can dream up." +> +> — Larry Brooks, *Story Engineering* (2011), Part 3 + +## 方法规则 + +### 角色不是一个形容词,也不是一个职业 + +角色由 7 个独立变量组成。每个变量可以独立调 1-10 档。7 变量 × 10 档 = 1000 万+ 唯一组合,不会重样。 + +### 7 个变量 + +1. **表层人格(Surface Affectations)**:外人眼中的形象,包括外貌、口头禅、怪癖 +2. **背景故事(Backstory)**:故事开始前发生的事,决定他现在是谁 +3. **角色弧(Character Arc)**:故事中角色的成长/改变路径 +4. **内在恶魔(Inner Demons)**:角色内心最深处的恐惧/创伤/伤痕(专论见 references/inner-demon.md) +5. **世界观(Worldview)**:角色对世界/道德/他人的根本信念 +6. **目标与动机(Goals and Motivations)**:角色想要什么,为什么想要 +7. **决策/行动/行为(Decisions, Actions, Behaviors)**:角色实际做了什么 + +### 输入与输出:行为是前 6 个变量的测试 + +- 前 6 个变量是"输入",第 7 个是"输出" +- 第 7 个(行为)是其余 6 个的"测试"——前 6 设定一致,第 7 自然一致;前 6 矛盾,第 7 就矛盾(这是写作的 bug 来源) +- 每个变量可以独立调,1-10 档;但一个变量的极端值(如背景故事 9,但角色弧 2)可能产生不一致 + +### 三种用法 + +- **创建角色**:7 变量全部设定 +- **诊断角色**:缺哪个变量 = 角色缺哪个维度 +- **对比角色**:两个角色哪些变量不同 → 区分度 + +## 案例全文 + +### 案例 1:一个"懦弱的士兵"角色 7 变量完整版 + +- **问题**:写作者想写"懦弱士兵"但脸谱化 +- **方法论的使用**: + 1. 表层:沉默寡言,总是低头 + 2. 背景:父亲是越战英雄,他无法复制父亲的勇气 + 3. 角色弧:学会做自己(而非做父亲) + 4. 内在恶魔:害怕重复父亲的命运 + 5. 世界观:"英雄主义是神话,普通人活下去就是英雄" + 6. 目标:让队友活着回家 + 7. 行为:关键时刻违抗命令救孩子,自己受重伤 +- **结论**:7 变量设定后,角色自然立体 +- **结果**:演示"7 变量填满 = 角色立住" + +> 中文落地:越战背景不是要点,换成中文语境里任何"父辈荣耀压力"的设定(父亲是战斗英雄、劳模、世家从军)结构都成立;世界观那句"英雄主义是神话,普通人活下去就是英雄"照原文保留即可,不需要翻译腔处理。 + +### 案例 2:作者 5 部小说主角(变量差异化角度) + +- **问题**:5 部小说 = 5 个主角,怎么不重样? +- **方法论的使用**:每个主角只调 2-3 个变量的极端值(如 Backstory 1 vs Backstory 9,Goal 5 vs Goal 9) +- **结论**:7 变量差异化 = 5 个完全不同主角 +- **结果**:全出版,0 重样 + +> 同一案例在 references/three-dimensions.md(角度:每个主角按 3 维建设,一本获 *Publishers Weekly* 年度最佳)和 references/inner-demon.md(角度:每个主角各有一个清晰的内在恶魔)再次出现。角度不同,三处都保留。 + +## 操作步骤 + +1. **选 1 个角色** + - 完成标准:用户指定 1 个 +2. **逐变量填(7 个)** + - 完成标准:7 段,每段 3-5 句具体描述 + - 提示:不要照抄变量名,写具体内容 + - 例:不要"角色有背景故事",要"她 12 岁目睹父亲车祸,之后 5 年不说话" +3. **一致性检查** + - 完成标准:验证 7 变量彼此一致 + - 检查:"他害怕亲密"(5)+ "他主动追求每个人"(7)= 矛盾 + - 如果矛盾:修一个变量,不要修全部 +4. **角色弧检查(变量 3)** + - 完成标准:故事开始时的角色 vs 故事结束时的角色,列出 3 个变化 + - 没有变化 = 角色弧缺失,用 references/inner-demon.md 找冲突 + +## 边界与失败模式 + +### 不要在以下情况使用 + +- 角色已成型,想检查特定维度(用 references/three-dimensions.md 或 references/inner-demon.md) +- 写 1 个角色 vs 群像的对比(用 references/three-dimensions.md 区分) +- 写非常配角(1-2 变量就够,7 变量过度) + +### 作者警告的失败模式 + +- 7 变量都"中庸"(4-5 档)= 没特色——至少 2-3 个变量在极端 +- 第 7(行为)跟前 6 不一致——必须先改前 6,不要直接改行为 +- 把变量 5(世界观)当成"哲学标签"——必须是角色具体信什么 + +### 作者盲点 + +- 7 变量假设 1 个主角——群像需要 1+7(1 主角 + 7 配角)的多份填表 +- 默认 7 变量在故事中不变——变量 3(角色弧)必然变,其他也可能变 +- 默认所有角色都该填 7 变量——反派/小配角可以少填 + +## 易混方法论 + +- "Character Bible"(影视行业)——类似但更宽,含外貌/关系图等 +- "16 Personalities"(MBTI)——是性格类型,不是 7 变量全维度 +- "Enneagram"(九型人格)——是 9 种类型,不是变量组合 + +## 中文落地 + +- 7 变量本身语言中立。中文填写时别把英文心理学词汇直接抄成标签——"他有信任问题"是哲学标签,要写成他具体信什么、做什么。 +- 世界观变量在中文小说里最容易写成套话:不写"他相信正义",写他会说出口的那句具体判断("过日子就是熬")。 +- 群像 1+7 多份填表法对章回体、家族群像式中文小说同样适用:每个角色一张表,逐个填,不批量。 + +## 与其他方法的关系 + +- **立体**:表层人格即三层信息的表层;7 变量填完后再查三层是否错位 → references/three-dimensions.md +- **驱动**:变量 4 内在恶魔是角色弧的引擎,专论 → references/inner-demon.md +- **定形**:7 变量填满的角色若仍能一句话说清,检查扁平形态是否刻意为之 → references/flat-vs-round.md +- **打底**:角色弧与世界观可挂到叙事原型上做反转 → references/archetype-reversal.md diff --git a/framework/catalog/dsh/skills/character-design/references/three-dimensions.md b/framework/catalog/dsh/skills/character-design/references/three-dimensions.md new file mode 100644 index 0000000..76a95d9 --- /dev/null +++ b/framework/catalog/dsh/skills/character-design/references/three-dimensions.md @@ -0,0 +1,123 @@ +# 立体化:角色 3 维度(表层/内层/深层) + +## 原文摘录 + +> "Three very separate and compelling layers—dimensions, in this context—that are carefully crafted to bring your story alive with resonant emotional depth. The first dimension is who the world sees. The second dimension is who the character is in private. The third dimension is who the character truly is, in spite of how she or he may present in either of the first two dimensions." +> +> — Larry Brooks, *Story Engineering* (2011), Part 3 + +## 方法规则 + +### 一个角色至少有 3 层独立的信息维度 + +大多数角色只写到 1 维(扁平),极少数写到 3 维(立体)。 + +**3 维度**: + +1. **表层(Surface Affectations)**:别人眼中的角色——外貌、口头禅、社会身份、第一印象 + - 例:严肃的律师,总是穿西装,不开玩笑 +2. **内层(Private Self)**:角色独处时的真实状态——内心挣扎、恐惧、爱好、矛盾 + - 例:独处时写诗,听 80 年代摇滚,害怕死亡 +3. **深层(True Self)**:角色自己都不知道的核心——驱动一生的根本信念/创伤/欲望 + - 例:童年被父亲抛弃,一生渴望被认可但永不表达 + +### 3 维的关系 + +- 表层是面具,内层是脱下面具的自己,深层是面具下连自己都不知道的核心 +- 大多数角色 3 维是**错位**的——表层严肃但内层温柔,深层害怕被爱 +- **戏剧来自错位**——关键场景里,3 维的错位会暴露/转移 +- 写作者必须能**列出 3 维的具体内容**,否则角色还在 1 维 + +### 3 维 vs 1 维 + +- 1 维角色:一个形容词就能概括(勇敢/聪明/坏) +- 3 维角色:需要 3 个以上不同维度的形容词,且彼此矛盾 + +### 深层 = 内在恶魔(合并点) + +本文的"深层"(角色自己都未必意识到的驱动力)与 references/inner-demon.md 的"内在恶魔"是同一件事。两处都保留:本文从信息分层角度说"它是角色最底下的一层",references/inner-demon.md 从冲突与弧的角度说"它是驱动角色弧的引擎"。 + +## 案例全文 + +### 案例 1:Walter White(《Breaking Bad》) + +- **问题**:一个中学化学老师变成毒枭,怎么让读者又恨又爱? +- **方法论的使用**: + - 表层:中学老师,收入低,被老婆看不起 + - 内层:孤独,害怕平庸一辈子,渴望证明自己 + - 深层:童年时父亲(科学家)早逝,一生想完成父亲的"伟大事业" +- **结论**:3 维的错位让观众持续 5 季 +- **结果**:史上最成功的反英雄之一 + +### 案例 2:作者 5 部小说主角(3 维建设角度) + +- **问题**:5 部小说主角怎么都不脸谱化? +- **方法论的使用**:每个主角都按 3 维建——表层职业身份,内层矛盾,深层创伤 +- **结论**:3 维 + 7 变量 = 1000 万+ 角色组合,不会重样 +- **结果**:5 部全出版,1 本获 *Publishers Weekly* 年度最佳 + +> 同一案例在 references/seven-variables.md(角度:变量差异化)和 references/inner-demon.md(角度:各带不同恶魔)再次出现。角度不同,三处都保留。 + +### 案例 3:Don Draper(《Mad Men》,作为反例背景) + +- **问题**:60 年代广告公司主管,为什么观众 7 季都爱看? +- **方法论的使用**:表层(成功主管)+ 内层(酗酒、外遇)+ 深层(童年在妓院长大,假身份) +- **结论**:3 维错位撑起 7 季 +- **结果**:经典反英雄 + +## 操作步骤 + +1. **选定 1 个角色** + - 完成标准:用户指定 1 个角色(主角/反派/配角) +2. **分别写出 3 维** + - 完成标准:3 个独立段落,每段 3-5 句 + - 提示:不要复制表层到内层,不要把深层当"我小时候如何" + - 深层 = 角色自己都未必意识到的驱动力 +3. **验证 3 维错位** + - 完成标准:列出 3 维之间的矛盾 + - 关键检查:"如果 3 维一样,角色是 1 维" +4. **找出 3 维都会"现身"的关键场景** + - 完成标准:至少 2 个场景,角色在场景里表层/内层/深层都"露馅"瞬间 + - 深层在关键时刻"浮出水面" = 角色弧的关键节拍 + +## 边界与失败模式 + +### 不要在以下情况使用 + +- 群像管理(≥ 3 个主角)——给每个主角分别用 1 次,不要批量 +- 写反派需要更具体的"动机"(用 references/seven-variables.md 找 Inner Demons) +- 写配角(用 references/seven-variables.md 的 1-2 个旋钮即可) + +### 作者警告的失败模式 + +- 深层写得太"哲学"——"她是个追寻自由的人"不是深层,是修辞 +- 深层只是内层的延伸——"表层严肃,内层不严肃,深层想严肃" = 错位失败 +- 3 维都用相同词汇——必须各有具体内容 + +### 作者盲点 + +- 3 维假设"角色有内省能力"——某些角色(例如小孩、动物、严重心理障碍)不适用 +- 默认 3 维都"善"——反派 3 维可以全是"自我",这也是有效的 +- 默认 3 维稳定——3 维在故事中可能演化(character arc),不是固定 + +## 易混方法论 + +- 心理学的"人格面具"(Persona / Shadow,Jung)——哲学源头相似,但应用不同 +- 写作的"角色原型"(Christopher Vogler 12 archetype)——那是类型,不是维度;本包 references/archetype-reversal.md 说的"原型"是克拉克的叙事母题原型,与 Vogler 的角色类型原型也不是一回事 + +## 冲突标注:一维是缺陷,还是合法形态? + +- 布鲁克斯(本文):1 维 = 缺陷,要补内层和深层修复。 +- 福斯特(references/flat-vs-round.md):扁平(≈ 一维)是合法功能,喜剧/群像优先,不必人人写圆;但严肃/悲剧必须圆形。 +- 两条规则都保留:先问"这个角色的形态是不是刻意选的"。配角、喜剧角色可以刻意一维;主角、严肃/悲剧角色一维就是缺陷。 + +## 中文落地 + +- 3 维法在中文网文里尤其值得用:网文主角常被写成"职业 + 金手指"的 1 维配置,补内层(独处时的真实状态)和深层(连自己都不说的渴望)是最快的去脸谱化手段。 +- 深层例"童年被父亲抛弃,一生渴望被认可但永不表达"是通用句式;中文语境可换成本土创伤源(重男轻女家庭、留守经历、父辈污点),但必须落到具体事件和动作,不能只写一个标签。 + +## 与其他方法的关系 + +- **建**:表层即 7 变量的表层人格,深层往往要靠背景故事(变量 2)供出 → references/seven-variables.md +- **驱动**:深层 = 内在恶魔;深层"浮出水面"的关键节拍常与故事中点配合(中点的结构定位见综合 skill story-structure) → references/inner-demon.md +- **定形**:3 维无错位 = 1 维 = 一句话能说清的扁平,形态该不该改由主题定 → references/flat-vs-round.md diff --git a/framework/catalog/dsh/skills/character-presentation/SKILL.md b/framework/catalog/dsh/skills/character-presentation/SKILL.md new file mode 100644 index 0000000..b2c723d --- /dev/null +++ b/framework/catalog/dsh/skills/character-presentation/SKILL.md @@ -0,0 +1,110 @@ +--- +name: character-presentation +description: | + 写小说时要把人物呈现给读者看,而不是讲给读者听,遇到这些情况激活:人物登场段读起来像 + 性格形容词清单,用了勇敢、热情、冷酷等抽象词但读起来假;人物扁平、脸谱化、群像分不清; + 次要人物只有 200 字登场空间不知道怎么让人记住;情节靠巧合推动,主角无故倒霉;人物没戏、 + 该转变但读者看不到转变;想知道"如何显示人物"而不是"告诉"。 + 关键 trigger:"细节马赛克 / mosaic of detail / 人物立体 / 人物脸谱化 / 登场段 / + 性格形容词 / show not tell / status details / Tom Wolfe / 网文主角人设 / + 性格碰撞 / 性格即命运 / 反常即戏 / 反常瞬间 / 关系网 / 隐藏关系 / 人物很立体 / + 比现实更真实 / 人物让我看到了看不到的东西 / 过程发现 / 人物自己说话了"。 + 不适用于:人物变量设计、人物弧线与原型定位、扁圆人物一句话测试(归 character-design); + 纯意识流、极简主义与人物作为思想载体的抽象哲学小说;真实人物之间的理解问题(那是心理学 + 不是文学);非虚构写作(纪实作品人物的话必须基于事实)。 + 与 dialogue-craft 交接:说话方式、句长、口头禅、同一声音诊断、遮住名字测试归 dialogue-craft; + 本 Skill 只管登场呈现、关系网、反常瞬间与"过程发现"叙事。 + 与 character-design 交接:建角变量与弧线归后者;定型后的场景内呈现归本 Skill。 +--- + +# 人物呈现(character-presentation) + +解决一件事:让人物被读者自己看见,而不是被作者讲给读者——用细节装配登场,让隐秘内在可见,用关系网显性格,用性格碰撞出命运,用反常瞬间翻转身份,让人物发出自己的声音。 + +## 方法索引 + +按创作动作组织;方法细节、案例、引文都在 references 里,这里只给一句话和指针。 + +### 用具体物装配登场 + +- 把"身份细节"扩展成细节马赛克:从 10+ 维度里精心挑 5-9 个具体到感官的细节,让读者自己合成完整的人 → references/detail-mosaic.md +- 每个细节是一个反推钩子(背头→爱面子,踝部枪→危险职业);反推不出任何东西的细节换掉;穷举 10 维度是糟糕写作 → references/detail-mosaic.md +- 抽象性格形容词是"失败的告诉",全部换成 1-2 个具体细节;Clark 检验:删一个细节人物变轻才必要 → references/detail-mosaic.md +- 中文适配:补家当与身份标志、服饰面料、玉石材质、茶酒待客等本地维度 → references/detail-mosaic.md + +### 让隐秘的内在可见 + +- 人物"真实"的标准不是像现实中的某个人,而是作者对其了如指掌 → references/visible-private-life.md +- 人物有两面:历史的一面(可观察行为)和虚构的一面(感情、幻想、没说出口的话),好小说必须写后一面 → references/visible-private-life.md +- 可见性分层:基础层是这个人物被写透了,更高一层是人物代表的人性可见 → references/visible-private-life.md + +### 用关系网显性格 + +- "他是谁"不能问他自己,要问他的关系网;给人物至少三重关系,五个关系就是人物的五张面孔 → references/relationship-web.md +- 关系要对比:同一个人在不同关系里反应不同才算设计到位,全是同一种反应等于没设计 → references/relationship-web.md +- 关系必须推动情节,装饰关系删掉或改;隐藏关系(读者知道人物不知道)是戏的来源 → references/relationship-web.md +- 群像区分:每个主要人物的关系网要独特,把两人的关系网互换还能用就是没设计好 → references/relationship-web.md + +### 用性格碰撞出命运 + +- 不让主人公倒霉,让他遇到另一个人:单个性格不产生命运,性格遇上性格才产生命运 → references/character-collision.md +- 把巧合翻译成性格碰撞:删掉这个巧合,主人公凭性格照样会遇到这件事,翻译才算成功 → references/character-collision.md +- 每个主要人物用 3-5 个性格词定位(删一词不像、加一词模糊),设计性格链和"判断瞬间";反派也要有性格,否则是工具人 → references/character-collision.md + +### 用反常瞬间翻转身份 + +- 人物的戏藏在"应该这样但没这样、不该这样却这样了"的瞬间;反常是人物身份变化的开始 → references/abnormal-moment.md +- 三种反常:行为反常、关系反常、时间反常;反常必须落实成一个具体动作或一句对话,不用形容词概括 → references/abnormal-moment.md +- 设计 3-5 个排成递进链;好的反常不事后解释:"原来如此"是成,"莫名其妙"是败,"早猜到了"是太露 → references/abnormal-moment.md + +### 让人物发出自己的声音 + +- 写足够久,人物会说出作者没计划的话;作者从发号施令的控制者转为感同身受的记录者 → references/voice-discovery-process.md +- 什么人说什么话、遮住名字测试、同一声音诊断 → `dialogue-craft` 的 [character-voice.md](../dialogue-craft/references/character-voice.md) + +### 总原则:不宣告,让读者反推 + +- 两本书三个源单元做同一件事:不宣告、不自夸、不自我介绍,用细节、关系、动作、对话替换形容词和标签;三个源单元的视角与引文见 references/detail-mosaic.md"多书合并点"节。 + +### 张力标注 + +- 外在细节装配(Clark)vs 内在可见(福斯特):分工是登场层 vs 深度层,细节堆得多 ≠ 人物被写透,见 references/visible-private-life.md"张力标注"节。 +- 事前设计(关系网、性格词)vs 声音的过程发现(余华):分工是骨架 vs 血肉,见 references/voice-discovery-process.md 张力标注节。 + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|---------| +| references/detail-mosaic.md | status details→细节马赛克、10+ 维度、5-9 个感官细节核心规则、反推钩子、Clark 检验、O'Neill 登场与 Belva Kent 胶带案例、替换抽象形容词四步、三大失败模式、中文本地化维度(中文适配)、多书合并点"不宣告让读者反推"、与 show-don't-tell/archetype-toolkit/dialogue-as-action/voice-equalizer 的区分 | +| references/visible-private-life.md | 小说与现实人的本体论差异、"真实=作者了如指掌"判断标准、小说比历史更真实、阿兰两面性、摩尔·弗兰德斯/维多利亚女王/海蒂 vs 米嘉案例、可见性分层、五步操作、四大失败模式、盲点与说书人可见(中文适配)、与代入感/心理现实主义/神入的区分 | +| references/relationship-web.md | 人物性格在关系里不在自我描述里、王熙凤与秦可卿三层关系、四条核心原则、王熙凤/林冲/《杀手》/《苔丝》四案例、六步操作(含 ❌✅ 王熙凤原句)、隐藏关系、群像互换检验、常见错误表 | +| references/character-collision.md | "性格从来就不是命运"题旨引文、命运=性格碰撞、错误命运 vs 正确命运、《促织》成名+里胥/林冲+高俅/王熙凤+贾瑞/苔丝四案例、巧合翻译表、性格速写 3-5 词、性格链、判断瞬间、常见错误表 | +| references/abnormal-moment.md | 沃滋沃斯两个反常、三种反常类型、沃滋沃斯芒果/小促织跳袖口/王熙凤骂街原句/《项链》四案例、列常态→找反常→具体化→递进链→不解释五步、常见错误表 | +| references/voice-discovery-process.md | 控制阶段→记录阶段、余华三案例、过程发现六步、传声筒失败模式、事前设计 vs 过程发现张力标注 | +| references/_coverage.md | 六个源单元的覆盖对照表与跨域指针(说话方式正文见 dialogue-craft/references/character-voice.md) | + +## 脚本 + +| 脚本 | 用途 | +|------|------| +| references/presentation-checklist.md | 人物呈现自查台账:登场细节装配、内在可见、关系网、碰撞设计、反常设计、声音检查、总判断标准,一份填完 | + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 红线 + +- 只给当前创作阶段的建议,不越权改设定主权、不绕过检测链、不复制粘贴其它 Skill 的 owner 定义。 +- 无用户明确授权不得替用户定稿或提交 Git。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/dsh/skills/character-presentation/references/_coverage.md b/framework/catalog/dsh/skills/character-presentation/references/_coverage.md new file mode 100644 index 0000000..d5388cd --- /dev/null +++ b/framework/catalog/dsh/skills/character-presentation/references/_coverage.md @@ -0,0 +1,13 @@ +# character-presentation 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| aspects-of-the-novel/visible-private-life | references/visible-private-life.md | +| bifeiyu-novel-skill/bifeiyu-anti-norm | references/abnormal-moment.md | +| bifeiyu-novel-skill/bifeiyu-character-fate | references/character-collision.md | +| bifeiyu-novel-skill/bifeiyu-relationship | references/relationship-web.md | +| bifeiyu-novel-skill/bifeiyu-relationship | references/detail-mosaic.md | +| wo-neng-fou-xiang-xin-zi-ji/character-voice-discovery | references/voice-discovery-process.md(过程发现);说话方式技术 → dialogue-craft/references/character-voice.md | +| writing-tools-clark/mosaic-of-detail | references/detail-mosaic.md | diff --git a/framework/catalog/dsh/skills/character-presentation/references/abnormal-moment.md b/framework/catalog/dsh/skills/character-presentation/references/abnormal-moment.md new file mode 100644 index 0000000..3a95639 --- /dev/null +++ b/framework/catalog/dsh/skills/character-presentation/references/abnormal-moment.md @@ -0,0 +1,178 @@ +# 反常即戏:找到"不该这样但这样了"的瞬间 + +来源:(毕飞宇《小说课》第 4 讲,案例取自《布莱克·沃滋沃斯》"等待"反常 + 整本书) + +> 「沃滋沃斯这个乞丐特殊了,他牺牲了他宝贵的谋生时间,一直在那里等待'我'。……不要小瞧了这个反常,从这个反常开始,沃滋沃斯的身份开始变化了。」 + +() + +## 原文摘录 + +《布莱克·沃滋沃斯》第五个乞丐出场前,奈保尔写了一段"反常": + +> 一个乞丐(沃滋沃斯),**不乞讨**——他在路边**等待**一个人(孩子)。 +> 一个乞丐(沃滋沃斯),**不讨饭**——他**请**孩子吃芒果。 + +**两个反常**: + +- 乞丐不去讨饭 → 失去"乞丐身份" → 显露"孤独者身份" +- 乞丐请人吃东西 → 关系反转 → 显出"爱"和"分享" + +**反常是人物身份变化的开始**。() + +## 方法规则 + +**反常即戏** = 找到"应该这样但没有这样"或"不应该这样但这样了"的瞬间。 + +**反常的三种类型**: + +1. **行为反常**:做了不该做的事 / 不做该做的事 +2. **关系反常**:用了不该用的关系 / 不用该用的关系 +3. **时间反常**:在该出现时没出现 / 在不该出现时出现 + +**反常是小说里最重要的"戏"**——它让人物"从 A 变成 B"。() + +## 案例全文 + +### 案例 1:奈保尔 沃滋沃斯请孩子吃芒果 + +- 乞丐请人吃 → 反常 +- 反常 → 他是"孤独者"不是"乞丐" +- 反常 → 他需要孩子 +- **整个小说从这里开始反转** + +### 案例 2:蒲松龄《促织》小促织跳到成名袖口 + +- 虫怕人 → 正常 +- 虫主动跳到人身上 → **反常** +- 反常 → 它是孩子变的 +- 反常 → 父亲不认识儿子,儿子认得父亲 +- **整个悲剧的"温度"在这里反转** + +### 案例 3:曹雪芹 王熙凤三句"骂街" + +> "别放你娘的屁了。再不带我看看,给你一顿好嘴巴。" + +- 贵族妇女在亲人面前骂街 → 反常 +- 反常 → 她和贾蓉的关系不正常 +- **揭示了隐藏关系** + +### 案例 4:莫泊桑《项链》路瓦赛太太决定买钻石项链还 + +- 一条假项链 → 不需要买真的还 +- 买真的还 → 花了 10 年 +- **反常但合理**——因为她诚实 / 因为她不知道是假的 +- 反常支撑了 10 年的故事 + +(以上四案例均出自) + +## 触发场景 + +1. 你的人物"没什么戏" → 找他的反常瞬间 +2. 你的情节"太平"了 → 加一个反常点 +3. 你想"揭示秘密" → 用反常代替直接说明 +4. 你的人物"该变了"但读者看不到变化 → 设计反常触发变化 +5. 你的"高潮"不够高潮 → 那个瞬间够反常吗? + +() + +## 操作步骤 + +### 步骤 1:列出"应该的常态" + +为你的主角 / 对手 / 关键人物,列出他**应该**有的行为模式: + +```yaml +人物:成名 +应该的常态: + - 父亲被责 → 想办法 + - 儿子惹祸 → 责罚儿子 + - 抓到促织 → 养好交差 + - 虫子跳来跳去 → 抓住它 +``` + +### 步骤 2:找出"反常瞬间" + +在常态列表中找**反例**: + +```yaml +反常: + - 儿子惹祸 → 儿子自杀(他没想父亲会这样) + - 抓到促织 → 促织主动跳上他(虫子不该这样做) + - 虫子 → 跳上袖口(虫子怕人才对) +``` + +**检验**:这个反常是**人物选择的反常**,还是**情境 / 情节的反常**? + +- 人物选择的反常 → 揭示性格 +- 情境的反常 → 推动情节 + +**两者都好**。 + +### 步骤 3:写"反常动作" + +把反常**具体化**为一个动作或对话: + +``` +❌ "沃滋沃斯很孤独"(形容词) +✅ 沃滋沃斯在路边等孩子,请孩子吃芒果(具体动作) +``` + +### 步骤 4:连锁反常 + +**一个反常通常不够**——要设计**3-5 个反常**形成链条: + +``` +反常 1:乞丐等孩子 +反常 2:乞丐请孩子吃芒果 +反常 3:乞丐讲"少年诗人和女诗人的故事" +反常 4:乞丐临死时告诉孩子"故事是假的" +``` + +每个反常都比上一个更"反常"——形成递进。 + +### 步骤 5:反常的"事后解释" + +**好的反常不解释**——读者读后能自己想通。 + +**检验**: + +- 读者读完后会"啊原来如此" → 好的反常 +- 读者读完后"莫名其妙" → 反常没设计好 +- 读者读完后"早猜到了" → 反常太明显 + +(以上步骤均出自) + +## 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 反常太多 | 假 | 短篇 1-2 个,递进式 | +| 反常没暗示 | 突兀 | 反常前要有"常态铺垫" | +| 反常变巧合 | 廉价 | 反常是"性格驱动",巧合是"作者安排" | +| 反常没后果 | 浪费 | 每个反常都要改变人物 / 情节 / 关系 | + +() + +## 适用边界 + +- **适合**:所有虚构叙事 +- **短篇必需**:短篇的"戏"几乎全靠反常 +- **慎用**:纯写实 / 纯纪录(它们恰恰要常态) + +() + +## 一句话总结 + +> **人物"应该这样"是常态;"不该这样但这样了"是戏——所有好小说的关键瞬间都藏在这里。** + +() + +## 跨 skill 链接 + +- 与 `bifeiyu-character-fate` 互补:反常是"性格即命运"的爆发点。(同在本包,见 references/character-collision.md) +- 与 `bifeiyu-iceberg` 配合:反常必有"水下"内容——一个反常的 7/8 在水下。(bifeiyu-iceberg 归综合 skill show-and-omission) +- 与 `bifeiyu-foreshadowing` 配合:反常前要有常态铺垫。(bifeiyu-foreshadowing 归综合 skill foreshadow-payoff) +- 与 `bifeiyu-momentum` 关联:反常是"势"的转折点。(bifeiyu-momentum 归综合 skill narrative-momentum) + +(;综合 skill 归属标注为本次合并所加) diff --git a/framework/catalog/dsh/skills/character-presentation/references/character-collision.md b/framework/catalog/dsh/skills/character-presentation/references/character-collision.md new file mode 100644 index 0000000..edbeebf --- /dev/null +++ b/framework/catalog/dsh/skills/character-presentation/references/character-collision.md @@ -0,0 +1,200 @@ +# 性格即命运:设计碰撞而非制造巧合 + +来源:(毕飞宇《小说课》第 7 讲,案例取自《促织》"迁讷遇猾黠" + 整本书) + +> 「蒲松龄只给了他四个字,'为人迁讷'。'为人迁讷'能说明什么呢?什么都说明不了。没听说'为人迁讷'就必须倒霉,性格从来就不是命运。问题出就出在《促织》开头的那个'里胥'身上,'里胥猾黠'。当'迁讷'遇见了'猾黠',性格就必须是命运。」 + +() + +## 方法规则 + +### 命运不是性格单独决定的——是性格 + 性格碰撞出来的 + +- 迁讷 + 猾黠 = 必然被欺负 +- 林冲(忍)+ 高俅(恶)= 必然被逼上梁山 +- 哈代式的苔丝(纯)+ 失贞 = 必然悲剧 + +**单个性格不产生命运,碰撞才产生命运。**() + +### 核心洞察 + +不要让你的主人公"倒霉",让你的主人公"遇到另一个人"。 + +"一个人遇到另一个人"——这是小说最深的结构。() + +**错误的"命运"**: + +- 主人公生来就惨 +- 主人公被随机事件压垮 +- 主人公被作者安排"该轮到你了" + +**正确的"命运"**: + +- 主人公的特定性格 +- 遇上另一个特定性格的对手 +- 碰撞产生必然结果 + +() + +## 案例全文 + +### 案例 1:蒲松龄《促织》成名 + 里胥 + +``` +成名 = 迁讷(老实、不会说话) +里胥 = 猾黠(狡猾、贪婪) +碰撞:迁讷遇上猾黠,必然被欺压 +``` + +**升级链条**: + +- 里胥报成名做里正 → 成名不敢反抗 +- 促织征收 → 成名不敢敛户口 +- 抓到差促织 → 成名被打得不能行走 +- 儿子自杀 → 成名只能继续"用儿子换促织" + +**每一步都是性格的必然**。 + +### 案例 2:施耐庵《水浒》林冲 + 高俅集团 + +``` +林冲 = 技术好、心稳、想留在体制内 +高俅 = 权贵、霸凌、不讲理 +碰撞:林冲越想体面,高俅越不让 +``` + +### 案例 3:曹雪芹《红楼梦》王熙凤 + 贾瑞 + +``` +王熙凤 = 毒辣、聪明、好玩弄人 +贾瑞 = 痴情、自以为是 +碰撞:王熙凤"毒设相思局",贾瑞必死 +``` + +### 案例 4:哈代《苔丝》苔丝 + 失贞的阶级 + +``` +苔丝 = 纯真、忠诚 +亚雷 = 资产阶级恶少 +碰撞:失贞后无法在丈夫面前自处 +``` + +(以上四案例均出自) + +## 触发场景 + +1. 你的人物"该倒霉"但没有具体原因 → 加一个对手 +2. 你的情节靠"巧合"推动 → 把巧合换成"性格碰撞" +3. 你的主角"觉醒"了但没说服力 → 他的对手是什么性格?那个性格决定了他的觉醒路径 +4. 你的悲剧"不悲" → 看看读者是否同情——同情的关键是"性格可识别" +5. 你写"反派人"但他像工具人 → 反派也要有"性格",碰撞才立体 + +() + +## 操作步骤 + +### 步骤 1:定义"主要碰撞" + +列出主角和**最重要的对手 / 环境**: + +```yaml +主角性格:A、B、C 三个特征 +对手性格:X、Y、Z 三个特征 +必然碰撞:主角的 [A] 遇上对手的 [X] → 必然 [事件] +``` + +### 步骤 2:把"巧合"翻译成"性格碰撞" + +| ❌ 巧合 | ✅ 性格碰撞 | +|-------|----------| +| 主角出门撞见坏人在做坏事 | 主角的好奇心(性格)→ 必然去查看 | +| 仇人正好路过 | 主角的某种执念 → 必然相遇 | +| 突然生病 | 主角的某种弱点 → 加上对手的某种利用 | +| 错认了人 | 主角的某种误解倾向(性格)+ 对方的某种特征 | + +**检验**:把这个巧合删掉,主角还会遇到这件事吗? + +- 会的(因为性格)→ 巧合换得好 +- 不会 → 你还有巧合没换 + +### 步骤 3:写"性格速写" + +每个主要人物用 **3-5 个性格词**定义: + +``` +成名:迁讷、善良、无能、坚韧(妻子替他想办法) +里胥:猾黠、贪婪、霸凌 +``` + +**检验**: + +- 删掉一个性格词 → 人物会"不像" → 这个词是关键 +- 加一个性格词 → 人物会"模糊" → 加多了 + +(注意:这 3-5 个性格词是给作者定位用的设计工具,不是写进正文的标签——"性格要通过动作显现,不是形容词",见本条所属常见错误表,以及与 的合并说明 references/detail-mosaic.md"多书合并点"节。) + +### 步骤 4:设计"性格链" + +不是一次碰撞——是**连串碰撞**: + +``` +性格 A 遇性格 X → 事件 1 +事件 1 改变 → 性格 A 暴露新侧面 +新侧面 + 性格 Y → 事件 2 +事件 2 → 性格 A 再暴露 +... +``` + +**林冲的链**: + +- 忍(性格)+ 高俅霸道 → 被陷害 +- 忍 + 路上被欺 → 咬牙忍 +- 忍 + 草料场 → 还在忍 +- 忍 + 听到阴谋 → **忍不了**——爆发 +- 爆发 + 柴进 → 上山 + +### 步骤 5:写"性格判断" + +每个主要人物应该有**一个"判断瞬间"**——读者看到他做这一个动作 / 选择,就能识别他: + +- 成名:听到"迁讷" → 立刻知道这是什么样的人 +- 林冲:被陷害后第一反应是"忍" → 立刻知道 +- 哈代苔丝:失贞后依然要"诚实" → 立刻知道 + +**检验**:你的主角有这样一个"判断瞬间"吗? + +(以上步骤均出自) + +## 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 性格太"模糊"(既 A 又 B 又 C) | 读者抓不住 | 3-5 个核心性格,且要有"主要矛盾" | +| 反派性格太"扁平" | 假 | 反派也要有"性格即命运" | +| 性格没碰撞只"遭遇" | 假 | 强调"碰撞"——是性格之间的化学反应 | +| 把"性格"等于"标签" | 假 | 性格要通过动作显现,不是形容词 | + +() + +## 适用边界 + +- **适合**:所有虚构叙事(小说、剧本、电影) +- **慎用**:群像小说(需要多对碰撞) +- **不适用**:纯意识流、纯抒情(它们靠情绪,不靠碰撞) + +() + +## 一句话总结 + +> **不要让你的主人公"倒霉",让他的"特定性格"遇到"另一个特定性格"——命运自己会来。** + +() + +## 跨 skill 链接 + +- 与 `bifeiyu-shakespeare` 同源:性格 + 现实的逻辑推演。(bifeiyu-shakespeare 归综合 skill theme-and-stance) +- 与 `bifeiyu-anti-norm` 关联:反常动作是"性格即命运"的爆发点。(同在本包,见 references/abnormal-moment.md) +- 与 `bifeiyu-base-temp` 配合:性格的"基础体温"是性格的色彩。(bifeiyu-base-temp 归综合 skill prose-craft) +- 与 `bifeiyu-mercy-ruth` 配合:作家要"心慈手狠"才能让性格碰撞产生必然命运——不能因心软去救人物。(bifeiyu-mercy-ruth 归综合 skill theme-and-stance) + +(;综合 skill 归属标注为本次合并所加) diff --git a/framework/catalog/dsh/skills/character-presentation/references/detail-mosaic.md b/framework/catalog/dsh/skills/character-presentation/references/detail-mosaic.md new file mode 100644 index 0000000..2c4a096 --- /dev/null +++ b/framework/catalog/dsh/skills/character-presentation/references/detail-mosaic.md @@ -0,0 +1,139 @@ +# 细节马赛克:用具体物装配人物 + +## 原文摘录 + +> Hairstyle: slicked-back. Facial features: winking black eyes, big round jaw. Speech patterns: +> tough talk in a New Jersey accent. Mannerisms: buffed nails. Habits: gun strapped to ankle. +> Tastes: scotch and water with a twist... Brand labels: Chivas Regal. Jewelry: thick pinky ring. +> +> — Roy Peter Clark, *Writing Tools* (Tool 54, 引用 Lawrence Wright《The Looming Tower》) + +这是 Clark 引用的标杆登场段:FBI 反恐主管 John O'Neill 完全由一组物质细节拼成,全程没有一个性格形容词。 + +## 方法规则 + +### 把 Tom Wolfe 的"身份细节"扩展成"细节马赛克" + +Clark 把 Tom Wolfe 的 **status details**(身份细节)概念**扩展**为**细节马赛克**:把人物当作**一组可枚举的细节类别**来搭建。 + +### 10+ 维度 + +- 发型 / 面部 / 口音 +- 姿态 / 习惯 / 口味 +- 品牌 / 首饰 / 服饰 / 鞋履 +- 步态 / 视线 / 与孩子 / 仆人的互动方式 + +### 核心规则 + +**精心选择 5-9 个具体到感官的细节,让读者自己合成"完整的人"。** + +判断标准:这一组细节是"反推"出人物性格(读者主动建构),还是"宣告"出人物性格(作者直接告知)? + +### 关键洞见 + +- **不是穷举——是"挑选"**。Clark 警告:把所有细节都写下来是糟糕的写作。**挑最揭示内在张力的 5-9 个**。 +- **替代抽象形容词**("勇敢"、"热情"、"冷酷")——这些是"失败的告诉"。 +- **每个细节都是 1 个"反推钩子"**——读者从"slicked-back 发型"反推"爱面子",从"踝部枪"反推"危险职业"。 +- **配合 Tool 27**——配合"不要用性格形容词"使用。(show-don't-tell 的原则本体归综合 skill show-and-omission,此处只取它落到人物细节上的操作。) + +这是**装配框架**:把人物当作有清单的待建物体来搭建。 + +## 案例全文 + +### 案例 1:Lawrence Wright《The Looming Tower》— John O'Neill 登场 + +- **问题**:写 FBI 反恐主管 O'Neill 登场,如何让读者 200 字内"看见"他? +- **方法论的使用**:Wright 用 9 个物质细节类别(发型 / 面容 / 口音 / 姿态 / 习惯 / 品味 / 品牌 / 首饰)搭建 O'Neill——slicked-back 发型,wink 黑眼睛,NJ 口音,磨光指甲,踝部枪,芝华士 + 柠檬,厚粉红戒指。 +- **结论**:**没有任何"勇敢""果断"等性格形容词**——读者从细节"反推"出"这是一个警觉、危险、有品味"的人。 +- **结果**:成为了"细节马赛克"的标杆案例;展示了"少形容词 + 多具体物"的力量。 + +### 案例 2:Christopher Scanlan 报道 Belva Kent 家门口的电灯开关 + +- **问题**:写谋杀案受害者家庭,如何"显示"悲伤而不直说? +- **方法论的使用**:Scanlan 在采访中,发现 Belva Kent 门口电灯开关上贴了一条胶带——"Deb never came home"。一条胶带 = 11 年的等待 = 全家的悲伤。 +- **结论**:**一个具体物件 > 一吨形容词**。Clark 的"狗的名字"工具的金案例:**好奇心(不是想象力)**发现了伟大细节。 +- **结果**:成为了 Poynter Institute 教学经典案例;证明"具体物件的揭示力"。 + +## 操作步骤 + +1. **列出 10 维度清单** + - 完成标准:从 10 维度(发型、面容、口音、姿态、习惯、口味、品牌、首饰、服饰、步态)中挑出 5-9 个。 + - 判停条件:不要 10 维度都写;Clark 警告穷举 = 糟糕写作。 +2. **每个细节问"反推什么"** + - 对每个细节,问"读者能反推出什么性格 / 阶层 / 心理?" + - 完成标准:每个细节对应 1 个具体的"反推结果"。 + - 判停条件:如果反推不出,换细节。 +3. **替换抽象形容词** + - 在人物段落中,把所有抽象性格形容词(勇敢、热情、冷酷、聪明等)替换为 1-2 个具体细节。 + - 完成标准:人物段落中,抽象性格形容词 ≤ 2 个,且有具体细节支撑。 +4. **(可选)Clark 检验:删去一个细节,看是否人物变轻** + - 检验"每个细节是否必要"。Clark 配套 Chekhov 之枪的反向——若删去后人物"变轻" = 必要;若删去后无感 = 删掉。 + +## 多书合并点:不宣告,让读者反推 + +"不宣告人物性格,让读者自己反推"是多本书里同一个方法点,落地层面不同,各家视角都保留: + +- **细节马赛克**:词句层面的操作——把所有抽象性格形容词(勇敢、热情、冷酷、聪明)替换为 1-2 个具体细节;抽象形容词是"失败的告诉"。 +- **关系网**:场景层面的操作——不写"他是个 X 的人",写他和另一个人的关系;人物怎么说话 > 人物自己说"我是 X 的人"。 + + > ❌ 错误写法:"王熙凤是个精明能干的女人。" + > ✅ 正确写法:"王熙凤笑道:'你们请我来做什么?有什么好东西孝敬我,就快供上来,我还有事呢。'" + +- **性格即命运**:设计层面的纪律——把"性格"等于"标签"是常见错误,"性格要通过动作显现,不是形容词"。 + +分工:Clark 管段落里形容词的替换;毕飞宇管用关系、对话、动作替换自我介绍;"性格即命运"的"3-5 个性格词"是给作者定位用的设计工具(见 references/character-collision.md),不是写进正文的标签。(本节为合并整合说明。) + +## 失败模式(作者警告) + +- **"完整清单"陷阱**:失败模式是写"完整 10 维度"——发型 + 面部 + 口音 + 姿态 + 习惯 + 口味 + 品牌 + 首饰 + 服饰 + 步态全部。信号:人物登场段像表格。机制:作者误把"装配框架"当"穷举清单"。预警:超过 9 个细节,停下来精选。 +- **"宣告式形容词"反扑**:失败模式是用了 5 个具体细节,但还在最后说"他是个勇敢的人"。信号:"形容词 + 细节"组合。机制:作者"不放心"读者反推,想再补一刀。预警:Clark 的核心——删掉所有抽象形容词,只留具体细节。 +- **"细节无张力"**:失败模式是选了 9 个细节但全是"中性"的——白衬衫、棕发、白鞋。信号:读者读完不知道"这是谁"。机制:作者没挑"最揭示内在张力"的细节,挑了"最容易观察"的。预警:Clark 检验——"删去一个细节,看人物是否变轻"——若变轻,必要;若不变,换掉。 + +## 边界:不要在以下情况使用 + +- **心理独白为主的小说**——如意识流 / 内心独白,人物通过"想法"而非"细节"显示。 +- **极简主义文学**——故意少细节(海明威冰山理论),过度装配反而破坏。 +- **抽象哲学小说**——人物是"思想载体",不需要物质细节。 +- **儿童文学的某些情况**——儿童角色可能不需要 status details。 + +## 中文适配 + +Clark 的 10 维度基于英语社会,中文写作者需要**本地化调整**: + +- **发型**:中文小说需要关注"发型 + 头面 + 头饰"(如头簪、刘海、长辫等) +- **服饰**:中文需要"上衣 / 下装 / 鞋履"区分,以及"面料"(丝绸 / 棉布 / 麻) +- **首饰**:中文有"玉 / 银 / 翡翠 / 木"等独特材质 +- **品牌**:中文社会"品牌"概念在 1980 年代后才普及;传统小说用"家当"或"身份标志"(官服 / 长衫 / 中山装) +- **行为细节**:中文"用餐 / 茶 / 酒 / 待客"是阶层显示的关键 + +中文写作补充的本地维度一句话版:**家当与身份标志、服饰面料、玉石材质、茶酒待客**。(中文适配) + +**时代局限**:Clark 写于 2006 年(英文版),网文 / 直播 / 短视频时代的"人物设定"需要新维度(如"人设标签 / 表情包 / 流行语")。(中文适配) + +### 中文落地说明 + +方法本身可直接搬到中文:反推钩子靠的是读者的社会认知,中文读者对"家当、官服、面料、待客方式"的反推习惯比对品牌更熟练。选细节时优先选中文读者能立刻反推的文化符号(什么品级的官服、什么面料、怎么斟茶让座),而不是堆没翻译的外国品牌。网文主角人设可以借用"人设标签"新维度,但落地时仍要走反推检验:标签本身是宣告,标签背后的具体行为细节才是马赛克。 + +## 激活场景与语言信号 + +用户会在什么情境下需要这个方法: + +1. 写完人物登场段后觉得"读起来像'性格形容词清单'"——用了勇敢、热情、冷酷、聪明等抽象词。 +2. 网文主角第一章登场,但读者记不住他长什么样、什么气质。 +3. 写次要人物只有 200 字登场空间,不知道怎么让读者记住。 +4. 写群像 / 阶层 / 权力场景,需要快速"定位"每个人的社会位置。 +5. 写人物对话但人物之间没有差异——读完分不清谁在说话。 + +语言信号:"细节马赛克" / "mosaic of detail";"人物立体" / "人物脸谱化";"如何显示人物" / "show not tell";"性格形容词" / "形容词清单";"status details" / "Tom Wolfe";"网文主角人设" / "登场段";"次要人物怎么写";"群像怎么写" / "阶层怎么显示"。 + +## 与邻近方法的区分 + +- 与 **"show, don't tell"(Tool 27)** 的区别:那个是更大的原则(用动作和细节显示而非直说),这个是具体的"细节装配"操作。show-don't-tell 是 what,细节马赛克是 how。(show-don't-tell 本体归综合 skill show-and-omission。) +- 与 `archetype-toolkit` 的区别:那个是"叙事母题层"(原型),这个是"叙事内容层"(具体物)。原型是骨架,细节是肉。(archetype-toolkit 归综合 skill character-design。) +- 与 `dialogue-as-action` 的区别:那个是"用对话显示人物"(声音语言),这个是"用物品显示人物"(物品语言)。前者是动词,后者是名词。(dialogue-as-action 归综合 skill dialogue-craft。) +- 与 `voice-equalizer` 的区别:那个是"作者声音的杠杆"(宏观),这个是"人物声音的细节"(微观)。前者是叙述者,后者是被叙述者。(voice-equalizer 归综合 skill prose-craft。) +- 组合关系:`dialogue-as-action`(物品语言 + 声音语言),`voice-equalizer`(细节的语言风格统一)——细节马赛克与对话动作配合,物品语言加声音语言合成完整的人物呈现;细节的语言风格统一则与声音均衡器配合完成。 + +## 张力标注:外在细节 vs 内在可见 + +细节马赛克用外在物质细节解决"人物显示";福斯特从另一面提醒:外在细节丰富 ≠ 人物被写透,误把"细节多"当"作者了然"是"小楼误为大廈"的失败模式。两者分工不冲突:细节马赛克管登场层和读者的第一层反推,隐秘生活可见性管深度层。见 references/visible-private-life.md"张力标注"节。(本节为合并整合说明。) diff --git a/framework/catalog/dsh/skills/character-presentation/references/presentation-checklist.md b/framework/catalog/dsh/skills/character-presentation/references/presentation-checklist.md new file mode 100644 index 0000000..035f879 --- /dev/null +++ b/framework/catalog/dsh/skills/character-presentation/references/presentation-checklist.md @@ -0,0 +1,124 @@ +# 人物呈现自查台账 + +用法:设计或修改一个人物时从 1 到 7 顺着填。每节有"过关线",达标进下一节,不达标按标注回退。判断标准全部来自本包 references/ 各文件,这里只是填写骨架;方法细节、案例与引文见各节标注的落点。 + +--- + +## 1. 登场细节装配(→ references/detail-mosaic.md) + +人物:____ 登场可用篇幅:____ 字 + +候选细节(先从 10 维度 + 中文本地维度列 9-12 个,再精选到 5-9 个;中文本地维度:家当与身份标志、服饰面料、玉石材质、茶酒待客): + +| # | 细节 | 所属维度 | 读者反推出什么(性格/阶层/心理) | 留/删 | +|---|------|---------|------------------------------|------| +| 1 | | | | | +| 2 | | | | | +| 3 | | | | | +| 4 | | | | | +| 5 | | | | | +| 6 | | | | | +| 7 | | | | | +| 8 | | | | | +| 9 | | | | | + +段落里的抽象性格形容词清单(勇敢、冷酷、精明能干……):____,每个换成 1-2 个具体细节:____ + +Clark 检验:逐个删一遍,删掉后人物变轻的留下,无感的删掉。 + +过关线:最终 5-9 个细节;每个都反推得出东西;抽象性格形容词 ≤ 2 个且有细节支撑;登场段不像表格。超过 9 个细节 = 回退精选。反推不出的细节 = 换掉。 + +## 2. 内在可见自查(→ references/visible-private-life.md) + +- 人物历史的一面(可观察行为)够吗:□ 够 □ 不够 +- 人物虚构的一面写了哪样(感情 / 幻想 / 喜悦悲伤 / 出于礼貌或羞愧没说出口的话):____ +- 我对这个人物了如指掌吗(说不出口的心里话、独处时的样子,我答得上来吗):□ 答得上 □ 答不上 → 先补人物功课 +- 指出至少一段让读者看到隐秘生活的段落:第____章第____段 + +过关线:能指出一段"现实中看不到的清晰"。只见外部细节堆叠 = 小楼误为大廈,回退补虚构的一面。可见性若走向预言式"我和所有人"的神异,转 novel-diagnosis 的 fantasy-prophecy-twin 测试。 + +## 3. 关系网台账(→ references/relationship-web.md) + +人物:____ + +| 关系 | 对方 | 关系类型 | 显示人物什么侧面 | 推动什么情节 | +|-----|------|---------|----------------|------------| +| 1 | | | | | +| 2 | | | | | +| 3 | | | | | +| 4 | | | | | +| 5 | | | | | + +三项检查: + +- 至少列得出 3 重?□ 是 □ 否 → 人物不立体,先设计关系再动笔 +- 同一人物在每重关系里反应不同(对比)?□ 是 □ 都是同一种反应 = 关系没设计 +- 每重关系都推动情节?□ 是 □ 有装饰关系 → 删或改 + +隐藏关系:有没有一条"读者知道但人物不知道"的关系?□ 有:____ □ 没有 → 加一条,并提前留"飞白"暗示。 + +群像互换检验(群像才填):把两个主要人物的关系网对调还能用吗?□ 不能(到位) □ 能(没设计好) + +## 4. 碰撞设计(→ references/character-collision.md) + +主角性格词(3-5 个):____;删掉一个词人物还像吗?□ 不像(词关键) □ 还像(删) +对手性格词(3-5 个):____ + +必然碰撞公式:主角的 [____] 遇上对手的 [____] → 必然 [____] + +巧合逐条翻译: + +| 原稿里的巧合 | 翻译成性格碰撞 | 删掉巧合后凭性格还会遇到吗 | +|------------|--------------|------------------------| +| | | □ 会(换得好)□ 不会(还有巧合没换) | +| | | □ 会 □ 不会 | + +性格链:性格 A 遇性格 X → 事件 1 → 暴露新侧面 → 新侧面遇性格 Y → 事件 2 → …… → 爆发 + +判断瞬间:读者看到主角做哪一个动作 / 选择就能认出他:____(写不出 = 回第 3 步) + +过关线:反派也有性格词(没有 = 工具人,碰撞立不住)。 + +## 5. 反常设计(→ references/abnormal-moment.md) + +人物按身份该有的常态: + +1. ____ +2. ____ +3. ____ + +反常清单(短篇 1-2 个,长篇排递进链 3-5 个,每个标驱动源): + +| # | 反常瞬间 | 驱动源(人物选择的反常→揭示性格 / 情境的反常→推动情节) | 落实的具体动作或对话(禁形容词) | 改变了人物/情节/关系的什么 | +|---|---------|--------------------------------------------------|------------------------------|--------------------------| +| 1 | | | | | +| 2 | | | | | +| 3 | | | | | + +事后解释检验(不写解释,只验读者反应预期):□ 原来如此(成) □ 莫名其妙(没设计好) □ 早猜到了(太露) + +过关线:每个反常前都有常态铺垫;每个反常都有后果;反常是性格驱动不是作者安排。 + +## 6. 声音检查(过程发现 → references/voice-discovery-process.md;技术修法 → dialogue-craft) + +1. 遮住名字读对话,分得出谁在说话吗?□ 分得出 □ 分不出 → 交 `dialogue-craft`(句长/口头禅/同一声音诊断) +2. 大声朗读,听着自然吗?□ 自然 □ 别扭 +3. 拿不准人物会不会说这句话?□ 拿得准 □ 拿不准 = 还不够了解人物 → 补人物小传 / 对话练习,或继续写、与人物相处足够久(过程发现) +4. 长篇里人物开始说计划外的话:先记录再取舍,不硬拉回大纲。□ +5. 通篇对话的长篇才查:每段对话是否同时承担人物发言 + 叙述推进?有没有节奏感和旋律感(对话成为叙述、叙述成为对话)?□ → 技术侧见 `dialogue-craft` + +老农民检验:身份最低的人物开口,腔调对吗?(老农民不能说大学教授的话)→ 不合格则交 `dialogue-craft` + +## 7. 总判断标准 + +| 标准 | 过关信号 | 出处 | +|------|---------|------| +| 真实 | 作者对人物了如指掌,而不是人物像现实某人 | references/visible-private-life.md | +| 细节必要 | 删掉一个,人物变轻 | references/detail-mosaic.md | +| 性格词准确 | 删一词不像,加一词模糊 | references/character-collision.md | +| 碰撞成立 | 删掉巧合,凭性格照样遇到 | references/character-collision.md | +| 关系立体 | 至少三重关系,反应各不同,都推动情节 | references/relationship-web.md | +| 反常有戏 | 常态铺垫 + 具体动作 + 有后果 + 不解释 | references/abnormal-moment.md | +| 声音区分 | 遮住名字也分得出谁在说话 | dialogue-craft/references/character-voice.md | + +全部过关 = 人物能被读者自己看见。任何一项不过,回对应小节。 diff --git a/framework/catalog/dsh/skills/character-presentation/references/relationship-web.md b/framework/catalog/dsh/skills/character-presentation/references/relationship-web.md new file mode 100644 index 0000000..6f365e3 --- /dev/null +++ b/framework/catalog/dsh/skills/character-presentation/references/relationship-web.md @@ -0,0 +1,228 @@ +# 关系即人物:通过关系网显性格 + +来源:(毕飞宇《小说课》第 6 讲,案例取自《红楼梦》王熙凤和秦可卿 / 整本书) + +> 「人物性格不在人物的自我描述里,在人物与人物的关系里。」 + +## 原文摘录 + +《红楼梦》里王熙凤和秦可卿的关系: + +- 字面:闺蜜 +- 字面下:和王熙凤和贾蓉的暧昧有关 +- 反逻辑:秦可卿死后,王熙凤和贾蓉都"消失"了 + +**王熙凤的全部复杂性**——通过她和**5 个人**的关系显出来: + +``` +王熙凤 - 贾瑞:被调戏 → 毒设相思局 → 杀 +王熙凤 - 秦可卿:闺蜜 → 但有隐藏关系 +王熙凤 - 贾蓉:暧昧 → 隐藏 +王熙凤 - 尤氏:嫂子 → 但互相嘲讽 +王熙凤 - 贾宝玉:嬉笑怒骂 → 玩伴 +``` + +**每一个关系都是王熙凤的一个侧面**。**5 个关系 = 5 个王熙凤**。 + +() + +## 方法规则 + +**人物不在"自我介绍"里,在"他和别人的关系"里。** + +> "他是谁?"这个问题,**不能问他自己,要问他的"关系网"**。 + +**核心原则**: + +1. **不写"他是个 X 的人"——写他和另一个人的关系** +2. **每个人的性格在他和不同人的关系中显示不同侧面** +3. **关系越复杂,人物越立体** +4. **隐藏关系 = 戏的来源** + +() + +## 案例全文 + +### 案例 1:曹雪芹 王熙凤的 5 重关系 + +- 闺蜜关系(秦可卿) +- 暧昧关系(贾蓉) +- 嫂子关系(尤氏) +- 玩伴关系(贾宝玉) +- 上下关系(贾瑞) + +**5 个关系 = 5 个王熙凤 = 立体人物**。 + +### 案例 2:施耐庵 林冲的 5 重关系 + +- 夫妻(林娘子) +- 同事 / 技术关系(高俅) +- 兄弟(鲁智深) +- 仇人(高衙内、陆谦) +- 同志(柴进) + +**5 个关系 = 5 个林冲 = 立体人物**。 + +### 案例 3:海明威《杀手》5 个男人 + +- 阿尔 + 马克斯(同事杀手) +- 阿尔 / 马克斯 + 乔治(压迫者 vs 服务员) +- 阿尔 / 马克斯 + 尼克(威胁者 vs 旁观者) +- 阿尔 / 马克斯 + 萨姆(威胁者 vs 后厨) + +**5 个关系网 = 5 个性格的碰撞 = 整个故事的势**。 + +### 案例 4:哈代《苔丝》3 重关系 + +- 苔丝 + 亚雷(阶级关系 / 失贞) +- 苔丝 + 克莱尔(爱情 / 真相) +- 苔丝 + 家庭(生存压力) + +**3 个关系 = 3 个苔丝 = 立体悲剧**。 + +(以上四案例均出自) + +## 操作步骤 + +### 步骤 1:列"人物关系网" + +```yaml +人物:[主角] +关系 1:[关系类型] - [对方人物] - [显示什么性格] +关系 2:[关系类型] - [对方人物] - [显示什么性格] +关系 3:[关系类型] - [对方人物] - [显示什么性格] +``` + +**检验**: + +- 列得出 3 个关系吗?→ 人物可写 +- 列不出 → 人物不立体,需要先设计关系 + +### 步骤 2:关系要"对比" + +**不同关系显示不同侧面**: + +```yaml +林冲 - 林娘子:温柔(家) +林冲 - 高俅:忍(职场) +林冲 - 鲁智深:义(兄弟) +林冲 - 陆谦:仇(仇人) +``` + +**检验**:你的主角在不同关系中是不是"不同的人"? + +- 都是同一种反应 → 关系没设计 +- 不同反应 → 关系到位 + +### 步骤 3:关系要"推动" + +**关系要推动情节**——不只是"展示": + +```yaml +林冲 - 高俅(仇)→ 推动:被陷害 +林冲 - 鲁智深(义)→ 推动:救他 +林冲 - 柴进(同志)→ 推动:上梁山 +``` + +**检验**: + +- 列出的关系都推动了情节?→ 关系到位 +- 有些关系只是"装饰"?→ 删或改 + +### 步骤 4:用"关系"代替"自我介绍" + +**❌ 错误写法**: + +> "王熙凤是个精明能干的女人。" + +**✅ 正确写法**: + +> "王熙凤笑道:'你们请我来做什么?有什么好东西孝敬我,就快供上来,我还有事呢。'" + +**人物怎么说话 > 人物自己说"我是 X 的人"**。 + +**检验**: + +- 你的主角有没有"自我介绍"?→ ❌ 删 +- 用对话 / 动作 / 关系显示 → ✅ 留 + +(本步骤与 的"替换抽象形容词"、 的"性格不是标签"是同一方法点,两本书三个源单元合并见 references/detail-mosaic.md"多书合并点"节,此处原文全量保留。) + +### 步骤 5:设计"隐藏关系" + +**戏的来源 = 隐藏关系**: + +```yaml +表面:闺蜜 +实际:和王熙凤和贾蓉的暧昧相关 +→ 戏:秦可卿死后的反逻辑 +``` + +**检验**:你的小说里有没有一个"读者知道但人物不知道"的隐藏关系? + +- 有 → 戏足 +- 没有 → 加一个 + +### 步骤 6:群像的"关系区分" + +每个主要人物的关系网要**独特**: + +``` +林冲:家-职场-江湖 +鲁智深:佛-江湖-兄弟 +武松:兄-官-江湖 +``` + +**3 个人的关系网几乎不重叠** = 群像立体。 + +**检验**:把两个主要人物的关系网互换——还能用吗? + +- 能 → 没设计好 +- 不能 → 设计到位 + +(以上步骤均出自) + +## 触发场景 + +1. 你的人物"自我描述太多" → 改用关系显性格 +2. 你的人物"平面" → 加多重关系 +3. 你想"藏秘密" → 隐藏关系是最好方式 +4. 你想"立体人物" → 给他至少 3 重关系 +5. 你的群像"区分不开" → 每个人物的关系网要独特 + +() + +## 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 自我描述太多 | 假 | 用对话 / 动作 / 关系显示 | +| 关系太单一 | 平面 | 至少 3 重关系 | +| 关系没推动 | 装饰 | 每个关系都要推动情节 | +| 关系太相似 | 群像不分 | 每个人物关系网独特 | +| 隐藏关系没暗示 | 突兀 | 隐藏关系要有"飞白" | + +(;"飞白"的展开归综合 skill show-and-omission 的 bifeiyu-anti-logic,此处只留原话。) + +## 适用边界 + +- **适合**:所有虚构叙事 +- **特别适合**长篇 / 多线叙事 +- **慎用**:独角戏(人物少到 1-2 个,关系网要"纵向深挖") + +() + +## 一句话总结 + +> **人物不在"我是 X 的人"里,在"我和 Y 的关系"里。** + +() + +## 跨 skill 链接 + +- 与 `bifeiyu-character-fate` 同源:关系 = 性格碰撞的载体。(同在本包,见 references/character-collision.md) +- 与 `bifeiyu-anti-logic` 配合:隐藏关系 = 反逻辑的来源。(bifeiyu-anti-logic 归综合 skill show-and-omission) +- 与 `bifeiyu-perspective` 配合:多视角看同一关系 = 立体人物。(bifeiyu-perspective 归综合 skill narration-pov) +- 与 `bifeiyu-system` 配合:短篇人物少,关系要"集中";长篇人物多,关系要"网状"。(bifeiyu-system 归综合 skill story-structure) + +(;综合 skill 归属标注为本次合并所加) diff --git a/framework/catalog/dsh/skills/character-presentation/references/visible-private-life.md b/framework/catalog/dsh/skills/character-presentation/references/visible-private-life.md new file mode 100644 index 0000000..4d3d356 --- /dev/null +++ b/framework/catalog/dsh/skills/character-presentation/references/visible-private-life.md @@ -0,0 +1,143 @@ +# 隐秘生活可见性:人物的"真实"是作者对其了如指掌 + +## 原文摘录 + +> "一旦剥离人际往来的社会属性, 单纯审视其本身, 事情就会变得好像幽魂缠身一般。我们无法彼此理解, 除非接受那种约定俗成而又粗略含糊的方式 …… 我们所谓'完美的认知'不过是幻象。小说中则不同, 我们不但可以彻底了解他人, 还可以 …… 找到各自生活的补偿。就这一点而言, 小说比历史更加真实, 因为它超越了对证据的需索。" + +> "小说能够抚慰人心, 哪怕主角是恶人也不例外, 原因就在这里: 它们暗示了一种更易于理解, 甚而更加有序、更加可控的人类的存在, 它们为我们打造了有关洞察力与力量的幻象。" + +> — E. M. 福斯特, 《小说面面观》第三讲 人物 + +## 方法规则 + +### 小说与现实人的本体论差异 + +现实人彼此的内心"不可见"(我们只能通过外在行为推测,"我们永远不可能完全了解其他人");小说人物"隐秘的内在人生是可见的",是叙述者与创造者合二为一的世界。() + +### 核心操作五条 + +1. **承认"我们无法彼此完全理解"**——现实人之间,即使最亲密的关系,也存在"我们永远不可能完全了解其他人"的本体论限制。我们的认知是"约定俗成而又粗略含糊的","完美的认知不过是幻象"。 +2. **小说 / 虚构给予"可见性"特权**——小说人物"隐秘的内在人生是可见的",因为作者对人物"了如指掌"。**判断"真实"不是"像我们",而是"作者对其了如指掌"**。 +3. **小说比历史更真实**——不是因为虚构,是因为"它超越了对证据的需索"。在小说里,我们可以"彻底了解他人",而在现实里,我们只能"约定俗成地"了解。 +4. **"可见性"是小说抚慰人心的原因**——小说"暗示了一种更易于理解,甚而更加有序、更加可控的人类的存在","为我们打造了有关洞察力与力量的幻象"。这是虚构 / 想象的合法理由,不是缺陷。 +5. **阿兰的"两面性"作为延伸**——人物 = 历史的一面(可观察行为)+ 虚构 / 浪漫的一面(纯粹的感情、幻想、喜悦、悲伤,还有出于礼貌或羞愧而没能启齿的心里话)。优秀小说必须深入"那一面"——"小说中没有天意,在这里,一切都能归结于人性"。 + +### 判断标准 + +判断"真实"不是"像我们",而是"作者对其了如指掌"。当我们说"X 写的人物真实",我们不是说"X 的人物像我",我们是说"X 的人物让我看到了一种现实给不了的可见性"。 + +**关键认识**:小说人物的"可见性"是**对真实人的渴望**的补偿,不是对真实人的**模仿**。() + +## 案例全文 + +### 案例 1:摩尔·弗兰德斯——圆形的极端(孤树型) + +- **问题**:摩尔·弗兰德斯"方方面面"都"合乎日常生活",但"我们还是无法在现实中找到这样一个完整的人物" +- **方法论的使用**:福斯特诊断——这是因为摩尔"在小说里"是**作者了然于心的存在**,而现实中的人不可能"被作者了然" +- **结论**:摩尔比真实人更"真实"(在福斯特的意义上),因为她的"隐秘生活可见" +- **结果**:借此福斯特给出"真实"的反直觉定义——"作者对其了如指掌"才是真实 + +### 案例 2:维多利亚女王——真实人物的"消解" + +- **问题**:如果维多利亚女王一模一样地进了小说,她就不再是维多利亚女王了 +- **方法论的使用**:福斯特诊断——"如果一个小说角色和维多利亚女王一模一样——不是多多少少有些像,而是一模一样——那么,她就是维多利亚女王本人了,这部小说,以及与这个角色相关的一切就变成了人物传记"。小说与传记 / 历史不同 +- **结论**:小说人物不模仿现实,小说人物"提供可见性" +- **结果**:借此福斯特划出"小说" vs "传记" vs "历史"的本体论边界 + +### 案例 3:海蒂 vs 米嘉(《卡拉马佐夫兄弟》) + +- **问题**:海蒂和米嘉都"忏悔自己的罪行",但为什么米嘉更深? +- **方法论的使用**:福斯特诊断——海蒂"只靠她自己便已足够成立",米嘉"单靠他自身是不足以成立的"。米嘉是"预言之中的幻象,也是小说家的造物",他代表了"某种半切身的感觉,就像沉入一个半透明的球体里,眼看着我们的经历远远地漂浮在我们头顶的球体表面上" +- **结论**:米嘉的"隐秘生活可见"是另一种——他代表了我们所有人的可能,是"圆形 + 预言"的极限 +- **结果**:借此福斯特说明,小说可见性有不同的"层次"——人物可见 vs 人物代表的人性可见 + +## 可见性的层次(判断标准延伸) + +- **基础层:人物可见**——这个人物被写透了(摩尔·弗兰德斯):人物真实但限于自己。 +- **更高层:人物代表的人性可见**——人物代表更广的可能性(米嘉):人物代表了我们所有人的可能。 + +## 操作步骤 + +1. **承认"我们无法彼此完全理解"** + - 完成标准:明确说出"现实中的人彼此不可见,我们只能'约定俗成'地了解" +2. **诊断虚构 / 想象的可见性** + - 完成标准:评估"X 是否提供了一种现实给不了但人渴望的可见性" + - 至少 1 个具体征兆:"X 在 Y 段落中让我看到了人物的内在,我在现实中看不到这种清晰" +3. **判断可见性的"层次"** + - 完成标准:区分"人物可见"(摩尔·弗兰德斯)vs"人物代表的人性可见"(米嘉) + - 前者:人物真实但限于自己;后者:人物代表更广的可能性 +4. **评估可见性的边界** + - 完成标准:明确说"X 提供的可见性是否会变成'神异'(如预言式的'我和所有人')",如果是,走 `fantasy-prophecy-twin` 测试(归综合 skill novel-diagnosis) + - 不要混用:可见性(作者了然)vs 神异(作者召唤) +5. **给出诊断 / 修改建议** + - 完成标准:至少 1 条具体修改(如"在 X 段加入人物的内在独白,让读者看到他们的隐秘生活"或"承认'我们其实看不见对方',不要假装小说可以替代心理学") + - 不要空话(如"让人物更立体")——给可操作修改 + +## 失败模式(作者警告) + +- **"模仿真实人"的错误**——把维多利亚女王硬塞进小说,真实人物消解虚构(ce04) +- **"小楼"误为大廈**——误把"细节丰富"当"作者了然"(c04:四本"小楼"小说 vs 托尔斯泰"大廈") +- **以可见性为借口逃避证据**——把"作者了然"当成"作者全能",失去对真实的尊重 +- **预设作者 / 读者的特权立场**——假设"我能'看到'你",是侵犯性的 + +## 作者的盲点 / 时代局限 + +- **1927 年的视角**——没看到 60 年代后的"不可靠叙述者"(Unreliable Narrator,纳博科夫《洛丽塔》、品钦)对"作者了然"的颠覆 +- **对"作者了然"过于乐观**——现代叙事学认为"作者"也是建构的,不可靠叙述者本身就说明"作者不一定比读者更了然" +- **西方文学中心的视角**——中国评书传统中"说书人可见"是合法手法,西方小说中不一定;福斯特未充分讨论跨文化差异 + +## 中文适配 + +- 福斯特中译本可直接用于中文小说评估;"作者对其了如指掌"这个标准不依赖语言,中文写作同样适用。 +- **说书人可见**(中文适配):福斯特的"可见性"以 19 世纪西方现实主义全知视角为背景;中国评书与话本传统里,说书人直接点评人物内心("看官听说")也是合法的可见性实现方式。用"可见性"评中文小说时,不必要求可见性一律通过展示实现,说书人式的全知介入同样算"作者了然"的供给,但要检查介入是否给了读者现实给不了的洞察,而不是只给了说教。 +- 中文写作落地:给主要人物补"虚构的一面"时,中文小说可用的手段包括内在独白、梦境、未说出口的话("欲言又止")、独处时的失态;判断标准不变——读者是否看到了现实中看不到的清晰。 + +## 激活场景与语言信号 + +用户会在什么情境下需要这个方法: + +1. **评估小说 / 电影 / 游戏 / 电视剧的"代入感"**——诊断"代入感"是来自人物真实(可见性)还是情节刺激 +2. **评估"品牌人格"**——品牌是否"提供了一种可见性"——让用户感到"被理解" +3. **评估"虚构"在产品 / 服务 / 制度中的作用**——为什么有些虚构(如品牌故事、用户画像)让人感到真实? +4. **评估一个产品 / 服务是否"触及人渴望的洞察力"**——不只是"功能满足",而是"洞察提供" +5. **设计 / 写作时**——检查"我的人物 / 角色是否对'隐秘生活'有可见性的提供" +6. **教学 / 讲课时**——解释"为什么小说比历史更真实"给学生 + +(本包主用途是第 1、5、6 条:评估与写作中的人物可见性;2-4 条为源单元原有的延伸应用,照录保留。) + +语言信号: + +- "X 让我看到了我自己看不到的" +- "X 比现实更真实" +- "X 的人物很立体 / 很丰满" +- "X 给了我洞察" +- "X 让我感到被理解" +- "X 让我知道了我不知道的我" +- "X 写的人 / 设计的角色 / 做的产品,让我觉得'对,就是这样'" +- "X 解释了我说不清楚的东西" +- "X 让我有了'啊哈'的瞬间" + +## 容易混淆的邻近概念 + +- **vs 代入感(Immersion)**——代入感是"我感到我在那里",可见性是"我能看到人物的内在";前者是空间 / 感官,后者是认知 / 洞察 +- **vs 心理现实主义(Psychological Realism)**——心理现实主义是文学流派,可见性是小说 / 虚构的本体论特征 +- **vs 神入(Theory of Mind)**——神入是心理学 / AI 概念,可见性是文学 / 哲学概念 + +## 边界:不要在以下情况使用 + +- **真实人之间的理解**——这是道德和心理学问题,不是文学方法论;"你应该理解我"不是这个方法能解决的 +- **纯信息 / 无人物的产物**——如新闻、菜谱,不需要"人物可见性" +- **科学论文 / 技术文档**——透明性优先,可见性反而是缺陷 +- **法律 / 合同**——文本优先,不要"让我看到你的内在" + +## 与邻近方法的区分 + +- 与 `flat-vs-round-character` 的区别:可见性是**本体论**(作者了然),扁 / 圆是**形式层**(一句话测试)。(flat-vs-round-character 归综合 skill character-design,圆形人物的"出人意料"建立在可见性之上。) +- 与 `fantasy-prophecy-twin` 的区别:可见性是**对真实人的补偿**,幻想 / 预言是**对真实人的超越**。(fantasy-prophecy-twin 归综合 skill novel-diagnosis。) +- 与"同理心(Empathy)"的区别:同理心是"我能理解你",可见性是"我能'看到'你的内在";前者是姿态,后者是特权。 + +(;综合 skill 归属标注为本次合并所加) + +## 张力标注:外在细节堆得多 ≠ 人物被写透 + +细节马赛克(→ references/detail-mosaic.md)用外在物质细节装配人物;福斯特警告的"小楼误为大廈"正是把"细节丰富"误当"作者了然"。两者分工不冲突:细节马赛克管登场层和读者的第一层反推;可见性管深度层——作者了然的内容包括细节列不出的虚构一面(感情、幻想、没说出口的话)。外在细节挑得准,加上内在可见,人物才真正立体。(本节为合并整合说明。) diff --git a/framework/catalog/dsh/skills/character-presentation/references/voice-discovery-process.md b/framework/catalog/dsh/skills/character-presentation/references/voice-discovery-process.md new file mode 100644 index 0000000..46562b1 --- /dev/null +++ b/framework/catalog/dsh/skills/character-presentation/references/voice-discovery-process.md @@ -0,0 +1,67 @@ +# 人物声音发现法:从控制到记录 + +> 说话方式的技术 owner 是 `dialogue-craft` 的 [character-voice.md](../../dialogue-craft/references/character-voice.md)(句长、口头禅、区分诊断)。 +> 本文件只保留**呈现侧**的过程发现:写作者何时从发号施令转为记录人物自己的声音。 + +来源:(余华,《我能否相信自己》(1998) / 演讲 (2014)) + +## 原文摘录 + +> "我写着写着突然发现人物有他们自己的声音, 这是令我惊喜的发现, 而且是在写作过程中发现的。在此之前我不认为人物有自己的声音, 我粗暴地认为人物都是作者意图的符号, 当我发现人物自己的声音以后, 我就不再是一个发号施令的叙述者, 我成为了一个感同身受的记录者, 这样的写作十分美好, 因为我时常能够听到人物自身的发言, 他们自己说出来的话比我要让他们说的更加确切和美妙。" +> +> — 余华, 《我能否相信自己》 + +## 方法规则 + +### 写作者与人物的关系有两个阶段 + +1. **控制阶段**:写作者认为人物是"作者意图的符号",发号施令地让人物说什么、做什么。此时人物僵硬,像传声筒,所有人物一个腔调。 +2. **记录阶段**:写着写着,人物突然有了自己的声音——他们会说写作者没想到的话,会做写作者没计划的事。此时写作者从"发号施令的叙述者"转变为"感同身受的记录者",尊重并记录人物自己的声音。 + +这个转变**发生在写作过程中**,不是预先设计的。通常需要与人物相处足够久(长篇写作中自然发生),人物才会自发产生声音。 + +### 与 dialogue-craft 的分工 + +- **本文件**:过程发现、传声筒诊断、事前设计 vs 过程发现的张力标注。 +- **`dialogue-craft/character-voice.md`**:什么人说什么话、句长/口头禅/遮住名字测试、对话双重功能的技术修法。 + +## 案例全文 + +### 案例 1:余华《在细雨中呼喊》——首次发现人物声音 + +- **问题**:余华早期(八十年代)认为人物是作者意图的符号,粗暴地控制人物。 +- **方法论的使用**:写《在细雨中呼喊》时,写着写着突然发现人物开始出现自己的声音。余华"有些惊奇",但他选择尊重这些声音,而不是强行拉回自己的计划。 +- **结论**:"我尊重他们的声音,结果证明我做对了。" +- **结果**:这是余华从先锋文学转向平易近人叙述的关键转折。 + +### 案例 2:余华《活着》——跨越更高门槛 + +- **问题**:如何写一个没文化的老农民讲述自己的故事? +- **方法论的使用**:《活着》以福贵(老农民)的第一人称讲述,余华在写作过程中与福贵相处足够久,福贵的声音自然产生——一个没文化但经历了一切的老老人的语言。余华不再控制,而是记录。 +- **结论**:"一个没有什么文化的老农民讲述自己的故事,这个写作过程让我跨过了更高的门槛。" +- **结果**:《活着》成为余华最著名的作品,福贵的声音成为其标志性特征。 + +### 案例 3:余华《许三观卖血记》——通篇对话的极致 + +- **问题**:如何写一部通篇用对话完成的长篇小说? +- **方法论的使用**:余华年轻时读乔伊斯《一个青年艺术家的画像》,就有写通篇对话长篇的愿望。写《许三观卖血记》时,开头恰好由对话组成,"机会来了"。他意识到通篇对话的困难:对话有双重功能(人物发言 + 叙述推进),必须有叙述的节奏感和旋律感。他从越剧唱词和台词的关系中得到启发——台词往唱词靠,唱词往台词靠,观众不会觉得别扭。 +- **结论**:"写对话的时候一定要有叙述中的节奏感和旋律感,如何让对话部分和叙述部分融为一体,简单地说如何让对话成为叙述,又让叙述成为对话。" +- **结果**:《许三观卖血记》成为通篇对话长篇的经典,余华"对于写对话不再担心了,想写就写,不想写可以不写"。 + +## 操作步骤 + +1. **评估当前人物状态**:人物是否有自己的语言习惯?不同人物是否可区分?完成标准:明确问题所在。 +2. **放弃控制,进入记录状态**:改为"如果这个人物在这里,他会说什么?"完成标准:写作时倾听而非预设台词。 +3. **与人物相处足够久**:长篇中自然产生;短篇可先做人物小传/对话练习。完成标准:对人物语言模式有直觉。 +4. **执行"什么人说什么话"**:教育/地域/职业/性格决定用词与句长。完成标准:遮住名字也能分辨是谁在说话(技术清单见 `dialogue-craft`)。 +5. **(长篇通篇对话)双重功能**:人物发言 + 叙述推进,节奏与旋律感。完成标准:对话同时在讲故事。 +6. **检验声音真实性**:朗读是否自然?完成标准:对话自然且有辨识度。 + +## 张力标注:事前设计 vs 过程发现 + +毕飞宇的关系网与性格词(见 [relationship-web.md](relationship-web.md)、[character-collision.md](character-collision.md))是动笔前的设计工具;余华的人物声音是写作过程中自然长出来的。两者分工:设计工具管骨架,声音发现管血肉。短篇可先用人物小传提前"熟悉"人物。 + +## 与相邻 skill 的区分 + +- **说话方式技术**:`dialogue-craft` owner,见 [character-voice.md](../../dialogue-craft/references/character-voice.md)。 +- **极端情绪下的身体呈现**:`show-and-omission` owner。 diff --git a/framework/catalog/dsh/skills/concept-design/SKILL.md b/framework/catalog/dsh/skills/concept-design/SKILL.md new file mode 100644 index 0000000..a3d6c1f --- /dev/null +++ b/framework/catalog/dsh/skills/concept-design/SKILL.md @@ -0,0 +1,93 @@ +--- +name: concept-design +description: | + 激活场景:用户手里只有模糊 idea、真实素材或"写了一半散掉"的稿子,还没形成能撑长篇的概念—— + "我想写 X 但不知道够不够"、"我的点子太平"、"题材写烂了,我没新意"、"真实事件想写成小说"、 + "朋友问小说讲什么我答不上来"、"写到一半故事散了"、"教学生怎么从 idea 到 concept"(教学演示)、 + "我有 3 个 idea,哪个最有潜力"(比较选择)、"朋友推荐我写 X,怎么判断值不值得"(第三方评估)、 + "真实人物的真实经历(传记/回忆录)怎么让它有 concept"、"读到一本好书/好新闻,想改写成小说"(非虚构改编)。 + 关键 trigger:"what if / 把 idea 变成 concept / 升级点子 / 故事种子 / premise / 这个点子够不够 / + 这个点子能写成小说吗 / 能撑 30 万字吗 / 哪个 idea 最有潜力 / 题材写烂了 / 我没新意 / 和别人一样 / + 我必须想新点子 / 真实事件写小说 / 历史题材 / 传记 / 回忆录 / 非虚构改编 / 叙事策略 / 通过谁的眼睛讲 / + 故事引擎 / story engine / 核心问题 / 小说在回答什么问题 / 中段失去方向 / 写到一半散了 / 故事没有主心骨"。 + 不适用于:纯抒情散文与反结构实验小说(问题引擎合法缺席);要求严格 1:1 复刻真实的新闻报道; + 概念已定之后的结构诊断(见 story-structure);写作习惯、心理状态等作者培养问题。 + 与 story-planning 交接:用户第一句话只有模糊 idea / 素材 / 引擎不清 → 本 Skill;概念已定、要做节拍表/工作流 → story-planning。 +--- + +# 概念设计(concept-design) + +动笔前先定下"这本书到底在回答什么问题":把模糊 idea 升级成疑问式概念,校验它撑不撑得住长篇,给真实素材找到自己的讲法,再用一个核心问题把整本书驱动起来。 + +## 方法索引 + +按创作动作组织;方法细节、案例、引文都在 references 里,这里只给一句话和指针。 + +### 产生:把"我想写 X"变成概念 + +- idea 是陈述句,concept 是疑问句:用"如果……会怎样"把题材升级成带角色、障碍、赌注的问题 → references/what-if.md +- idea→concept→premise→theme 四级递进,先判断种子到了哪一级 → references/what-if.md +- 写 3-5 个不同角度的疑问句,只挑最有戏剧张力的那一个 → references/what-if.md + +### 校验:这个概念配不配写成长篇 + +- 新鲜、新角度、冲突、可撑长四问校验;至少 3 问 Yes 且"可撑长"必须过 → references/four-questions.md +- 四问不全过也能写:新鲜度失败时用角色、主题、声音当补偿桶 → references/four-questions.md + +### 讲真实素材:真实事件也有概念 + +- 真实事件改不了,但"通过 X 的眼睛看 Y"就是概念,不同视角 = 不同故事 → references/delivery-strategy.md +- 视角人物化、时间结构化、形式实验化、主题聚焦化四种交付策略 → references/delivery-strategy.md +- 先列 ≥5 个候选视角再挑最强的,写成"通过 X 的眼睛,故事变成了 Y" → references/delivery-strategy.md + +### 找角度:"题材写烂了"是假问题 + +- 原创性不是题材新,是诚实:精确说出自己的看法,俗套提纲也能写出新故事 → references/originality.md +- 用信念清单挖角度,用旧题材验证,用目前的信念动笔,不等"想清楚" → references/originality.md + +### 驱动:用一个问题撑住整本书 + +- 主题陈述不是引擎,具体问题才是读者翻页的理由 → references/story-engine.md +- 引擎分答案驱动与过程驱动两类;副线迷你引擎必须服从主引擎 → references/story-engine.md +- 引擎体检:问题一句话说出、逐章推进比例、中段进展密度 → references/story-engine.md + +### 冲突标注 + +- Brooks 四问把"新鲜独特"列为第一关;布兰德主张视角的深度与诚实决定原创、题材不必新。两条规则都保留,见 references/originality.md 的"冲突标注"节。 + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|---------| +| references/what-if.md | 疑问句升级法、四级递进、芭蕾舞者/可爱的骨头/冰球队案例、失败模式与盲点、中文适配 | +| references/four-questions.md | 四问校验与记分标准、The Closers/Cold Mountain 案例、双向用法、失败模式、中文适配 | +| references/delivery-strategy.md | 真实素材四种交付策略、五步视角选择、Miracle/可爱的骨头/Collateral 案例、失败模式、中文适配 | +| references/originality.md | 原创性 = 诚实、信念清单、24 学生课堂/华顿/海明威案例、不等最后智慧、与 Brooks 新鲜度的冲突标注、与原书裁剪相邻方法的区分注记 | +| references/story-engine.md | 引擎三层概念、两类引擎、Kansas/Rosebud/Baby No. 81 案例、逐章与中段诊断、抒情传统与网文边界、相邻方法区分与衔接(write-toward-ending/gold-coins/mix-narrative-modes/inciting-incident 指针)、疑问句即 concept 即引擎的合并点 | +| references/_coverage.md | 五个源单元的覆盖对照表(唯一追溯文件,落点到小节) | + +## 脚本 + +| 脚本 | 用途 | +|------|------| +| references/concept-worksheet.md | 概念自查台账:从素材陈述、what-if 候选、四问记分、引擎一句话、视角候选到信念清单,一份填完 | + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落。 + +## 红线 + +- 只给当前创作阶段的建议,不越权改设定主权、不绕过检测链、不复制粘贴其它 Skill 的 owner 定义。 +- 无用户明确授权不得替用户定稿或提交 Git。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/dsh/skills/concept-design/references/_coverage.md b/framework/catalog/dsh/skills/concept-design/references/_coverage.md new file mode 100644 index 0000000..fc1f781 --- /dev/null +++ b/framework/catalog/dsh/skills/concept-design/references/_coverage.md @@ -0,0 +1,13 @@ +# concept-design 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| becoming-a-writer/originality-is-honesty | references/originality.md | +| story-engineering/concept-delivery-strategy | references/delivery-strategy.md | +| story-engineering/concept-four-questions | references/four-questions.md | +| story-engineering/concept-four-questions | references/originality.md | +| story-engineering/concept-what-if | references/what-if.md | +| story-engineering/concept-what-if | references/story-engine.md | +| writing-tools-clark/story-engine | references/story-engine.md | diff --git a/framework/catalog/dsh/skills/concept-design/references/concept-worksheet.md b/framework/catalog/dsh/skills/concept-design/references/concept-worksheet.md new file mode 100644 index 0000000..593f5fc --- /dev/null +++ b/framework/catalog/dsh/skills/concept-design/references/concept-worksheet.md @@ -0,0 +1,102 @@ +# 概念自查台账 + +用法:小说种子阶段从 0 到 6 顺着填。每节有"过关线",达标进下一节,不达标按标注回退。判断标准全部来自本包 references/ 各文件,这里只是填写骨架;方法细节与案例见各节标注的落点。 + +--- + +## 0. 素材陈述 + +我要写的(idea / 真实素材),1-2 句陈述句: + +> ____ + +## 1. What-if 候选(→ references/what-if.md) + +写 3-5 个不同角度的疑问句;试加反转 / 限制 / 时间压力 / 对手介入: + +1. 如果____? +2. 如果____? +3. 如果____? +4. (可选)如果____? +5. (可选)如果____? + +选定一个:____ +句子里有没有:角色 □ 障碍 □ 赌注 □ +为什么这个最有戏:____ + +过关线:能挑出一个含角色、障碍、赌注的疑问句。写不出 = 还没到 concept 阶段,回 0 重想素材。纯虚构以外的真实素材可直接跳第 4 节。 + +## 2. 四问校验(→ references/four-questions.md) + +| 问 | 问题 | Yes/No | 备注 | +|---|---|---|---| +| 1 | 新鲜独特:别人写过吗?这个类型里写烂了吗? | | | +| 2 | 新角度:不新的话,有没有独特角度(历史 / 真实事件也算)? | | | +| 3 | 冲突性:核心是不是冲突? | | | +| 4 | 可撑长:能撑满预定篇幅不枯竭吗(网文按连载字数算,中短篇改问"会不会注水")? | | | + +记分: + +- 全 Yes → 过关,进第 3 节 +- 3 Yes(必须含第 4 问)→ 可写;弱项:____;补救方式:____(参考 Cold Mountain 的补偿桶:角色、主题、声音) +- 2 Yes 或更少 → 回炉,回第 1 节 + +注意:第 1、2 问别混用——"不新但有新角度"记为问 1 No、问 2 Yes。"我觉得有趣"不算标准。第 4 问不作弊。 + +## 3. 引擎问题(→ references/story-engine.md) + +一句话说出(≤ 25 字,who / what / which / how): + +> ____ + +- 引擎类型:□ 答案驱动(读者要答案本身) □ 过程驱动(答案已知,看过程) +- 是不是主题陈述?("伟大的爱战胜死亡"这类判断不合格,要改写成具体问题)□ 已是问题 □ 已改写为:____ +- 副线迷你引擎(每个都必须服从主引擎): + - 副线 A:他 / 她的赌注是____? + - 副线 B:____? + +过关线:一句话说不出 = 没有引擎 = 故事会散,回第 1 节重磨疑问句。 + +## 4. 真实素材视角候选(仅真实素材填;→ references/delivery-strategy.md) + +素材(事件 / 人物 / 题材):____ + +| # | 视角人物 | 位置(主角 / 配角 / 反对者 / 旁观者 / 受影响者) | 对事件的信息差或情感连接 | 能撑 30 万字吗 | +|---|---------|--------------------------|---------------------------|----------------| +| 1 | | | | | +| 2 | | | | | +| 3 | | | | | +| 4 | | | | | +| 5 | | | | | + +最强视角一句话:通过____的眼睛,故事变成了____。 + +→ 把这句话当 concept,回第 2 节复验四问。 + +警告自检:□ 没有把"反派视角"当创新 □ 视角选择是戏剧策略不是营销策略 □ 没有为有趣牺牲史实 + +## 5. 信念清单(→ references/originality.md) + +排除"应该",只留"真的": + +1. 我真正相信什么?____ +2. 我真正愤怒什么?____ +3. 我最难忘的经历?____ +4. 我与大多数人不同意的看法?____ +5. 我的失败 / 丑事?____ +6. 我想对谁说什么话?____ + +列不出 → 问自己"我最讨厌什么?最反感什么?" + +验证:挑一个烂大街题材(灰姑娘 / 英雄之旅 / 复仇 / 爱情),用上面清单里的一条写 1 段 1-2 分钟的故事,必须包含我自己的看法。写得动吗?□ 能 □ 不能 + +只有我经历过的细节 3 个:____;____;____。 + +承诺:用我现在的想法写,不等"以后想清楚"。□ + +## 6. 总评 + +- 概念定稿(一句话):____ +- 引擎问题(一句话):____ +- 判定:□ 四问通过且引擎到位 □ 可写,弱项补救清单:____ □ 回炉 +- 下一步:结构规划(见综合 skill story-structure)/动笔 diff --git a/framework/catalog/dsh/skills/concept-design/references/delivery-strategy.md b/framework/catalog/dsh/skills/concept-design/references/delivery-strategy.md new file mode 100644 index 0000000..b4707e7 --- /dev/null +++ b/framework/catalog/dsh/skills/concept-design/references/delivery-strategy.md @@ -0,0 +1,99 @@ +# 真实素材也是 concept:叙事交付策略 + +## 原文摘录 + +> "A story about the 1980 U.S. Olympic hockey team and their gold medal may seem to defy the notion of a concept, because it is what it is, you can't mess with the truth. But you can—and should—land upon a conceptual delivery strategy to show us that truth, and it doesn't always have to do with plot. The moment you tell that story through the eyes of a single player—the goalie, for example, or maybe the coach—then you have evolved the idea into the realm of concept." +> +> — Larry Brooks, *Story Engineering* (2011), Part 2 + +## 方法规则 + +### 核心洞察 + +Concept 不一定是"疯狂的点子"。即使你的素材是真实事件,选一个独特的**叙事视角 / 策略**就构成 concept。 + +- Concept 不必是"如果 X 会怎样"(虚构 what if) +- Concept 可以是"通过 X 的眼睛看 Y"(视角选择) +- 同一真实事件,不同视角 = 不同 concept = 不同故事 + +### 4 种常见叙事策略 + +1. **视角人物化**:通过一个非中心人物(守门员、医生妻子、敌方士兵)看大事件 +2. **时间结构化**:用倒叙 / 闪回 / 跨越数十年的结构重组事件 +3. **形式实验化**:用日记 / 信件 / 审讯记录 / 多个短篇拼图等非传统形式 +4. **主题聚焦化**:把大事件压到单一主题维度(种族、阶级、性别、信仰) + +### 操作法 + +拿到你的真实素材,问"如果我通过 X 的眼睛讲,会怎样?"——这个 X 必须对原始事件有独特的"信息差"或"情感连接"。 + +## 案例全文 + +### 案例 1:Miracle——1980 美国冰球队 + +- **问题**:真实事件"1980 美国冰球队夺金"看似无法加 concept +- **方法论的使用**:通过守门员 Jim Craig 的眼睛讲(他在 1980 年成为美国精神的象征) +- **结论**:叙事策略 = concept +- **结果**:2004 年电影 *Miracle*,Kurt Russell 主演,票房评论双成功 + +### 案例 2:The Lovely Bones——天堂题材 + +- **问题**:Alice Sebold 想"写天堂是什么" +- **方法论的使用**:通过一个被谋杀的 14 岁女孩的眼睛(她在天堂叙述)讲谋杀案 +- **结论**:叙事策略(死后视角)+ 主题(正义、宽恕、家庭)= 概念 +- **结果**:全球 1000 万册 + +> 本案例在 references/what-if.md 也出现,那边角度是把"想写天堂"升级成疑问句,这边角度是视角交付策略,角度不同,两处都保留。 + +### 案例 3:Collateral——出租车 + +- **问题**:"杀手 + 出租车"太单薄 +- **方法论的使用**:通过一个普通出租车司机的眼睛,整晚被迫载杀手,逐渐变成被迫害者 +- **结论**:视角选择 = concept +- **结果**:验证了"非典型视角"的有效性 + +## 操作步骤 + +1. **陈述素材** + - 完成标准:1-2 句说清真实素材(事件 / 人物 / 题材) +2. **列出可能的视角人物(≥ 5 个)** + - 完成标准:至少 5 个不同位置的人(主角 / 配角 / 反对者 / 旁观者 / 受影响者) + - 不要先挑,先全列 +3. **对每个视角评估"戏剧性"** + - 完成标准:每个视角回答"这个视角能撑 30 万字吗?" + - 戏剧性 = 角色 + 障碍 + 赌注 + 信息差 +4. **挑 1 个最强视角** + - 完成标准:给出 1 句话:"通过 X 的眼睛,故事变成了 Y" + - 这是你的 concept +5. **验证**(用 references/four-questions.md 的 4 问) + - 完成标准:4 问通过,进入下一阶段 + +## 边界与失败模式 + +### 不要在以下情况使用 + +- 已经在写纯虚构(用 references/what-if.md) +- 写非叙事 / 学术 / 技术(这不适用) +- 真实素材需要严格 1:1 复刻(新闻 / 纪实)——应保持中立,不叙事化 + +### 作者警告的失败模式 + +- 把"通过反派视角讲"当创新——经常是噱头,戏剧性不够 +- 视角选择 = 营销策略(如"我们这次用女性视角")而不是戏剧策略 +- 忽略真实人物 / 事件的约束——只选有趣的视角,牺牲史实 + +### 作者盲点 + +- 默认西方个人主义视角——集体 / 文化 / 家族视角可能更适合某些题材 +- "通过 X 眼睛"的视角单一——多视角(POV 切换)是另一种合法策略 + +## 中文适配 + +- 中国历史与家族题材(村志、厂史、家变、年代群像)常用"小人物看大事件"或"一个家族当视角容器",这正是 Brooks 盲点条款指出的集体 / 家族视角方向,比硬套个人英雄视角更顺。 +- 中文历史题材有史实硬边界:视角人物可以虚构,事件骨架要尊重史实,失败模式里"牺牲史实"的警告在此同样成立。 +- 形式实验化在中文里有现成传统可依托:日记体(鲁迅《狂人日记》)、书信体、供状 / 卷宗体、章节拼图都有本土成例,选形式时优先想清楚形式与"信息差"的关系,不为新而新。 + +## 易混方法论 + +- "Rashomon 效应"——多个视角讲同一事件,不同于本方法的"挑 1 个" +- 电影 *Rashomon* vs 小说多 POV:前者展示真相多面性,后者展示人物丰富性 diff --git a/framework/catalog/dsh/skills/concept-design/references/four-questions.md b/framework/catalog/dsh/skills/concept-design/references/four-questions.md new file mode 100644 index 0000000..f5d6cf1 --- /dev/null +++ b/framework/catalog/dsh/skills/concept-design/references/four-questions.md @@ -0,0 +1,93 @@ +# 概念合格性校验:concept 四问 + +## 原文摘录 + +> "A concept, it could be said—and it should be viewed this way—is something that asks a question. The answer to the question is your story. Is the concept fresh and original? Does it at least present an opportunity to impart a new spin on a familiar theme or premise? Is it cast in terms of conflict? Can you sustain reader interest in this concept over the length of a novel?" +> +> — Larry Brooks, *Story Engineering* (2011), Part 2 + +## 方法规则 + +判断一个写作种子是否升级为"concept"的 4 个筛子。任何一题答 No,种子就还没准备好作为故事,需要回炉。 + +### 4 问 + +1. **新鲜独特(Fresh & Original)**:这个 concept 是不是别人没写过的?或者至少在这个时代 / 这个 genre 还没被写烂?(过低 = 没人想看) +2. **新角度(New Spin)**:如果不新,它有没有给熟悉主题一个独特角度?(历史 / 真实事件都算) +3. **冲突性(Cast in Conflict)**:这个 concept 的核心是不是"有冲突"?没有冲突 = 不是概念 +4. **可撑长(Sustains Novel-length)**:这个 concept 能不能撑 300+ 页而不枯竭?(概念太单薄 = 写不到长篇) + +### 判断逻辑 + +不必 4 问全 Yes,但至少 3 问 Yes,第 4 问(可撑长)必须 Yes。没有冲突的 idea 不是 concept,单一事件的 idea 撑不到长篇。 + +### 用法的关键:双向 + +这是**双向的**——可以 (a) 评估现有 idea,也可以 (b) 在 idea 阶段就自我检查,避免"写了 200 页才发现 concept 撑不住"。 + +## 案例全文 + +### 案例 1:The Closers——同 idea 多种 concept + +- **问题**:Michael Connelly 想写一个"警探破案"故事,这个 idea 撑不起 30 万字 +- **方法论的使用**:对 idea 问 4 问:(1) 新鲜?不,警探破案写烂了 (2) 新角度?加:20 年前的悬案 + 警方掩盖 + 种族歧视历史背景 (3) 冲突?是 (4) 可撑长?是 +- **结论**:通过 4 问后,idea 升级为 killer concept +- **结果**:成为纽约时报畅销书 + +### 案例 2:Cold Mountain——4 问不通过但仍成功 + +- **问题**:Civil War 士兵回家,这个 idea 极度普通(第 1 问失败) +- **方法论的使用**:接受第 1 问失败,用 (2)(3)(4) 强力支撑——靠"角色 + 主题 + 声音"救场 +- **结论**:4 问不全通过也能写,但必须有补偿桶 +- **结果**:#1 畅销书,国家图书奖,证明 6 桶互为补偿 + +> "6 桶"指 Brooks 的六项核心能力(six core competencies),该框架归属综合 skill novel-diagnosis,此处不展开。 + +## 操作步骤 + +1. **陈述你的 idea/concept** + - 完成标准:用户能用 1-2 句话说清他的种子 +2. **逐题问 4 问** + - 完成标准:4 问都有 yes/no 答案 + - 答案不需要长解释,是 / 否即可 +3. **统计 + 诊断** + - 完成标准:给出"通过 X 问"的总评 + - 全 Yes:升级成功,进入下一阶段 + - 3 Yes(含第 4 问):可写,但需补不强项 + - 2 Yes 或更少:需回炉,用 references/what-if.md 升级 +4. **给出建议** + - 完成标准:用户拿到一个"下一步做什么"的具体指引 + +## 边界与失败模式 + +### 不要在以下情况使用 + +- 已有 concept 但想改进结构(用 story-structure 综合 skill) +- 想把 idea 升级到 concept(用 references/what-if.md) +- 非小说写作(诗歌 / 散文 / 论文) + +### 作者警告的失败模式 + +- 把"我觉得有趣"当"concept 达标"——主观趣味不等于客观 4 问 +- 第 4 问(可撑长)容易作弊——以为 200 页就够了,但商业小说需 300+ +- 第 1 问和第 2 问混用——"不新但有新角度"应该归到第 2 问 Yes,第 1 问 No + +### 作者盲点 + +- 4 问默认"商业出版"标准,文学 / 实验小说可能需要更宽松 +- 第 4 问"撑 300 页"假设长篇——中短篇不需要这条 + +## 中文适配 + +- "撑 300+ 页"是商业出版页数口径:中文纸质出版可按 20-30 万字折算;网文连载要按几十万字到百万字的连载体量算,"可撑长"要拆到小钩子的更新节奏上逐段检验。 +- 中短篇免除第 4 问,改问"能不能在预定篇幅内把故事讲完而不注水"。 +- 中文网文里被写烂的类型(赘婿、系统、刑侦悬疑)可以走 The Closers 的路:保留熟悉框架,叠加本土悬案、时代背景、社会议题当"新角度",把第 1 问的失败转成第 2 问的通过。 + +## 冲突标注(一句话指针) + +第 1 问"新鲜独特"与布兰德的原创性观点相左——布兰德认为题材不必新,视角的诚实与深度才决定原创 → 见 references/originality.md 的"冲突标注"节。 + +## 易混方法论 + +- "Save the Cat 的 10 个 genre 类型"——那是 genre 分类,不是 concept 质量 +- Christopher Booker 的 7 个原型——那是主题原型,不是 concept 评估 diff --git a/framework/catalog/dsh/skills/concept-design/references/originality.md b/framework/catalog/dsh/skills/concept-design/references/originality.md new file mode 100644 index 0000000..493caf5 --- /dev/null +++ b/framework/catalog/dsh/skills/concept-design/references/originality.md @@ -0,0 +1,173 @@ +# 原创性就是诚实:你的视角本身就是原创 + +## 原文摘录 + +> "只要你能够和自己友好相处,能够而且愿意精确地说出你对任何一种情形或一个人的看法, +> 如果你能够讲出一个好像包括地球上所有人在内只有你自己看到的故事, +> 你自然而然地就有了一篇原创作品。 +> 而这一点看起来似乎非常简单,却是一般作家最难做到的。 +> 那些作家的优点恰恰在于,他们拒绝像他们的模仿者那样谦卑地人云亦云。 +> 他们每一个人都有一个自己的视角,都传达出了自己对世界的描写。" +> +> — 多萝西娅·布兰德,《成为作家》第十二章(引用伊迪丝·华顿) + +## 方法规则 + +### 核心反直觉命题 + +**原创性 = 你的诚实**——精确说出自己的看法。不是"想新点子"。 + +### 流行误解 + +- 原创性 = 想到没人想到的题材 +- 原创性 = 独特的风格 +- 原创性 = 标新立异 + +### 布兰德的真相 + +- 原创性 = 精确说出**自己**对情形的看法 +- 你的视角**已经**是独特的——"即使是一对双胞胎也不会对同样的故事有完全一样的看法" +- 不需要"新点子",需要"真诚的旧点子" + +### 为什么"旧点子"也是原创 + +- 同样一个"俗套"提纲,24 个学生写出 24 个故事 +- 你的"愤怒"和别人的"愤怒"不是同一种 +- 你的"爱"和别人的"爱"经历不同 +- 你的"妈妈" / "童年" / "失败" / "成功"**不是**别人的 +- 关键不是题材,是**你怎么看待** + +### "不要等最后智慧"(布兰德的反复警告) + +- 思想永远不会"完成",因为人在持续成长 +- 等"最终" = 等"死"——因为只有死时思想才"停止变化" +- "等我想清楚再写"的人永远不写 +- 在你**目前的信念**基础上写,不要假装成未来的自己 + +### "令人吃惊的结尾"的陷阱 + +- 有些作者为"原创"而原创,把结尾写得"惊人" +- 他们为了服务"原创"这个上帝,让角色做不该做的事 +- 故事不连贯,失败 +- 真正的好结尾是**角色自身**会做的事,不是作者强加的 + +### 为什么布兰德说"难" + +- "看起来似乎非常简单"——你只需要说自己的看法 +- "却是一般作家最难做到的"——因为作者会**模仿**别人的看法 +- 长期读书的人,习惯"通过别人的眼睛看世界" +- 重新"通过自己的眼睛看",需要勇气 + +### 华顿夫人的两条法则(布兰德引用) + +1. 小说家应该只处理他力所能及之事(与你真诚相关的题材) +2. 一个主题的价值完全取决于作者能够从中发现什么以及他发现的深度 + +### 原创性的"诚实清单" + +- 你相信什么?(信念) +- 你为什么愤怒?(情感) +- 你最难忘的经历是什么?(记忆) +- 你与大多数人不同意的看法是什么?(立场) +- 你的"丑事" / "失败"是什么?(隐私) +- 你想对谁说什么话?(目标) + +## 案例全文 + +### 案例 1:高尔夫球冠军少女的课堂 + +- **问题**:布兰德给一个"极俗套"的提纲(娇生惯养的女孩结婚,对金钱的态度差点毁了姻缘) +- **方法论的使用**:让学生 10 分钟内各写一段 +- **结论**:同一提纲,24 个学生写出 24 个完全不同的故事——视角本身就是原创 +- **结果**:学生再没抱怨"我唯一的思路陈腐" + +### 案例 2:华顿夫人的"两项基本法则" + +- **问题**:写小说时不知如何处理题材 +- **方法论的使用**:引用华顿:题材的价值不在于"题材本身多新",在于"你从中发现的深度" +- **结论**:同一个"旧"题材,写得有深度 = 原创 +- **结果**:重新定义"原创"的来源 + +### 案例 3:海明威 vs 模仿者 + +- **问题**:模仿者模仿海明威"硬汉味",但越来越僵 +- **方法论的使用**:布兰德诊断:模仿者模仿"风格"(海明威的"味道"),不是"视角"(海明威的真实经验) +- **结论**:风格 = 海明威的真实;模仿者 = 抄别人的真实,永远不真 +- **结果**:模仿者凝在错误年代 + +## 操作步骤 + +1. **诊断:用户的"原创性"误解是哪一个** + - 完成标准:用户能说出"我以为原创是 X,现在知道是 Y" + - 提问:"你说的'新意'是什么意思?是新题材,还是新视角?" + - 判停条件:若用户说"我两者都要" → 解释:视角才是真正可得的,题材是无限的也是不重要的 +2. **诚实地填一份"信念清单"** + - 完成标准:用户能列出 3-5 个"我真正相信的事" / "我真正愤怒的事" + - 关键:排除"应该"相信的,只留"真的"相信的 + - 例:"我相信'努力就会成功'是骗人的" / "我相信现代婚姻本质上是经济关系" + - 判停条件:若用户列不出 → 提问"你最讨厌什么?最反感什么?" +3. **从一个"旧"提纲开始** + - 完成标准:用户能写"1 段 1-2 分钟"的故事,用"旧"提纲 + 自己的视角 + - 任务:"挑一个'烂大街'的题材(灰姑娘 / 英雄之旅 / 复仇 / 爱情),写 1 段 1-2 分钟的故事,必须包含你'自己的看法'" + - 关键:不是"想新点子",是"用你真实的看法写" +4. **找出"你独有的细节"** + - 完成标准:用户能列出"别人没经历过的 3 个细节" + - 任务:列出只属于你的"童年记忆 / 工作细节 / 某次失败 / 某次惊喜" + - 这些细节是"你"写的,别人无法抄 +5. **不要等"最后智慧",现在就写** + - 完成标准:用户承诺"用我现在的想法写,不等'以后想清楚'" + - 关键:现在的看法 = 现在的原创;以后的看法 = 以后的原创 + - 写出来后,以后还能改 + +## 边界与失败模式 + +### 不要在以下情况使用 + +- **用户没有素材**——对应的是素材积累类方法,未收入本技能库 +- **用户写得好但没发表**——对应的是写后心态类方法,未收入本技能库 +- **用户被"不知写什么"卡住**——对应的是写作困难诊断类方法,未收入本技能库 +- **用户被法律 / 版权问题困扰**——那是原创性之外的"抄袭"问题 + +### 作者在书中警告的失败模式 + +- **等最后智慧**:想"等想清楚再写",永远想不清楚 +- **模仿风格**:模仿别人的"味道"(别人的真实),永远不是自己的 +- **公共场合批评**:在班上当众批评,让学生扔掉自己的风格 +- **一本正经学技巧**:把"学技巧"当作主要工作,越学越像别人 + +### 作者的盲点 / 时代局限 + +- **"诚实"假设你有勇气**——现实中很多人因为经济压力 / 家庭压力,不能完全诚实 +- **"你的视角"假设你能表达**——有些人有视角但表达不出来(那是技术问题) +- **不区分"创作自由"和"商业写作"**——商业写作有时不能完全诚实(客户要求) +- **过度理想化"自我表达"**——写公众号 / 营销文 / 学术论文,都不是"自我表达"主导 + +## 冲突标注:与 Brooks"新鲜独特"第 1 问的分歧 + +Brooks 的概念四问把"新鲜独特"列为第一关:concept 不新就不合格(→ references/four-questions.md)。布兰德相反:题材根本不必新,原创来自作者的诚实视角与发现深度,"旧"题材写出深度就是原创。 + +两条规则冲突,都保留。使用分工: + +- Brooks 的标准评的是**概念的市场成立性**——判断一个点子能不能撑起读者兴趣时用。 +- 布兰德的标准评的是**作者的独有角度**——卡在"题材写烂了、我没新意"时用。 +- 可操作的顺序:先用布兰德的方法把真实视角挖进熟悉题材,再用 Brooks 的第 2 问(新角度)检验这个视角是否构成独特角度——"诚实"用来供给"新角度",两套标准就接上了,而不是互相抵消。(此段为合并整合说明,两条规则的出处见 references/_coverage.md。) + +## 中文适配 + +- 《成为作家》中译本直接可用:信念清单、旧提纲练习、独有细节清单可以原样用于中文写作自查和课堂。 +- 中文写作者填信念清单时,"应该相信"的干扰常来自教育与平台语境的套话;按布兰德的标准,这些"应该"一律排除,只留"真的"相信的。 +- 平台定制、商业连载写作中,布兰德的盲点条款依然成立:诚实要与类型契约商量着来,但"你怎么看待这个处境"仍然是别人抄不走的部分。 + +## 易混的邻近方法论 + +- **"寻找独特卖点"(USP 营销)**——是商业概念,找市场差异,不是"你的真实" +- **个人品牌建设**——是包装自己,不是诚实表达 +- **"创新方法论"(TRIZ 等)**——是技术发明方法,不是写作原创 + +## 与原书相邻方法的区分 + +以下相邻方法均属作者培养类,未收入本技能库;区分条目按原文保留,供理解本方法的边界: + +- **与"重新看世界"(素材积累类方法)的区别**:素材积累教"重新看世界";本方法教"从自己的视角写"。前者是 input,后者是 output 角度;先"重新看",再找到自己的视角。 +- **与"学别人的技术"(模仿学习类方法)的区别**:模仿学习教"学别人的技术";本方法教"写自己的内容"。两者**对比**——**技术可借,内容不可借**(学别人的技术 vs 写自己的内容)。这条判断标准有独立方法价值。 +- **与"保护创作能量"(能量管理类方法)的区别**:能量管理解决"能量被消耗";本方法解决"内容无自己"。前者是 energy,后者是 angle;自己的视角需要保护。 diff --git a/framework/catalog/dsh/skills/concept-design/references/story-engine.md b/framework/catalog/dsh/skills/concept-design/references/story-engine.md new file mode 100644 index 0000000..8e7da16 --- /dev/null +++ b/framework/catalog/dsh/skills/concept-design/references/story-engine.md @@ -0,0 +1,122 @@ +# 故事引擎:让核心问题驱动整本书 + +## 原文摘录 + +> Who done it? Guilty or not guilty? Who will win the race? Which man will she marry?… This narrative strategy is so powerful that it needs a name, and Tom French gave it to me: he calls it the "engine" of the story. He defines the engine as the question the story answers for the reader. +> +> — Roy Peter Clark, *Writing Tools* (Tool 31) + +> I have read many manuscripts that lack a story engine. The writers have worked hard, often beautifully, but there is no narrative fuel to power the piece to its end. +> +> — Roy Peter Clark, *Writing Tools* (Tool 31, on the failure mode) + +## 方法规则 + +Clark 通过 Tom French 提出"故事引擎",核心论断是:**长篇 / 短篇集 / 非虚构书的结构不是"主题",而是"问题"。** + +### 三层概念必须分清 + +- **主题(theme / premise)**:抽象判断,如"伟大的爱战胜死亡"、"权力腐蚀人"。是结论,是终点,不能驱动翻页。 +- **故事(story)**:事件流,人物动作、情节转折。是回答的载体,但不是回答的吸引力。 +- **引擎(engine / key question)**:贯穿全书的**核心问题**——读者翻页的唯一原因是想知道这个问题的答案。 + +### 区分两类引擎问题 + +1. **答案驱动(who / what / which)**:"她会不会回到 Kansas?"、"Rosebud 是什么?"、"Baby No. 81 是谁家的孩子?"——读者要的是"答案本身"。 +2. **过程驱动(how)**:"007 怎么能赢?"——答案已预知,读者要的是"过程如何精彩"。 + +### 一句话说出来 + +Clark 强调:**小说写作者要能用一句话说出"我的故事在回答什么问题?"** 说不上来 = 没有引擎 = 故事散了。 + +### 副线迷你引擎 + +副线可以挂"迷你引擎"(每个角色"他的赌注是什么?")——但所有迷你引擎必须服从主引擎。 + +## 案例全文 + +### 案例 1:奥兹《Short Story》("她会不会回到 Kansas?") + +- **问题**:短篇如何让人一口气读完? +- **方法论的使用**:奥兹把一个小说压缩到一个人物的一句话里——"她会不会回到 Kansas?"——这是 who 引擎,读者必须翻到末尾才知道答案。 +- **结论**:即使最短的短篇也需要一个"答案驱动"的问题;**没有这个问题,短篇会被读者搁置**。 +- **结果**:成为了"短篇也需要引擎"的金标准案例;Clark 用来反驳"短篇不需要结构"的天真假设。 + +### 案例 2:《公民凯恩》("Rosebud 是什么?") + +- **问题**:看似无情节的人物传记片如何让人想看下去? +- **方法论的使用**:整部电影就是一个侦探在追问"Rosebud 是什么?"——一个 who 引擎,答案(童年雪橇)在最后一秒揭晓。 +- **结论**:引擎可以**穿越任何题材**——传记、悬疑、爱情、家庭——只要有一个具体问题,故事就有动力。 +- **结果**:成为了"答案驱动 vs 过程驱动"分类的标志案例;展示了"如果题材本身没戏剧性,人造一个问题也能造出动力"。 + +### 案例 3:Tom French 的 HB 婴儿案("Baby No. 81 是谁家的孩子?") + +- **问题**:非虚构长篇报道如何让人愿意读 30 万字? +- **方法论的使用**:Tom French 把整本非虚构书围绕一个具体问题——一个被错换的女婴最终回到哪家?——读者翻页是因为想知道"答案"。 +- **结论**:**非虚构书也需要引擎问题**——不是"主题"(医疗体系批判),而是"一个具体问题"——主题是结论,问题是钩子。 +- **结果**:成为了"非虚构 = 故事"论点的最强证据;证明了 French 概念在虚构 / 非虚构之间的可迁移性。 + +## 操作步骤 + +1. **一句话写出引擎问题** + - 问用户:"你的小说在回答什么问题?"——强制 25 字以内,who/what/which 形式。 + - 完成标准:用户能用一句话说出"她会不会……" / "他能不能……" / "X 是什么……";说不出的,标为"无引擎"。 + - 判停条件:若用户写的是"主题陈述"(如"伟大的爱战胜死亡"),需帮其改写为具体问题(如"她会不会为他放弃自己的医生事业?")。 +2. **检验每章是否被引擎驱动** + - 列出每章标题,逐一问:"这章把引擎问题往答案推了多远?"——回答应是"推了一半"、"让它更复杂"、"让答案变成新问题"。 + - 完成标准:90% 章节被标"推进引擎";若超过 30% 章节"无关于引擎",标为"引擎失效"——需重写或删减。 + - 判停条件:章节可能是"必需但无关引擎"(如背景铺垫),允许最多 10% 的"装饰性章节",但作者需明确知道这些是"非引擎"。 +3. **中段诊断:三分之一处读一遍** + - 单独读 1/3 处的章节(全书 30%-40% 位置),问:"如果我读到这页,我会想翻下一页吗?" + - 完成标准:中段每 5000-10000 字至少 1 次"问题进展"(新信息 / 矛盾 / 加码 / 答案翻盘);否则诊断为"中段塌陷",用金币密布的方法修补(gold-coins,归属综合 skill narrative-momentum)。 + - 判停条件:若中段每章都"等距推进",说明引擎问题"线性可预测"——需在中段加入"答案翻盘"或"问题变形"。 + +## 激活场景 + +用户在这些情境下需要本方法: + +1. 写到长篇中段,每章都写了但"读起来像流水账"——章节之间没有"答案推进"。 +2. 朋友 / 编辑问"你这本小说讲什么?",你只能回答"呃……很多事"。 +3. 写短篇集,各篇都好但整本读完"没有主心骨"——读者记不住你。 +4. 写非虚构书,书里充满"主题"但没有一个具体问题钩住读者。 +5. 动笔前不知道"我这本书在回答什么问题"——主题写满三页纸但没有一句话的问题。 +6. 长篇写到 1/3 处感觉"故事散了"——人物还在动,但读者(和自己)已经忘了"为什么在动"。 + +语言信号:"故事没有主心骨"、"中段失去方向"、"小说要回答什么问题"、"故事散了" / "写到一半散了"、"故事引擎" / "story engine" / "key question"、"我小说讲什么?"答不上来、"主题太抽象" / "落不进情节"、"Tom French" / "French engine"。 + +## 边界与失败模式 + +### 不要在以下情况使用 + +- **纯抒情散文 / 散文诗**——没有"问题"是合法的,引擎是叙事性文学的工具。 +- **反结构实验小说**——故意无情节、无问题(《项狄传》、某些后现代)是反"引擎"的合法艺术选择,不能用此方法评判。 +- **单场景剧本 / 独幕剧**——没有长程结构,引擎失效。 +- **工具书 / 教材**——引擎问题不适用,改用"读者翻页是为了解 X"——那是手册结构,不是故事结构。 + +### 作者在书中警告的失败模式 + +- **"没有引擎 = 故事散"**:失败模式是长篇没有核心问题——读者读完 200 页不知道"作者想说什么"。**信号**:朋友问"你小说讲什么?"作者回答"呃……很多事"。**机制**:人脑把故事存储为"问答结构"——核心问题 + 解答过程;没有问题 = 没有存储格式 = 记不住 / 不想继续。**警告信号**:用一句话说不清 / 章节之间没有"答案推进" / 中段之后结构松散。 +- **"主题陈述当引擎"(常见混淆)**:把"伟大的爱战胜死亡"当引擎——但这是判断,不是问题。判断被读者接受就完了,问题才会让人翻页。 + +### 作者的盲点 / 时代局限 + +- Clark 的引擎理论主要在**非虚构**和**小说长篇**语境下发展(Tom French 是记者,Clark 自己是写作教师),**散文诗 / 抒情文学**不在视野内,中文文学传统里大量"无问题"的散文会被错误判定为"无引擎"——这是工具的边界,不是文学的失败。(中文适配) +- **时代局限**:Clark 写于 2006 年(英文版),未涵盖**网文连载**——网文有独特的"明线引擎" + "暗线升级"双轨结构(明线是表层问题,暗线是深层问题翻盘),直接套用"一句话引擎"会让网文结构被错判为"单一"。(中文适配) +- **概念溯源需注明**:故事引擎这个概念**主要来自 Tom French**(记者、普利策奖得主),Clark 在书里**明确把命名权归给 French**。引用时不应说"Clark 发明了故事引擎",而应说"Clark 通过 French 的概念提炼为可操作工具"。 + +## 与概念的关系:疑问句既是 concept 也是引擎(两书合并点) + +Brooks 说概念是"asks a question","问题的答案就是你的故事";French 把引擎定义为"故事为读者回答的那个问题"。两本书说的是同一件事的两面: + +- 同一个疑问句,在概念阶段是 what if(→ references/what-if.md),在运行阶段是引擎。 +- 概念阶段产不出疑问句,运行阶段就没有问题可驱动;反过来,写到中段引擎失效,回概念阶段检查疑问句本身有没有角色、障碍、赌注。 +- Brooks 四问里的第 4 问"可撑长",其实就是对"引擎能不能撑长篇"的预检(→ references/four-questions.md)。 + +## 易混的邻近方法论 + +- **与 "inciting incident" 的区别**:那个是"第一秒扔出来的打火石",这个是"持续牵引的问题";前者是开关,后者是发动机。一本书可以**没有 inciting incident(慢热)**但**必须有 engine**——反之不行。两者可衔接:inciting incident 是引擎的"开场打火石"。(inciting-incident 方法归属综合 skill story-structure。) +- **与 "write-toward-ending" 的区别**:那个是"先定结局"——锚定终局再反向写作;这个是"先定问题"——锚定核心问题再驱动写作。**问题在前,结局在后**——读者读小说不是为看结尾,是看问题怎么被回答。两者可衔接:先定引擎问题,再倒推向结局。(write-toward-ending 方法归属综合 skill story-ending。) +- **与 "gold-coins" 的区别**:那个是"中段撒金币"——防止读者在中段弃读的小高潮密布;这个是"中段为什么不散"——**引擎持续运转,中段自然不塌**。金币是"锦上添花",引擎是"主结构";引擎不散 + 金币不弃读 = 长篇双保险。(gold-coins 方法归属综合 skill narrative-momentum。) +- **与 "mix-narrative-modes" 的区别**:那个是"主线 / 折线 / 蒙太奇"等模式调度;这个是"无论用哪种模式,都在回答同一个核心问题"。(mix-narrative-modes 方法归属综合 skill narration-pov。) +- **与 "theme / premise"(经典写作书)的区别**:主题是抽象判断("爱战胜死亡"),引擎是具体问题("她会不会为他死?")。**判断是终点,问题是路径**——读者读小说是走路径,不是看终点。 +- **与 "logline"(编剧术语)的区别**:logline 是"卖点压缩"(人物 + 冲突 + 钩子),引擎是"贯穿问题"——logline 可以多重,引擎只能一个。 diff --git a/framework/catalog/dsh/skills/concept-design/references/what-if.md b/framework/catalog/dsh/skills/concept-design/references/what-if.md new file mode 100644 index 0000000..d2e37d1 --- /dev/null +++ b/framework/catalog/dsh/skills/concept-design/references/what-if.md @@ -0,0 +1,109 @@ +# 把 idea 升级成 concept:concept 必须是"what if"疑问句 + +## 原文摘录 + +> "A concept, it could be said—and it should be viewed this way—is something that asks a question. The answer to the question is your story. The idea to write a story about ballet dancers is not a concept. It is just an idea. But when you add a forward-thinking realm to that idea, and do it in the form of a question—what if a ballet dancer loses her leg at the knee but perseveres against great prejudice to become a professional dancer?—you have evolved the idea into the realm of conceptualization." +> +> — Larry Brooks, *Story Engineering* (2011), Part 2 + +## 方法规则 + +### idea 是陈述句,concept 是疑问句 + +"想写 X"是一个 idea,但 idea 不是 concept。Concept 必须以**疑问句(what if?)**形式存在——只有疑问才能撑起故事的张力。 + +核心规则对照: + +| Idea(陈述句) | Concept(疑问句) | +|---|---| +| "我想写律师" | "如果律师发现自己辩护的凶手是父亲?" | +| "我想写芭蕾舞者" | "如果芭蕾舞者失去膝盖以下?" | +| "我想写珍珠港事件" | "如果珍珠港当天一个日本飞行员的妻子在等他回家?" | + +### 4 级递进 + +1. **Idea**(陈述性)→ 2. **Concept**(疑问性)→ 3. **Premise**(概念 + 角色任务)→ 4. **Theme**(故事意义) + +### 为什么必须是疑问句 + +- 疑问自带戏剧张力——读者想知道答案 +- 疑问暗示"还没决定"——给角色留出走过的路径 +- 疑问暗示"还有风险"——给故事留下起伏空间 + +### 操作法 + +拿到 idea,用 "What if...?" 起头,强逼自己写出疑问句。如果写不出 = 还没到 concept 阶段。 + +## 案例全文 + +### 案例 1:芭蕾舞者 → 概念化 + +- **问题**:写作者只想"写一个芭蕾舞者" +- **方法论的使用**:强加 what if? ——"如果她在 25 岁失去膝盖以下呢?" +- **结论**:失去肢体 + 坚持 + 偏见 = 戏剧张力,撑起 30 万字 +- **结果**:演示了 idea→concept 的标准路径 + +原文摘录里 Brooks 的说法是 "what if a ballet dancer loses her leg at the knee but perseveres against great prejudice to become a professional dancer?"——同一个案例,多了"顶着偏见成为专业舞者"这层坚持与偏见的具体内容,两处对照使用。 + +### 案例 2:The Lovely Bones——从主题到 concept + +- **问题**:Alice Sebold 想"写天堂是什么样" +- **方法论的使用**:用 what if? ——"如果一个被谋杀的 14 岁女孩在天堂,她的家人不知道真相,她干预?" +- **结论**:疑问句打开 murder mystery 主题 +- **结果**:全球 1000 万册 + +> 本案例在 references/delivery-strategy.md 再次出现,那边角度是"死后视角"作为叙事交付策略,角度不同,两处都保留。 + +### 案例 3:1980 美国冰球队 → 守门员视角 + +- **问题**:写作者想"写 1980 美国冰球队夺金" +- **方法论的使用**:用 what if? ——"如果通过守门员的视角看这支球队?" +- **结论**:疑问句把历史事件变成故事 +- **结果**:成为 2004 年电影 *Miracle* + +> 本案例同时是 references/delivery-strategy.md 的头号案例(真实事件的视角化交付),角度不同,两处都保留。 + +## 操作步骤 + +1. **陈述 idea** + - 完成标准:1-2 句,描述性(非疑问) +2. **用 what if? 起头,写 3-5 个疑问句** + - 完成标准:至少 3 个不同角度的 what if? 句 + - 提示:试加"反转" / "限制" / "时间压力" / "对手介入" +3. **挑出最有戏剧张力的疑问句** + - 完成标准:选 1 个,并解释"为什么这个最有戏" + - 戏剧张力 = 角色 + 障碍 + 赌注 +4. **验证**:这个疑问句能展开成 30 万字吗? + - 完成标准:yes 走四问校验(references/four-questions.md),no 重新写 + +## 边界与失败模式 + +### 不要在以下情况使用 + +- 已经有完整 concept(用 references/four-questions.md 评估) +- 在优化叙事视角(用 references/delivery-strategy.md) +- 非小说写作 + +### 作者警告的失败模式 + +- 把"我想问 X"当 what if?——"我想问律师的道德"不是疑问句,是研究主题 +- what if? 句子里没有"障碍 / 赌注"——"如果律师是好人?"没戏 +- what if? 太多——只挑 1 个,不是 5 个 + +### 作者盲点 + +- 默认疑问句 = 西方式"个体困境",不适配集体 / 文化 / 宇宙级故事 +- what if? 假设写作者用英语——其他语言的疑问句构造不同 + +## 中文适配 + +- 中文疑问句用"如果/要是/倘若……会怎样?"起头,构造与 "What if...?" 功能相同,不需要翻译腔的"如果有一天"式长定语。 +- 家族史诗、村志厂史、群像题材不一定从个体困境起问:可以把疑问抬到集体层面——"如果这个家族……""如果这个村子……";也可以不硬造虚构疑问,直接走 references/delivery-strategy.md,用"通过谁的眼睛讲"当概念。 +- 中文网文里疑问句的赌注常挂在长线悬念上(升级、复仇、真相),验证"能不能撑 30 万字"时要按连载体量算,参见 references/four-questions.md 的中文适配。 + +## 与其他方法的关系 + +- **校验**:concept 成型后用四问校验 → references/four-questions.md。 +- **真实素材**:真实事件 / 非虚构素材不必硬造虚构 what if → references/delivery-strategy.md。 +- **引擎**:这个疑问句同时就是全书要回答的问题——概念在诞生时是 what if,在运行时是引擎 → references/story-engine.md。 +- **易混方法论**:Snowflake Method 的"一句话前提"——那是 premise 不是 concept;Logline 公式——那是概念 + 主角 + 冲突,已经到 premise 阶段。 diff --git a/framework/catalog/dsh/skills/dialogue-craft/SKILL.md b/framework/catalog/dsh/skills/dialogue-craft/SKILL.md new file mode 100644 index 0000000..61f9307 --- /dev/null +++ b/framework/catalog/dsh/skills/dialogue-craft/SKILL.md @@ -0,0 +1,115 @@ +--- +name: dialogue-craft +description: | + 激活场景:写或改小说对话——用户说"我对话写不好"、"对话太书面、像论文答辩"、 + "对话全是 X 说 Y 说"、"所有角色说话一个声音"、"对话推动不了情节"、 + "不知道什么时候用对话什么时候用叙述"、"对话只是在传递信息"、"对话没张力"、 + "对话写得像答辩"、"写了一整章对话情节没推进"、"权力博弈场景对话没张力"、 + "对话怎么暴露人物、怎么改变权力关系"。 + 关键 trigger:"对话写不好"、"对话太书面"、"对话像答辩"、"什么时候用对话"、 + "对话一个声音"、"对话推动情节"、"X说Y说"、"对话没张力"、"对话太碎/太满"、 + "对话即行动"、"dialogue as action"、"对话和引语的区别"、"dialogue vs quote"、 + "对话暴露人物"、"对话改变权力"、"小说对话技巧"。 + 不适用于:说明文/议论文;访谈记录与会议实录(非虚构对话是转录,不是小说); + 剧本(两书冲突保留:布兰德认为对白即剧本全体、无需判断何时用;克拉克源单元声明 + 适用于写剧本;见 references/boundaries-and-pitfalls.md 适用范围节); + 纯抒情与内心独白(规则不同,见 narration-pov); + 无对话的纯动作戏(见 scene-craft);辩论稿与演讲稿(目标是说服,不是"做事"); + 用户整篇不会写(那是 story-planning 的活);对话只是其中一部分、想整体优化 + (先把稿子放一边、隔夜重读做整篇优化,不在对话层面修)。 + 与 character-presentation 交接:登场呈现与"过程发现"归后者;说话方式、句长、口头禅、同一声音诊断归本 Skill。 +--- + +# 对话写作(dialogue-craft) + +把对话当事件写:先判断该不该用对话,再给每段对话派任务、给每个角色定声音、磨出真人质感、控好节奏、删掉标签让读者偷听。 + +## 方法索引 + +按创作动作组织;方法细节、案例、引文都在 references 里,这里只给一句话和指针。 + +### 判断:这段该不该用对话 + +- 对话是故事在高潮处的"喷涌",冲突与高潮必用,密度可达 50%-80% → references/when-to-use-dialogue.md +- 对话是"在场发生",事后补话是引语:判断一句话是"上方传来"还是"在场发生" → references/when-to-use-dialogue.md +- 信息、背景、前情交给叙述/独白/闪回,别让角色用嘴讲设定 → references/when-to-use-dialogue.md +- 对话还是叙述,按 7 行速查表定(冲突用对话、信息用叙述、过渡看隐含冲突) → references/when-to-use-dialogue.md + +### 派任务:每段对话都要做事 + +- 对话不是装饰,是事件:推进关系、改变权力、揭示人物三件事至少做一件 → references/dialogue-does-things.md +- 好对话是不同目标与价值观的碰撞,互相分享信息的对话改用叙述 → references/dialogue-does-things.md +- 闲聊也要藏东西:表面聊童年实际在比"谁更惨",纯寒暄删掉 → references/dialogue-does-things.md +- 案例:《卡瓦利与克雷的神奇冒险》开篇一句"什么是漫画书?"一次做实关系、性格与氛围 → references/dialogue-does-things.md + +### 建声音:每个角色说话像那个人 + +- 句长、用词、节奏随年龄、教育、性格走,内向的人句子更短 → references/character-voice.md +- 让人物自己暴露:删掉叙述者说明,看对话本身能不能让读者懂 → references/character-voice.md +- 给每个角色固定语言习惯,至少 2 个区别点:一个总说"反正",一个总说"你懂的" → references/character-voice.md +- 一个声音的诊断:把对话单独抽出来,看分不清是谁 → references/character-voice.md + +### 磨质感:对话要像真人说话 + +- 真人说话有半句话、重复、嗯嗯、打断;一样都没有的标准化台词是作者代笔 → references/real-speech-texture.md +- 反书面化也反"太真实":不能是"我非常感谢你的意见",也不是逐字录音 → references/real-speech-texture.md +- 教科书式对话(ce24)的信号:说整句、不重复、不卡顿、不用俚语 → references/real-speech-texture.md +- 中文适配:语气词密度、翻译腔与公文腔信号 → references/real-speech-texture.md + +### 控节奏:对话的快与慢 + +- 短对话加叙述增强时间感,长独白不如短的来回交换 → references/rhythm-and-density.md +- 一页纸切成数不清的小段对话 = 时间快,大段叙述 = 时间慢 → references/rhythm-and-density.md +- 短对话比长独白有力:海明威的对话几乎都是 1-6 个字 → references/rhythm-and-density.md +- 对话是读者的"通风口":伦纳德"删除读者会跳过的部分",对话恰是读者不跳过的 → references/rhythm-and-density.md + +### 删标签:让读者偷听 + +- "X 说 Y 说"挂满标签节奏被切碎,"他严肃地说"把读者推出场景 → references/tags-and-attribution.md +- 用动作、环境、段落归属替代:"她把茶杯摔在桌上"比"她生气地说"传达得多 → references/tags-and-attribution.md +- 量化标准:一段来回"X 说"不超过 2-3 次,中介标签 ≤ 30% 对话 → references/tags-and-attribution.md +- 中文适配:中文"说"无变位,删标签必须补动作节拍,语气词节奏别删丢 → references/tags-and-attribution.md + +### 诊断与改写 + +- 五病诊断(太书面/标签多/一个声音/推不动/不知何时用)+ 克拉克四步逐段诊断 + 布兰德五步改写 → references/execution-flow.md +- 逐段过稿的可执行清单 → references/dialogue-revision-checklist.md + +### 边界与误区 + +- 适用范围声明(克拉克侧 frontmatter)、剧本适用性两书冲突保留、不适用场景(含"对话只是其中一部分、想整体优化"分流)、两书警告的失败模式、盲点(网文对话、多人对话归属)、易混方法与相邻 skill 区分 → references/boundaries-and-pitfalls.md + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|---------| +| references/when-to-use-dialogue.md | 布兰德 R 段"喷涌"原文、克拉克 R 段 quote/dialogue 原文、三条原则、引语 vs 对话二分与"上方传来/在场发生"判断标准、三个使用场景、对话 vs 叙述速查表、"信息不是对话的活"两书合并点、视角差异注记 | +| references/dialogue-does-things.md | 对话是事件、三大功能(推进关系/改变权力/揭示人物)、碰撞原则、闲聊藏东西、信息反例两条、查邦《卡瓦利与克雷》案例全文、《红楼梦》王熙凤中文案例 | +| references/character-voice.md | 三种声音全文、固定语言习惯与 2 个区别点标准、同一声音诊断与修、布兰德课堂 24 个故事案例、中文声音区分工具与王熙凤例 | +| references/real-speech-texture.md | 克拉克规则 3 与加质感执行、教科书式对话 ce24 全文、布兰德错误 2 全文与例句、不书面也不过真实的平衡、中文适配(语气词密度、翻译腔/公文腔信号、中文真话质感) | +| references/rhythm-and-density.md | 时间感原则全文、密度 50%-80%、海明威 1-6 字案例全文、伦纳德"通风口"案例全文、两书节奏链合并 | +| references/tags-and-attribution.md | 布兰德错误 1 全文、克拉克规则 2、去中介标签执行与茶杯例句、2-3 次与 ≤30% 双标准合并表、多人对话归属补充、中文适配(无变位归属、副词标签、语气词情绪) | +| references/execution-flow.md | 布兰德诊断五问与两条判停路由("我都不会写"→ story-planning;"想整体优化"→ 写后阶段)、克拉克 E 段四步全文、布兰德 E 段六步全文、"两个自我对话"批评法案例、日常训练汇总、两套流程衔接说明 | +| references/boundaries-and-pitfalls.md | 克拉克侧适用范围声明全文(写小说/写剧本/写场景戏/人物对白设计/对话节奏校准)与剧本适用性冲突注记(两书冲突都保留)、两书激活场景与语言信号全文、不适用边界 10 条、失败模式 6 条、盲点 7 条(含网文/微信对话体)、易混邻近方法论、相邻 skill 区分与相关 skills 指针 | +| references/_coverage.md | 两个源单元的覆盖对照表 | + +## 脚本 + +| 脚本 | 用途 | +|------|------| +| references/dialogue-revision-checklist.md | 对话改写检查清单:定病 → 逐段功能标注/在场检查 → 整场时机密度/声音区分/质感/标签计数/节奏复查 → 完稿纪律,逐条打钩过稿 | + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/dsh/skills/dialogue-craft/references/_coverage.md b/framework/catalog/dsh/skills/dialogue-craft/references/_coverage.md new file mode 100644 index 0000000..ad59291 --- /dev/null +++ b/framework/catalog/dsh/skills/dialogue-craft/references/_coverage.md @@ -0,0 +1,22 @@ +# dialogue-craft 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| becoming-a-writer/fiction-dialogue | references/when-to-use-dialogue.md | +| becoming-a-writer/fiction-dialogue | references/rhythm-and-density.md | +| becoming-a-writer/fiction-dialogue | references/character-voice.md | +| becoming-a-writer/fiction-dialogue | references/real-speech-texture.md | +| becoming-a-writer/fiction-dialogue | references/tags-and-attribution.md | +| becoming-a-writer/fiction-dialogue | references/dialogue-does-things.md | +| becoming-a-writer/fiction-dialogue | references/execution-flow.md | +| becoming-a-writer/fiction-dialogue | references/boundaries-and-pitfalls.md | +| writing-tools-clark/dialogue-as-action | references/when-to-use-dialogue.md | +| writing-tools-clark/dialogue-as-action | references/dialogue-does-things.md | +| writing-tools-clark/dialogue-as-action | references/real-speech-texture.md | +| writing-tools-clark/dialogue-as-action | references/tags-and-attribution.md | +| writing-tools-clark/dialogue-as-action | references/rhythm-and-density.md | +| writing-tools-clark/dialogue-as-action | references/character-voice.md | +| writing-tools-clark/dialogue-as-action | references/execution-flow.md | +| writing-tools-clark/dialogue-as-action | references/boundaries-and-pitfalls.md | diff --git a/framework/catalog/dsh/skills/dialogue-craft/references/boundaries-and-pitfalls.md b/framework/catalog/dsh/skills/dialogue-craft/references/boundaries-and-pitfalls.md new file mode 100644 index 0000000..e21c013 --- /dev/null +++ b/framework/catalog/dsh/skills/dialogue-craft/references/boundaries-and-pitfalls.md @@ -0,0 +1,160 @@ +# 边界、失败模式、盲点与相邻区分 + +来源:(多萝西娅·布兰德,《成为作家》第八章 + 第十章 + 第十一章 的 A2 与 B 段);(Roy Peter Clark,《Writing Tools: 55 Essential Strategies for Every Writer》Tool 26 的 A2 与 B 段) + +## 激活场景与语言信号 + +### 布兰德侧() + +用户会在什么情境下需要: + +1. **"我对话写不好"**——经典信号 +2. **"我对话太'说人话'/太书面"**——风格问题 +3. **"我对话总是'X 说 Y 说'"**——标签病 +4. **"我不知道什么时候用对话什么时候用叙述"**——决策问题 +5. **"我对话推动不了情节"**——对话无功能 +6. **"我对话里的人都一个声音"**——区分度问题 +7. **"我对话写得太满/太碎"**——密度问题 +8. **"我想让对话有'喷涌'感"**——风格目标 + +语言信号(用户的话里出现这些就应激活): + +- "对话写不好" +- "对话太书面" +- "什么时候用对话" +- "对话一个声音" +- "对话推动不了情节" +- "X说Y说" +- "对话没张力" +- "对话太碎/太满" + +源 frontmatter 的询问式触发词同等激活:"对话怎么写"、"小说对话技巧"、"什么时候用对话"。其中"什么时候用对话"已在上述清单,"对话怎么写"与克拉克侧"如何写对话"同义;"小说对话技巧"原包无对应信号,本次核验补录。() + +### 克拉克侧() + +用户会在什么情境下需要: + +1. 写对话时觉得"读起来像论文答辩"——人物都在说整句、不重复、不卡顿。 +2. 写了一整章对话,但情节没推进——读者跳读或弃读。 +3. 不知道一段话该用"引号 + X 说道"还是让人物在场景里说。 +4. 写到权力博弈场景(谈判、对质、审讯、家庭冲突)时,对话读起来没张力。 +5. 问"对话如何暴露人物性格"——而不是用旁白告诉读者"他很冷酷"。 + +语言信号: + +- "对话写得像答辩" +- "对话推进不了情节" +- "对话只是传递信息" +- "dialogue as action" / "对话即行动" +- "dialogue vs quote" / "对话和引语的区别" +- "对话如何暴露人物" +- "如何写对话" +- "写对话没张力" + +## 适用范围(源单元 frontmatter 声明) + +### 克拉克侧() + +源单元 frontmatter 声明的适用范围,全量保留:**写小说、写剧本、写场景戏、人物对白设计、对话节奏校准**。() + +布兰德源单元 frontmatter 未列适用范围声明,只列不适用分流(见下文"不适用边界"布兰德侧)。() + +**规则冲突(两书冲突都保留,标注冲突与各自出处)**——"写剧本"的适用性两书冲突: + +- 克拉克侧:frontmatter 适用范围含**写剧本**。() +- 布兰德侧:**写剧本**列入不适用——"剧本对话是唯一内容,不需要'什么时候用对话'的判断"。() + +两条都保留,不做单边裁决。使用指引:写剧本时打磨对白本身(对白质量、人物声音、节奏、删标签),本 skill 的方法可用(克拉克侧);布兰德侧不适用的是"什么时候用对话"这一判断——剧本对白即全体,references/when-to-use-dialogue.md 的时机框架与速查表对剧本没有适用空间。 + +## 不适用边界 + +### 布兰德侧() + +- **用户不知道怎么写故事**——那是 story-draft-flow(已并入综合 skill `story-planning`) +- **对话只是其中一部分,想整体优化**——那是写后阶段:对话只是稿子问题的一部分、用户要的是整篇整体优化时,不在对话技术层面修,先把稿子放一边再做整体优化 +- **写非虚构对话**(访谈/会议记录)——那是 transcript,不是 fiction +- **写剧本**——剧本对话是唯一内容,不需要"什么时候用对话"的判断(冲突注记:克拉克源单元 frontmatter 声明"适用于写剧本",两书冲突都保留,见上文"适用范围"节) +- **写诗/散文**——对话不是主要工具 +- **用户已经能写好对话**——这是基础技术,不是优化 + +### 克拉克侧() + +- **纯抒情独白 / 内心独白**——这是"内心 dialogue",规则不同(参见 mix-narrative-modes 的 broken line;该单元在综合 skill `narration-pov`) +- **纯动作戏(无对话)**——没有对话可优化,改用 cinematic-distances(该单元在综合 skill `scene-craft`) +- **说明文 / 议论文**——角色对话的功能性差异不适用 +- **辩论稿 / 演讲稿**——目标是说服,不是"做事";Clark 的"做事"标准会让辩论稿被错判 + +## 失败模式 + +### 布兰德警告的失败模式() + +- **"X 说 Y 说"标签**——节奏断,读者疲倦(→ references/tags-and-attribution.md) +- **对话太书面化**——失真,像"教课"(→ references/real-speech-texture.md) +- **对话都是同一声音**——失角色化(→ references/character-voice.md) +- **用对话传递信息**——说教化(→ references/dialogue-does-things.md) +- **模仿别人的对话风格**(ce02)——永远追不上(→ references/character-voice.md) + +### 克拉克警告的失败模式() + +- **"教科书式"对话(ce24)**:失败模式是写人物对话像"论文答辩"——"你是否同意 X 观点?""是的,因为……"。信号:对话中人物都"说整句、不重复、不卡顿、不用俚语"。机制:真实对话充满"半句话、重复、嗯嗯、打断";标准化对话是"作者代笔"而非"人物说话"。(全文 → references/real-speech-texture.md) + +## 盲点与时代局限 + +### 布兰德的盲点() + +- **1934 年的"对话"偏文学**——类型小说(悬疑/科幻/言情)的对话有不同要求 +- **不区分"第一人称对话"/"全知对话"**——视角影响对话限制 +- **没考虑"网文对话"**——网络连载的对话节奏更快,信息密度更高 +- **没考虑"多人对话"**——3 人以上对话的归属难题,布兰德没细说(中文落地补充 → references/tags-and-attribution.md) +- **"对话暴露人物"假设每个角色都有"真实"性格**——有时角色是"工具人",不必太深 + +### 克拉克的盲点() + +- Clark 的对话理论在**中文小说**中的迁移需要本地化:中文的"嗯"、"这个"、"那个"等语气词比英文对话标签更密集,直接套用"去中介标签"会丢失中文对话的特殊节奏。(中文适配,落地 → references/tags-and-attribution.md) +- 时代局限:Clark 写于 2006 年(英文版),未涵盖**网文 / 微信对话体**——这些是 2010 年后兴起的对话形式,有自己的一套"动作化"机制(括号表情、截图、撤回)。 + +## 容易混淆的邻近方法论 + +两本书各列一份,合并保留(show don't tell 两书都提,各自视角都留): + +### 布兰德侧() + +- **"Show don't tell"**——是大原则,对话是 show 的一种工具(跨域指针:综合 skill `show-and-omission`) +- **"潜台词"(Subtext)**——高级技术,角色不说"真话",读者自己懂 +- **"对话作为独白"(Soliloquy)**——是戏剧技术,不是小说主流 + +### 克拉克侧() + +- 与 "show, don't tell"(Tool 27):那个管"用动作和细节显示人物",这个管"对话的功能化"——前者是"如何写一个画面",后者是"如何让声音做事"。(跨域指针:综合 skill `show-and-omission`) +- 与 "active verbs"(Tool 3):那个管"动词的力度",这个管"对话作为动词事件"——前者是"句法",后者是"叙事事件类型"。 + +## 与相邻 skill 的区分 + +跨域引用只留一句话指针: + +### 布兰德侧() + +- **与 `fiction-opening` 的区别**:fiction-opening 是"怎么写第一句"(包括用对话);fiction-dialogue 是"怎么用对话"的整体技术。前者是局部,后者是贯穿。(fiction-opening 已并入综合 skill `story-structure` 的开篇段) +- **与 `fiction-scene-craft` 的区别**:fiction-dialogue 是"对话"这个工具;fiction-scene-craft 是"场景/节奏"这个整体。前者是工具,后者是框架。(fiction-scene-craft 已并入综合 skill `scene-craft`) +- **与"模仿技术而非风格"的区别**:那个教"学别人的对话节奏";本 skill 教"自己写对话"。前者是模仿,后者是原创。(该方法未入本技能库,区分条目按原文保留) + +### 克拉克侧() + +- 与 `mosaic-of-detail` 的区别:那个用"具体物清单"显示人物,这个用"对话做的事"显示人物——前者是"物品语言",后者是"声音语言"。(mosaic-of-detail 在综合 skill `character-presentation`) +- 与 `voice-equalizer` 的区别:那个管"作者声音的杠杆"(节奏、句长、词汇),这个管"角色声音的功能"(让对话推进情节)。(voice-equalizer 在综合 skill `prose-craft`) +- 与 `mix-narrative-modes` 的区别:那个是"主线 / 折线 / 蒙太奇"等叙事模式调度,这个专注对话作为单一模式的功能最大化。(mix-narrative-modes 在综合 skill `narration-pov`) + +## 相关 skills(原书登记,指针化) + +### 布兰德侧() + +- **composes-with** `fiction-opening`:方法 2(对话开头)的延伸(→ `story-structure`) +- **composes-with** `fiction-scene-craft`:对话是场景的一部分(→ `scene-craft`) +- **composes-with**"作者的双重自我":角色差异化来自作者的多视角(该方法未入本技能库,关系条目按原文保留) +- **composes-with** `story-draft-flow`:阶段 4-5 的内部技术(→ `story-planning`) + +### 克拉克侧() + +- depends-on:无 +- contrasts-with:`mosaic-of-detail`(用"物"显示人物 vs 用"声音"显示人物)(→ `character-presentation`) +- composes-with:`cinematic-distances`(对话放在哪个镜头距离?)(→ `scene-craft`)、`voice-equalizer`(对话的语言风格统一)(→ `prose-craft`) diff --git a/framework/catalog/dsh/skills/dialogue-craft/references/character-voice.md b/framework/catalog/dsh/skills/dialogue-craft/references/character-voice.md new file mode 100644 index 0000000..5d50239 --- /dev/null +++ b/framework/catalog/dsh/skills/dialogue-craft/references/character-voice.md @@ -0,0 +1,87 @@ +# 角色声音:让每个人说的话像那个人 + +来源:(多萝西娅·布兰德,《成为作家》第八章 + 第十章 + 第十一章);与 的"揭示人物"功能合并 + +## 布兰德的三种声音 + +角色对话的差异化,布兰德给了三种声音。() + +### 声音 1:"听上去像那个人" + +- 每个角色说话的**节奏/用词/句长**应该**像那个人** +- 老人说话 vs 年轻人说话:句长不同,用词不同 +- 受过教育 vs 没受过教育:词汇量不同 +- 性格内向 vs 外向:句子长度不同(内向更短) +- **怎么练**:第二遍阅读时,标出不同角色的对话,听"他们声音不同吗" + +() + +### 声音 2:"暴露人物" + +- 好的对话,**让人物**自己暴露性格/价值观/关系 +- 不需要"叙述者说:他很紧张"——让他说话时暴露 +- 例:"我没想伤害她,我只是想——"(暴露:内疚,怕被拒绝) +- **怎么练**:写完对话,删掉"叙述者说明",看对话本身能不能让人懂 + +() + +两本书在这条上合并:Clark 把"揭示人物"列为对话"做事"的三大功能之一(推进关系 / 改变权力 / 揭示人物),并反对用旁白代替暴露——"而不是用旁白告诉读者'他很冷酷'"。() + +### 声音 3:"推动情节" + +- 好的对话,**让情节前进一步** +- 不是"闲话"——不是角色聊天气/吃饭/与情节无关 +- 哪怕是"闲聊",也**隐含**着冲突/价值观 +- 例:两个角色聊童年——表面是闲聊,实际在对比"谁更惨" + +(;与 Clark"推进关系/改变权力"合并,展开见 references/dialogue-does-things.md) + +## 给每个角色固定语言习惯 + +修法与量化标准:() + +- **怎么修**(发现一个声音之后):给每个角色**固定的语言习惯**(口头禅/句长/用词) +- 例:一个人总说"反正",另一个人总说"你懂的"——这就是区分 +- 执行标准:能列出 2-3 个角色的"口头禅/句长/用词";至少 2 个区别点(口头禅/句长) +- 例:角色 A 总说"反正",角色 B 总说"你懂的" + +() + +## "同一个声音"的诊断与修 + +这是布兰德列的对话三大常见错误之一(错误 3),全量保留:() + +- **错误 3:对话都是"同一个声音"** +- 全部角色用**作者的口吻**说话——那是因为作者没用"不同的声音" +- 怎么发现:把对话单独抽出来,看每段是不是能**区分**是谁 +- **怎么修**:给每个角色**固定的语言习惯**(口头禅/句长/用词) +- 例:一个人总说"反正",另一个人总说"你懂的"——这就是区分 + +() + +## 案例全文:布兰德的课堂实验——同一提纲 24 个故事 + +- **问题**:不知道怎么让故事有"自己的声音" +- **方法论的使用**:同一提纲,24 个学生写 24 个故事,每个对话声音都不同 +- **结论**:对话声音的差异 = 作者视角的差异 = 原创性 +- **结果**:学生发现自己对话的"声音",不必模仿别人 + +() + +由此引出的失败模式:**模仿别人的对话风格**(ce02)——永远追不上;对话声音的差异本身就是作者视角的差异,那是原创性。() + +## 中文适配与中文落地 + +(以下第 1 条为源单元原有内容,第 2-4 条为本次合并补充,标注"中文适配") + +1. Clark 的"揭示人物"在中文里同样成立:中文的"嗯"、"这个"、"那个"等语气词比英文对话标签更密集,用不用、怎么用这些词,本身就是人物声音的一部分。(,中文适配) +2. **中文区分声音的现成工具**(中文适配):称呼语与敬语(你/您、职称、老 X/小 X、亲属称谓)、语气词习惯(吧/呢/嘛/啊各人不同)、方言词与儿化音、书面语与口语的配比(有人张嘴就是成语,有人全是短句碎句)。给角色定语言习惯时,这些比"口头禅"更不容易写油。 +3. **中文范本**(中文适配):《红楼梦》第三回王熙凤出场,"我来迟了,不曾迎接远客!"——人未到声先到,一句话立住泼辣、得宠、越礼三层性格,是"听上去像那个人 + 暴露人物"的合一。判断标准照布兰德的来:遮住名字,读这句话能不能认出是谁。 +4. **网文与类型小说**(中文适配):网文对话节奏快、信息密度高,角色声音区分更要靠固定语言习惯——连载里读者跳着读,声音不稳的角色会互相混成一个人。 + +## 本主题常见误区 + +- **对话都是同一声音**——全用作者的口吻说话;用口头禅、句长、用词修,至少 2 个区别点。() +- **用叙述者说明代替暴露**——"他很紧张"式旁白;删掉旁白,看对话本身能不能让人懂。(;) +- **模仿别人的对话风格**(ce02)——追别人的声音永远追不上。() +- **"对话暴露人物"的适用前提**——假设每个角色都有"真实"性格;有时角色是"工具人",不必太深(布兰德的盲点之一,→ references/boundaries-and-pitfalls.md)。() diff --git a/framework/catalog/dsh/skills/dialogue-craft/references/dialogue-does-things.md b/framework/catalog/dsh/skills/dialogue-craft/references/dialogue-does-things.md new file mode 100644 index 0000000..87240b8 --- /dev/null +++ b/framework/catalog/dsh/skills/dialogue-craft/references/dialogue-does-things.md @@ -0,0 +1,69 @@ +# 给每段对话派任务:对话是事件,不是装饰 + +来源:(Roy Peter Clark,《Writing Tools: 55 Essential Strategies for Every Writer》Tool 26);(多萝西娅·布兰德,《成为作家》第八章 + 第十章 + 第十一章) + +## 核心命题:对话不是装饰,是事件 + +Clark 给场景写作的核心定位:**对话不是装饰,是事件。** 写对话要"做事"——推进关系 / 改变权力 / 揭示人物,而非传递信息。() + +## 对话的三大功能(克拉克规则 1) + +每段对话至少做成三件事里的一件:() + +1. **推进关系**——两人之间的距离、亲疏、攻守在这一段里发生了变化 +2. **改变权力**——谁占上风、谁被拿捏、谁翻盘,在这段话之后不一样了 +3. **揭示人物**——读者通过角色怎么说话,看清这个人是谁 + +执行方法:找出场景中所有对话,逐一问:"这段对话在做事吗?推进关系 / 改变权力 / 揭示人物,还是只是传递信息?"每段对话被标注"做事"或"传信息";只传信息且无法改写为"做事"的,标记为删除候选。(完整流程 → references/execution-flow.md)() + +## 好对话是碰撞,不是交换 + +布兰德从冲突角度说同一件事:() + +- 对话**不仅**强调冲突,**而且**制造冲突(原则 3,见 references/when-to-use-dialogue.md) +- 好的对话 = 角色在**不同的目标/价值观**上碰撞 +- 坏的对话 = 角色在"分享信息"——那应该用叙述 + +中文落地:中文小说里"碰撞"常藏在礼数底下——饭桌上客客气气的敬酒词,每句都在争座次、争面子、争话语权;写碰撞不一定要吵架,把目标和价值观的对立压进客套话里,张力反而更大。(中文落地说明,方法出自) + +## 闲聊也要藏东西 + +哪怕写的是"闲聊",也得隐含冲突或让情节前进一步:() + +- 好的对话,**让情节前进一步** +- 不是"闲话"——不是角色聊天气/吃饭/与情节无关 +- 哪怕是"闲聊",也**隐含**着冲突/价值观 +- 例:两个角色聊童年——表面是闲聊,实际在对比"谁更惨" + +() + +## 信息不是对话的活:让角色用嘴交代背景是最糟的"告诉" + +两本书在这条上合并:(;) + +- 布兰德:需要**传递信息**(背景/前情/设定)时,**不要**用对话——那是"告诉"的最糟方式;用叙述/独白/闪回。() +- Clark:引语(quote)提供信息与解释,对话(dialogue)让情节变厚;信息是引语和叙述的活,不是对话的活。() + +反例两个,照原样保留:() + +- 例:不要用两个角色说"你知道吗,上世纪 90 年代我们..." +- **反例**:"老师对学生说:'写作需要想象力...'"——这是说教,不是故事 + +## 案例全文:查邦《卡瓦利与克雷的神奇冒险》对话开篇 + +Michael Chabon《Kavalier & Clay》对话开篇(Clark 评价"对话即行动"的金标准案例):() + +- **问题**:如何在第一章就让人物关系"瞬间定型"? +- **方法论的使用**:Chabon 让 Joe 和婶婶的对话从"什么是漫画书?"开始——表面温和,每个动作("head down", "shoulder against the door frame")都在场景中"做事",同时揭示 Joe 的羞涩、婶婶的惊讶、家族氛围。 +- **结论**:对话是"角色正在发生的事件",读者通过偷听获得信息,而非被告知。 +- **结果**:成为了 Clark 评价"对话即行动"的金标准案例;展示了"开篇对话 = 关系 + 性格 + 氛围"的复合功能。 + +() + +中文落地:中文开篇对话做复合功能的经典样本是《红楼梦》第三回王熙凤出场——人没到,"我来迟了,不曾迎接远客!"先到:一句话同时做了三件事,立住人物声音(揭示人物)、压住全场辈分秩序(改变权力)、让黛玉和读者瞬间知道这个人在家族里的位置(推进关系)。写中文开篇对话可以照这个标准自查:这一句做了几件事?只做"传递信息"一件事的,改。(中文适配:中文案例补充,判断标准出自) + +## 常见误区(本主题相关) + +1. **用对话的嘴传信息**——"你知道吗,上世纪 90 年代……"式对话是说教,不是故事;信息交给叙述。(;) +2. **拿闲聊当对话**——"今天天气真好"直接删;日常对话得透出人物真正的担忧再用。() +3. **写了一整章对话,情节没推进**——读者跳读或弃读;每段对话都要过"做事还是传信息"的标注。() diff --git a/framework/catalog/dsh/skills/dialogue-craft/references/dialogue-revision-checklist.md b/framework/catalog/dsh/skills/dialogue-craft/references/dialogue-revision-checklist.md new file mode 100644 index 0000000..a334795 --- /dev/null +++ b/framework/catalog/dsh/skills/dialogue-craft/references/dialogue-revision-checklist.md @@ -0,0 +1,96 @@ +# 对话改写检查清单 + +> 把两个源单元的可执行步骤串成一份逐段过稿清单:先定病,再逐段过功能、在场、质感、标签,最后整场复查。 +> 方法全文见 [references/execution-flow.md](execution-flow.md);速查表见 [references/when-to-use-dialogue.md](when-to-use-dialogue.md)。 + +## 〇、定病:这段对话的问题是哪一种 + +先回答(): + +- [ ] (a) 太书面?→ 重点过第五节 +- [ ] (b) 标签太多?→ 重点过第六节 +- [ ] (c) 一个声音?→ 重点过第四节 +- [ ] (d) 推动不了情节?→ 重点过第一、二节 +- [ ] (e) 不知道什么时候用?→ 先对第八节速查表 +- [ ] 判停:若"我都不会写"——问题不在对话,在整篇流程,先走 story-planning +- [ ] 判停:若对话只是其中一部分、想整体优化——不在对话层面修,走写后阶段:先把稿子放一边再做整体优化 + +## 一、功能标注(逐段) + +找出场景中所有对话,逐段问(): + +- [ ] 这段对话在做事吗?——推进关系 / 改变权力 / 揭示人物,还是只是传递信息? +- [ ] 每段都已标注"做事"或"传信息" +- [ ] 只传信息且改写不成"做事"的,已列为删除候选 +- [ ] 表面闲聊的段落,确认隐含冲突或让情节前进一步(两角色聊童年 = 在比"谁更惨")() +- [ ] 没有用对话的嘴交代背景/前情/设定("你知道吗,上世纪 90 年代我们..."式句子已改为叙述)() + +## 二、在场检查(逐段) + +对每段保留的对话问(): + +- [ ] 这句话是"在场发生"(dialogue)还是"事后补话"(quote)? +- [ ] "事后补话"已改写为当下场景,或转叙述/动作/内心独白 +- [ ] 判停:需要"事后才知道"的内容,改成当下场景或转 narrator 描述,不保留"事后补话"形式 + +## 三、时机与密度(整场) + +对照速查表与三场景框架(): + +- [ ] 冲突/高潮段落用了对话,密度在 50%-80% +- [ ] 信息/说明段落交给叙述、独白或闪回,没有让角色用嘴讲课 +- [ ] 日常/过渡段落的对话隐含冲突;纯"今天天气真好"已删 + +## 四、声音区分度(整场) + +- [ ] 把对话单独抽出来,能分清每段是谁说的() +- [ ] 每个主要角色有固定语言习惯(口头禅/句长/用词),至少 2 个区别点(角色 A"反正"/角色 B"你懂的")() +- [ ] 句长、用词、节奏贴合人物的年龄、教育、性格(内向更短)() +- [ ] 删掉叙述者说明后,对话本身仍能让读者懂人物("我没想伤害她,我只是想——"自带内疚);不懂的段落回头加动作() + +## 五、质感检查(逐段) + +- [ ] "做事"对话中已插入 1-2 处"半句话/重复/嗯/打断/俚语"() +- [ ] 改写后至少 1 处非标准化表达(口音、停顿、思维跳跃、方言词)() +- [ ] 没有"论文答辩"式对白——"你是否同意 X 观点?""是的,因为……"(ce24 信号:说整句、不重复、不卡顿、不用俚语)() +- [ ] 没有"我非常感谢你的意见"式书面台词() +- [ ] 判停:插入质感后通读,确认不像台词剧本、不是逐字录音(;) +- [ ] 中文自查:无翻译腔("哦,我的天"、代词用满)、无公文腔(会议体家常话)(中文适配:本次合并补充) + +## 六、标签计数(逐段 + 全篇) + +- [ ] 一段来回里"X 说"不超过 2-3 次() +- [ ] 中介标签 ≤ 30% 对话,其余用动作/沉默/表情替代() +- [ ] "他严肃地说""她解释道"式副词标签已换成动作("她把茶杯摔在桌上")() +- [ ] 归属不清处用段落归属 + 动作节拍补上,不只删不补(;中文适配:中文"说"无变位,删标签要补动作) +- [ ] 中文语气词节奏没被删丢("嗯/这个/那个"比英文标签密,删过头对话失掉自身节奏)(,中文适配) + +## 七、节奏复查(整场) + +- [ ] 高潮段对话切成短交换,没有拖节奏的长独白() +- [ ] 对话与叙述的配比让页面有"通风口"——读者会跳过的部分已删(伦纳德标准)() +- [ ] 大段叙述没有压在需要快的段落上(切小段 = 时间快,大段叙述 = 时间慢)() + +## 八、对话 vs 叙述速查表 + +| 场景 | 优先用 | +|---|---| +| 冲突/高潮 | 对话 | +| 信息/说明 | 叙述 | +| 动作/事件 | 叙述 | +| 思考/感受 | 叙述或内心独白 | +| 角色关系/性格 | 对话(暴露) | +| 日常/过渡 | 看情况(隐含冲突才用) | +| 故事开头 | 可用对话(建声音)或不用 | + +() + +## 九、完稿纪律 + +- [ ] 写完立刻放一边,至少隔一夜再读对话 +- [ ] 重读时可用布兰德"两个自我对话"批评法:一个自我写,一个自我批,用对话形式逐段审,比独白式自查更具体、不极端 + +## 日常训练(不在改稿时用) + +- [ ] 第二遍阅读时标出不同角色的对话,听他们声音是否不同() +- [ ] 听身边人说话,录下来,看真实的说法长什么样() diff --git a/framework/catalog/dsh/skills/dialogue-craft/references/execution-flow.md b/framework/catalog/dsh/skills/dialogue-craft/references/execution-flow.md new file mode 100644 index 0000000..54251c5 --- /dev/null +++ b/framework/catalog/dsh/skills/dialogue-craft/references/execution-flow.md @@ -0,0 +1,96 @@ +# 诊断与改写流程:从"我的对话哪里病了"到逐段修完 + +来源:(Roy Peter Clark,《Writing Tools: 55 Essential Strategies for Every Writer》Tool 26 的 E 段四步);(多萝西娅·布兰德,《成为作家》第八章 + 第十章 + 第十一章 的 E 段六步) + +两套流程合并使用:克拉克四步管"逐段诊断"(每段对话做什么、是不是在场、有没有质感、标签多不多),布兰德六步管"定病 + 逐段改写 + 完稿纪律"。可执行版清单 → references/dialogue-revision-checklist.md。 + +## 第 0 步:诊断入口——用户的对话问题在哪(布兰德 E 步骤 1) + +全量保留:() + +- 完成标准:用户能指出"我的对话是 X 问题" +- 提问:"你的对话问题是——(a) 太书面?(b) 标签太多?(c) 一个声音?(d) 推动不了情节?(e) 不知道什么时候用?" +- 判停条件:若用户说"我都不会写" → 路由到 `story-planning` 的起草流程阶段 1,不在本 skill 内解决 +- 判停条件:若用户的问题里对话只是其中一部分、想整体优化 → 走写后阶段:不在对话技术层面修,先把稿子放一边再做整篇优化 + +各病对应的治法入口: + +| 病 | 治法入口 | +|---|---| +| (a) 太书面 | references/real-speech-texture.md | +| (b) 标签太多 | references/tags-and-attribution.md | +| (c) 一个声音 | references/character-voice.md | +| (d) 推动不了情节 | references/dialogue-does-things.md | +| (e) 不知道什么时候用 | references/when-to-use-dialogue.md | + +## 克拉克四步:逐段功能诊断(全量保留) + +() + +1. **诊断对话的功能** + - 找出场景中所有对话,逐一问:"这段对话在做事吗?推进关系 / 改变权力 / 揭示人物,还是只是传递信息?" + - 完成标准:每段对话被标注"做事"或"传信息";只传信息且无法改写为"做事"的,标记为删除候选。 + +2. **判断引语 vs 对话** + - 对每个被保留的对话,问:"这句话是角色在场景里说的(dialogue),还是事后补话(quote)?" + - 完成标准:每段对话的角色定位明确——"在场说话"或"事后补话";"事后补话"被改写到"在场说话",或改用其他方式(内心独白、动作)。 + - 判停条件:若对话需要"事后才知道",应改成"当下场景",或转用 narrator 描述;不要保留"事后补话"形式。 + +3. **加生活质感** + - 在"做事"对话中插入 1-2 个"半句话 / 重复 / 嗯 / 打断 / 俚语"——让对话"听着像人"。 + - 完成标准:改写后的对话中至少 1 处非标准化表达(口音、停顿、思维跳跃、方言词)。 + - 判停条件:若场景中角色均为"标准话",插入 1-2 处后通读,确认不像台词剧本。 + +4. **去中介标签** + - 把"他严肃地说"、"她解释道"等中介标签删掉,用动作标签替代("她把茶杯摔在桌上")。 + - 完成标准:中介标签 ≤ 30% 对话;其余用动作 / 沉默 / 表情替代。 + +## 布兰德五步:改写执行(E 步骤 2-6,全量保留) + +() + +1. **第一步:选好"什么时候用对话"** + - 完成标准:用户能用"3 个使用场景"框架判断 + - 关键:冲突/高潮必用,信息/说明用叙述,日常/过渡看情况 + +2. **第二步:给每个角色"固定语言习惯"** + - 完成标准:用户能列出 2-3 个角色的"口头禅/句长/用词" + - 关键:至少 2 个区别点(口头禅/句长) + - 例:角色 A 总说"反正",角色 B 总说"你懂的" + +3. **第三步:写对话时减少"标签"** + - 完成标准:用户承诺"一段对话中,'X 说'不超过 2-3 次" + - 关键:用动作/环境/段落归属代替标签 + +4. **第四步:检查对话"暴露人物/推动情节"** + - 完成标准:用户的每段对话,都**暴露**人物(性格/价值观)或**推动**情节 + - 检验:删掉叙述者说明,看对话本身能不能让读者懂 + +5. **第五步:写完不立即重读** + - 完成标准:用户承诺"写完后立刻放一边,至少隔一夜" + - 隔一夜再读对话,声音差异和标签问题才听得出来 + +## 案例全文:布兰德的"两个自我对话"批评法 + +布兰德 A1 案例 2,全量保留:() + +- **问题**:不知道如何自我批评 +- **方法论的使用**:假装是**两个**自己在对话(一个写得好,一个写得不好) +- **结论**:自我对话**用对话的形式**,比独白有效 +- **结果**:自我批评更具体,不会极端 + +用法:隔夜重读对话时,把"作者自我"和"批评者自我"分成两个声音对话,逐段审对话的声音、标签与功能。 + +## 日常训练(布兰德散见各条的"怎么练",汇总) + +() + +1. **第二遍阅读**时,标出不同角色的对话,听"他们声音不同吗"(声音 1 的练法,→ references/character-voice.md)。 +2. **写完对话,删掉"叙述者说明"**,看对话本身能不能让人懂(声音 2 的练法,→ references/character-voice.md)。 +3. **听身边人说话,录下来**,看你**真的**怎么说话(错误 2 的练法,→ references/real-speech-texture.md)。 + +## 两套流程的衔接说明(合并整合) + +- 顺序建议:先走克拉克四步(逐段过功能、在场性、质感、标签),再走布兰德五步里的第一、二步(时机框架、语言习惯)做整场复查——克拉克是逐段显微镜,布兰德是整场框架。 +- 两套完成标准都保留,不互相覆盖:克拉克的"≤ 30% 中介标签"与布兰德的"一段 2-3 次 X 说"分别计数(→ references/tags-and-attribution.md)。 +- 判停条件都保留:克拉克两处判停(事后补话的处理、质感插入后通读),布兰德两处判停("我都不会写"→ story-planning;"对话只是其中一部分、想整体优化"→ set-aside-the-manuscript 写后阶段,该单元已裁剪、路由注记保留)。 diff --git a/framework/catalog/dsh/skills/dialogue-craft/references/real-speech-texture.md b/framework/catalog/dsh/skills/dialogue-craft/references/real-speech-texture.md new file mode 100644 index 0000000..6828a3a --- /dev/null +++ b/framework/catalog/dsh/skills/dialogue-craft/references/real-speech-texture.md @@ -0,0 +1,59 @@ +# 真话质感:让对话像真人说话 + +来源:(Roy Peter Clark,《Writing Tools: 55 Essential Strategies for Every Writer》Tool 26);(多萝西娅·布兰德,《成为作家》第八章 + 第十章 + 第十一章) + +两本书在这条上合并:Clark 的规则 3(避免论文化)与布兰德的错误 2(太书面化/太完美)说的是同一件事,合并一条,各自视角与例句全部保留。 + +## 克拉克规则 3:避免论文化 + +真实对话有"半句话、重复、嗯嗯、打断";标准化对话是作者代笔,不是人物。() + +执行(加生活质感):在"做事"对话中插入 1-2 个"半句话 / 重复 / 嗯 / 打断 / 俚语"——让对话"听着像人"。完成标准:改写后的对话中至少 1 处非标准化表达(口音、停顿、思维跳跃、方言词)。判停条件:若场景中角色均为"标准话",插入 1-2 处后通读,确认不像台词剧本。() + +## 失败模式全文:教科书式对话(ce24) + +Clark 在书中警告的失败模式,全量保留:() + +- **"教科书式"对话(ce24)**:失败模式是写人物对话像"论文答辩"——"你是否同意 X 观点?""是的,因为……"。信号:对话中人物都"说整句、不重复、不卡顿、不用俚语"。机制:真实对话充满"半句话、重复、嗯嗯、打断";标准化对话是"作者代笔"而非"人物说话"。 + +对应激活场景:写对话时觉得"读起来像论文答辩"——人物都在说整句、不重复、不卡顿。() + +## 布兰德错误 2:对话太"书面化"/太"完美" + +全量保留:() + +- **错误 2:对话太"书面化"/太"完美"** +- 真实的人说话:有停顿,有"嗯"/"那个"/"就是说" +- 太书面:"我非常感谢你的意见"——没人这么说话 +- 真实:"嗯,我觉得还行,反正..." +- **怎么练**:听身边人说话,录下来,看你**真的**怎么说话 +- **平衡**:不要"太真实"(文学要节奏)——但**不要**完全"书面化" + +() + +## 平衡:不书面,也不过真实 + +两个方向的错误都要防,这是两本书共同的分寸: + +- 太书面 = 失真,像"教课"(布兰德警告的失败模式之一)。() +- 太真实 = 一字不落地记录"嗯""啊"会丢掉小说的节奏,质感要控制——"不要'太真实'(文学要节奏)"。() +- 插入 1-2 处非标准化表达后要通读,确认不像台词剧本——过了就成录音稿。() + +## 中文适配 + +### 源单元原有的中文适配条目 + +- Clark 的对话理论在**中文小说**中的迁移需要本地化:中文的"嗯"、"这个"、"那个"等语气词比英文对话标签更密集,直接套用"去中介标签"会丢失中文对话的特殊节奏。(,中文适配) + +### 本次合并补充(中文适配) + +- **翻译腔信号**:对话里出现"哦,我的天"、"我向你保证"、每句话以"你知道的"开头、代词用满(他/她反复出现而不靠称呼和上下文省略)、每句都是主谓宾完整的书面句——这是翻译过来的腔调,不是中文口语。自查法:把对话念出声,舌头打结、平时没人这么说的,就是翻译腔。 +- **公文腔信号**:角色对家人朋友说会议体——"我们要认真对待这件事"、"总体来说我同意你的看法,但是……"、"这个问题我们要分两方面看"。这是论文答辩式对话(ce24)的中文变体:信号同样是"说整句、不重复、不卡顿",只是把英文教科书腔换成了机关腔。 +- **中文真话质感长什么样**:省略多("走了啊"而不是"我要先离开了")、倒装("真好吃,这个")、称呼代替代词("妈给你留了饭"而不是"我给你留了饭")、语气词收尾(吧、呢、嘛、啊、呗)、半句话和打断("我其实——算了,没什么")。按 Clark 的分寸:每段挑 1-2 处用,不是逐字录音。 +- **方言的分寸**:方言词可以做角色区别点(→ references/character-voice.md),但整段方言会挡住非本地读者;用词点缀,不用方言写整句语法。 + +## 本主题常见误区 + +1. **答辩式对话**——人物全说整句、不重复、不卡顿、不用俚语,像论文答辩;信号一出现就是作者在代笔。() +2. **太书面**——台词完美得不像人话;"我非常感谢你的意见"没人这么说话。() +3. **太真实**——纯录"嗯啊"会丢小说节奏;插 1-2 处质感后通读,确认不像台词剧本。(;) diff --git a/framework/catalog/dsh/skills/dialogue-craft/references/rhythm-and-density.md b/framework/catalog/dsh/skills/dialogue-craft/references/rhythm-and-density.md new file mode 100644 index 0000000..a5260e8 --- /dev/null +++ b/framework/catalog/dsh/skills/dialogue-craft/references/rhythm-and-density.md @@ -0,0 +1,51 @@ +# 节奏与密度:对话的时间感、短对话、通风口 + +来源:(多萝西娅·布兰德,《成为作家》第八章 + 第十章 + 第十一章);(Roy Peter Clark,《Writing Tools: 55 Essential Strategies for Every Writer》Tool 26) + +## 布兰德原则 2:对话要"增强时间感" + +全量保留:() + +- 短的对话,加上周围的叙述,**增强**段落的紧凑感 +- 长的独白,不如短的交换 +- 一页纸上**被分割成数不清的小段**对话 = 时间快,节奏紧 +- 反过来:大段叙述 = 时间慢,节奏松 + +R 段原文对应句:"这种波涛的升高和薄落,这种浪潮的喷涌,即使只表现为一页纸上被分割成数不清的小段的对话,也足以让它的时间感增强了,段落的时间感增强。"(原文全引 → references/when-to-use-dialogue.md)() + +## 密度标准 + +- 冲突/高潮场景:**对话占比 50%-80%**(布兰德"场景 1:冲突/高潮——必用对话"的密度项)。() +- 故事开头:可用对话(建声音)或不用(速查表条目)。() + +## 案例全文:海明威的"短对话"风格 + +- **问题**:想知道"对话怎么用最有力" +- **方法论的使用**:海明威的对话几乎都是 1-6 个字("嗯"/"好"/"是") +- **结论**:**短对话**比长独白有力,节奏快 +- **结果**:像"喷涌"——强张力 + +() + +## 案例全文:伦纳德(Elmore Leonard)的写作哲学——对话是通风口 + +- **问题**:写作时如何决定"删什么"? +- **方法论的使用**:Leonard 给出标准——"删除读者会跳过的部分"。"而对话是读者不会跳过的部分"——对话的白色空间在视觉上吸引眼睛,本身就是场景的"通风口"。 +- **结论**:对话承担"读者粘性"功能,是小说节奏的调节器。 +- **结果**:成为了"对话 vs 描述"决策的金句;说明对话不是"信息容器",是"注意力锚点"。 + +() + +## 两本书的合并点 + +- 布兰德管**对话内部的时间感**:切小段提速、短交换强过长独白、叙述包裹对话。() +- Clark(借伦纳德)管**对话在页面上的注意力功能**:对话是读者不跳过的部分,空白本身调节节奏。() +- 合起来是一条完整节奏链:场景内的快慢靠对话长短与切段(布兰德),场景之间的透气靠对话与叙述的配比(伦纳德标准)。 + +中文落地:中文网文连载的对话密度普遍偏高,大段叙述在手机阅读里容易被跳过——伦纳德的"删除读者会跳过的部分"在网文语境下几乎是硬规则;但布兰德的提醒同样成立:对话的喷涌要靠叙述铺垫,全是碎对话没有叙述包裹,张力反而泄掉。两边标准的用法:用伦纳德标准砍掉读者会跳的叙述,用布兰德标准保住高潮场景 50%-80% 的对话密度和外围叙述。(中文落地说明,规则出自、) + +## 相关误区与边界 + +- **对话写得太满/太碎**——这是激活本 skill 的典型信号之一;太满(全是独白)拖节奏,太碎(没有叙述包裹)泄张力。() +- **长独白不如短的交换**——独白拖慢时间感;需要角色长篇表达时,拆成交换或让叙述打断。() +- **网文对话**是布兰德没考虑过的形态:网络连载的对话节奏更快,信息密度更高(布兰德盲点,完整清单 → references/boundaries-and-pitfalls.md)。() diff --git a/framework/catalog/dsh/skills/dialogue-craft/references/tags-and-attribution.md b/framework/catalog/dsh/skills/dialogue-craft/references/tags-and-attribution.md new file mode 100644 index 0000000..829f24f --- /dev/null +++ b/framework/catalog/dsh/skills/dialogue-craft/references/tags-and-attribution.md @@ -0,0 +1,72 @@ +# 标签与归属:删"X 说 Y 说",让读者偷听 + +来源:(多萝西娅·布兰德,《成为作家》第八章 + 第十章 + 第十一章);(Roy Peter Clark,《Writing Tools: 55 Essential Strategies for Every Writer》Tool 26) + +两本书在这条上合并:布兰德的错误 1("X 说 Y 说"标签)与 Clark 的规则 2(让读者偷听、去中介标签)方向一致,合并一条;各自的量化标准与例句全量保留。 + +## 布兰德错误 1:"X 说 Y 说"标签 + +全量保留:() + +- **错误 1:"X 说 Y 说"标签** +- 不要每句话都加"X 说"/"Y 说"/"他说"/"她回答" +- 标签用**过头** = 节奏断,读者疲倦 +- **怎么做**:段落归属 + 偶尔插入"她说" +- 真正好的对话:**靠动作/环境**暗示谁在说话,不靠"说" + +执行标准(布兰德 E 步骤):一段对话中,"X 说"不超过 2-3 次;用动作/环境/段落归属代替标签。() + +## 克拉克规则 2:让读者偷听 + +让读者偷听——去掉"他说"等中介标签,让读者直接进入场景。() + +这一条的理论根据是引语/对话二分:读者"偷听"到对话发生,叙事才被推进;中介标签把读者拦在场景外面,偷听变成听转述。(→ references/when-to-use-dialogue.md)() + +## 克拉克执行:去中介标签(含例句与量化标准) + +全量保留:() + +- 把"他严肃地说"、"她解释道"等中介标签删掉,用动作标签替代("她把茶杯摔在桌上")。 +- 完成标准:中介标签 ≤ 30% 对话;其余用动作 / 沉默 / 表情替代。 + +() + +## 两本书的量化标准合并 + +| 标准 | 数值 | 出处 | +|---|---|---| +| 一段来回里"X 说"的次数 | 不超过 2-3 次 | | +| 中介标签占全部对话的比例 | ≤ 30% | | +| 替代手段 | 动作 / 环境 / 沉默 / 表情 / 段落归属 | 两本书合并 | + +两条标准不冲突,分别管两个层面:布兰德数的是单段来回里的显性标签个数,Clark 算的是全篇中介标签占比。中文落地时两条一起用:先按 Clark 的 30% 扫全篇,再按布兰德的 2-3 次抠单段。(合并说明) + +## 视角差异注记(不冲突,互补) + +- 布兰德保留"偶尔插入'她说'":标签不是全删,是用过头才病;对话靠外围叙述托着("为了创作这个段落,作家必须依赖他的叙事能力")。() +- Clark 的删法更彻底:中介标签(尤其带情绪的"他严肃地说")直接删,让动作说话。() + +实操取中间:归属不明时保留最朴素的"说",带副词的情绪标签("严肃地说""生气地说")一律换成动作。(合并说明,依据上面两条原文) + +## 多人对话的归属难题(布兰德盲点,本条补充) + +布兰德没细说 3 人以上对话的归属难题(其盲点之一,→ references/boundaries-and-pitfalls.md)。中文落地办法(中文适配:本次合并补充): + +- 3 人以上场景,每个新说话人出场给一次归属(动作或名字),之后靠段落和声音习惯维持 +- 用各角色固定语言习惯做无标签归属(→ references/character-voice.md):声音区分度够高,读者不需要"X 说"也知道是谁 +- 超过 4 人同时说话的场景,考虑用叙述点名其中一两个,其余并入群像 + +## 中文适配 + +(以下除第 1 条外为本次合并补充,标注"中文适配") + +1. 中文的"嗯"、"这个"、"那个"等语气词比英文对话标签更密集,直接套用"去中介标签"会丢失中文对话的特殊节奏——删标签删到对话失掉自身节奏就是删过头。(,中文适配) +2. **中文归属的天然弱点**(中文适配):中文"说"没有人称变位、没有首字母大写,说话人切换完全靠分段、动作和语境;英文里能靠形式区分的地方,中文必须靠动作节拍(beat)补——删标签的代价在中文里更高,替换动作要跟上,不能只删不补。 +3. **中文最常见的中介标签是副词标签**(中文适配):"他严肃地说"、"她不悦地回道"、"他意味深长地说"——翻译腔小说里尤其密集。按 Clark 标准这些全在 ≤ 30% 的清点范围里,优先删。 +4. **语气词分担情绪功能**(中文适配):中文里"吧、呢、嘛、呗"本身携带情绪和态度,"她说:'好吧。'和'她说:'好。'"情绪不同;删标签后用语气词和标点找补情绪,是中文对话的独门手段。 + +## 本主题常见误区 + +1. **"X 说 Y 说"挂满标签**——节奏被切碎,读者疲倦;用动作、环境、段落归属替代。() +2. **语气标签把读者推出场景**——"他严肃地说""她解释道"是中介,不是信息;换成动作("她把茶杯摔在桌上")。() +3. **只删不补**——删掉标签后归属不清,读者分不清谁在说话;删的同时用动作节拍、段落归属、声音习惯补上。(合并说明,依据两书规则) diff --git a/framework/catalog/dsh/skills/dialogue-craft/references/when-to-use-dialogue.md b/framework/catalog/dsh/skills/dialogue-craft/references/when-to-use-dialogue.md new file mode 100644 index 0000000..136bfbb --- /dev/null +++ b/framework/catalog/dsh/skills/dialogue-craft/references/when-to-use-dialogue.md @@ -0,0 +1,110 @@ +# 什么时候用对话:定位、时机与形式判断 + +## 原文摘录 + +> "小说中使用对话好像是几个固定的规则之一。它应该用在故事最高潮的时候, +> 就像' 喷涌'。这种波涛的升高和薄落, 这种浪潮的喷涌, 即使只表现为一页纸上被分割成 +> 数不清的小段的对话, 也足以让它的时间感增强了, 段落的时间感增强。 +> 为了创作这个段落, 作家必须依赖他的叙事能力。 +> 因此, 对话的应用不仅是为了强调故事的冲突和高潮, 而且是为了总体上增强故事持续发展的更大流畅。" +> +> — 多萝西娅·布兰德,《成为作家》第八章 + +> While quotes provide information or explanation, dialogue thickens the plot. The quote may be heard, +> but dialogue is overheard. The writer who uses dialogue transports us to a place and time where +> we get to experience the events described in the story. +> +> — Roy Peter Clark, *Writing Tools* (Tool 26) + +## 对话是什么:布兰德的三条原则 + +布兰德给对话定了三条底层逻辑。 + +### 原则 1:对话是"喷涌"——在高潮时用 + +- 对话**不是**为对话而对话 +- 对话**不是**"展示角色在说话" +- 对话**是**"故事在高潮时喷涌"——情绪/冲突达到顶点时的爆发 +- 就像河水在窄口喷涌,对话是故事**在窄口喷涌** + +### 原则 2:对话要"增强时间感" + +- 短的对话,加上周围的叙述,**增强**段落的紧凑感 +- 长的独白,不如短的交换 +- 一页纸上**被分割成数不清的小段**对话 = 时间快,节奏紧 +- 反过来:大段叙述 = 时间慢,节奏松 + +节奏机制的细节与案例(海明威、伦纳德)→ references/rhythm-and-density.md。 + +### 原则 3:对话是"冲突"工具 + +- 对话**不仅**强调冲突,**而且**制造冲突 +- 好的对话 = 角色在**不同的目标/价值观**上碰撞 +- 坏的对话 = 角色在"分享信息"——那应该用叙述 + +碰撞的展开与案例 → references/dialogue-does-things.md。 + +## 引语 vs 对话:克拉克的核心二分法 + +Clark 的核心二分法:**引语(quote)** 与 **对话(dialogue)** 看似都是"角色说话",但在叙事功能上截然不同。 + +- **引语(quote)**:角色事后补话,**关于**动作。读者**听到**它在解释,叙事被打断。 +- **对话(dialogue)**:角色在场景中说话,**在**动作中。读者**偷听**到它发生,叙事被推进。 + +**判断标准:一句话在角色嘴里是"上方传来"还是"在场发生"?** + +这是场景写作的核心理论:**对话不是装饰,是事件。**事件的三大功能见 references/dialogue-does-things.md。 + +中文落地:这个二分法来自 Clark 的新闻写作背景(新闻里引语是采访所得的事后陈述),迁到小说里就是"转述"与"场景直呈"的区别。中文稿子里常见的病灶是把关键戏写成"他后来告诉我……""据他说……"式的转述带过;按 Clark 的标准,凡是读者需要"在场经历"的段落,就把转述改回当下场景里的说话。 + +## 三个使用场景:什么时候用对话 + +### 场景 1:冲突/高潮——必用对话 + +- 角色之间**有冲突**(目标不一致/价值观不一致/隐藏动机) +- 故事到了**高潮点**(情绪达到顶点) +- 例:离婚谈判,告白,摊牌,争吵 +- **密度**:对话占比 50%-80% + +### 场景 2:信息/说明——慎用对话 + +- 需要**传递信息**(背景/前情/设定) +- **不要**用对话(那是"告诉"的最糟方式) +- 用叙述/独白/闪回 +- 例:不要用两个角色说"你知道吗,上世纪 90 年代我们..." +- **反例**:"老师对学生说:'写作需要想象力...'"——这是说教,不是故事 + +### 场景 3:日常/过渡——选着用对话 + +- 故事中**日常的过渡**(角色一起吃饭/坐车/走路) +- 可以用对话,但要让它**隐含冲突**/推动情节 +- 纯粹的"今天天气真好" = 删掉 +- 例:角色吃饭时,一句话透露了他**真正的担忧**——看似闲聊,实际推进 + +## 对话还是叙述:速查表 + +| 场景 | 优先用 | +|---|---| +| 冲突/高潮 | 对话 | +| 信息/说明 | 叙述 | +| 动作/事件 | 叙述 | +| 思考/感受 | 叙述或内心独白 | +| 角色关系/性格 | 对话(暴露) | +| 日常/过渡 | 看情况(隐含冲突才用) | +| 故事开头 | 可用对话(建声音)或不用 | + +## 两本书的合并点:信息不是对话的活 + +两本书从不同方向落到同一条规则上: + +- 布兰德:传递信息、背景、前情是叙述/独白/闪回的活;用对话的嘴交代背景,是"告诉"的最糟方式,会写成说教。 +- Clark:引语(quote)才是提供信息与解释的形式;对话(dialogue)的本职是让情节变厚(thickens the plot),不是给信息。 + +中文落地:中文网文里常见的"设定问答"(两个角色互相讲解世界观)就是本条的反面教材;设定该用叙述、动作、冲突逐步放出来,而不是让角色在课堂上互相提问。 + +## 视角差异注记(不冲突,互补) + +- 布兰德强调对话**需要叙述能力托着**:R 段原文里"为了创作这个段落,作家必须依赖他的叙事能力"——对话的喷涌要靠周围叙述铺垫和承接。() +- Clark 强调**去掉中介让读者直接进场景**:删"他说"之类的标签,读者才不被叙述者拦住。() + +两条不冲突:布兰德说的是叙述在对话**外围**做的事(铺垫、承接、控制时间感),Clark 说的是删掉对话**中间**的转述性标签。删标签的量化标准 → references/tags-and-attribution.md;外围叙述与对话的比例节奏 → references/rhythm-and-density.md。 diff --git a/framework/catalog/dsh/skills/foreshadow-payoff/SKILL.md b/framework/catalog/dsh/skills/foreshadow-payoff/SKILL.md new file mode 100644 index 0000000..9faa801 --- /dev/null +++ b/framework/catalog/dsh/skills/foreshadow-payoff/SKILL.md @@ -0,0 +1,78 @@ +--- +name: foreshadow-payoff +description: | + 小说写作的伏笔与回收方法:把显著元素登记成债务、把铺垫埋得自然、让兑现从已埋细节生长出来。 + 当用户说"埋了没收""线索失踪""伏笔太突兀""这个细节是装饰还是债务""契诃夫之枪怎么用" + "伏笔怎么分层""兑现时间表",或明确在谈埋/收/铺垫链、特殊人物出场前的台阶时激活。 + 关键 trigger:"伏笔" / "回收" / "铺垫" / "契诃夫之枪" / "chekhov's gun" / "foreshadow" / + "线索失踪" / "埋了没收" / "承诺不兑现" / "前面挖的坑没填" / "删除测试" / "伏笔分层" / + "短期伏笔 / 中期伏笔 / 长期伏笔" / "兑现时间表" / "伏笔台账" / "修楼梯" / "Hitchcock 变体" / + "显眼的凶器" / "预暴露的伏笔" / "前后呼应" / "高潮从天而降(欠债未兑)"。 + 不适用于:仅问「高潮怎么写」「反转怎么设计」「大场面怎么拍」而无埋/收/契诃夫语境 + (归 scene-craft / story-structure / story-ending); + 散文/随笔(无情节承兑机制)、纯意识流/氛围小说(无情节闭环压力,元素出现又消失是合法的)、 + 解构/反小说(刻意让伏笔不兑现正是其目的)、需要大场面直接冲击的灾难/战争场景、 + 1000 字以下超短篇(没有埋设与生长的空间;1500 字以下不需要分层)。 + 与 scene-craft 交接:单场景高潮执行(使命/镜头/进出)归 scene-craft;本 Skill 只管债务登记与兑现链。 + 与 story-ending 交接:终局姿态与倒推收束归 story-ending;本 Skill 只保证前文债务可兑。 +--- + +# 伏笔与回收 + +伏笔是一条完整链路:**登记埋设 → 自然生长 → 兑现/高潮**。三家各管一段:《写作工具》管"显著元素就是借款,必须登记、偿还",《小说课》管"铺垫埋得自然,给读者的接受度修楼梯",《我能否相信自己》管"高潮不是凭空降临,而是从不动声色的细节里长出来"。 + +## 方法索引 + +### 埋设决策:埋什么、在哪里还 + +- 显著元素就是借款:被镜头对准、被台词反复提及、被位置强调的元素都在向读者借款,用位置/重复/特写/对话四个信号判断"装饰还是债务" → references/register-and-repay.md +- 建伏笔台账,按短/中/长期分层,写兑现时间表;找不到兑现点的伏笔就删除或降低显著度 → references/register-and-repay.md +- 删除测试(修订阶段用):删掉它故事不变轻就是装饰,删;变轻就是隐性债务 → references/register-and-repay.md +- Hitchcock 变体:把凶器预先命名、预先暴露,悬念从"会发生什么"移到"怎么发生" → references/register-and-repay.md + +### 自然埋设:埋得不露痕迹 + +- 铺垫就是修楼梯:特殊人物/事件/场景出场前,先垫 2-4 个普通同类台阶 → references/natural-staircase.md +- 每级台阶 1-3 句话,台阶要独立、有"无关感",读者不能一眼看出是台阶 → references/natural-staircase.md +- "去掉铺垫"测试校准台阶数量:突兀就加一级,还能接受就删一级 → references/natural-staircase.md +- 铺垫要有双重功能:表层让特殊物出场自然,深层同时承担情节、主题或性格描写 → references/natural-staircase.md + +### 兑现与高潮:让细节爆发 + +- 细节先行、细节生长、细节爆发三段链路:高潮由一个微小的动作、物品或一句话触发 → references/detail-driven-climax.md +- 回溯有效性验收:回溯时一切合理,初读时不察觉 → references/detail-driven-climax.md + +### 诊断与边界 + +- 不适用场景、常见误区(承诺不兑现、装饰过载、铺垫露形、细节与高潮关联太弱等)、盲点与中文落地 → references/boundaries-and-pitfalls.md + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|----------| +| references/register-and-repay.md | 显著元素即借款;装饰 vs 债务判断;伏笔台账与显著信号四条;短/中/长期分层与兑现时间表;删除测试;Hitchcock 变体;契诃夫 1889 年信与《Lamb to the Slaughter》案例;伏笔与线索的区分 | +| references/natural-staircase.md | 铺垫=修楼梯;识别特殊物;设计 2-4 级普通台阶;台阶简洁与独立;去掉铺垫测试;铺垫双重功能;奈保尔四个乞丐、水浒林冲风雪、《促织》驼背巫与斗蛐蛐案例 | +| references/detail-driven-climax.md | 细节先行/生长/爆发三段链路;不动声色的埋法;回溯恍然大悟;《一千零一夜》戒指、《拜占庭的陷落》小门、《威尼斯商人》一磅肉案例;与契诃夫之枪的关系 | +| references/boundaries-and-pitfalls.md | 不适用场景汇总;常见误区(线索失踪、装饰过载、伏笔露形三形态、关联太弱、只用一次、常见错误表);盲点与时代局限(网文落地、类型惯例、红鲱鱼);与相邻方法的区分及跨 skill 配合 | + +## 脚本 + +| 脚本 | 用途 | +|------|------| +| references/foreshadow-ledger-template.md | 伏笔台账与兑现时间表模板:登记显著元素,标注装饰/债务与短/中/长期,对应埋设点与兑现点 | +| references/foreshadow-checklist.md | 修订阶段检查清单:场景四问、删除测试、去掉铺垫测试、回溯有效性三问 | + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/dsh/skills/foreshadow-payoff/references/_coverage.md b/framework/catalog/dsh/skills/foreshadow-payoff/references/_coverage.md new file mode 100644 index 0000000..589ab4d --- /dev/null +++ b/framework/catalog/dsh/skills/foreshadow-payoff/references/_coverage.md @@ -0,0 +1,13 @@ +# foreshadow-payoff 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| bifeiyu-novel-skill/bifeiyu-foreshadowing | references/natural-staircase.md | +| bifeiyu-novel-skill/bifeiyu-foreshadowing | references/boundaries-and-pitfalls.md | +| bifeiyu-novel-skill/bifeiyu-foreshadowing | references/detail-driven-climax.md | +| wo-neng-fou-xiang-xin-zi-ji/detail-driven-climax | references/detail-driven-climax.md | +| wo-neng-fou-xiang-xin-zi-ji/detail-driven-climax | references/boundaries-and-pitfalls.md | +| writing-tools-clark/chekhov-gun | references/register-and-repay.md | +| writing-tools-clark/chekhov-gun | references/boundaries-and-pitfalls.md | diff --git a/framework/catalog/dsh/skills/foreshadow-payoff/references/boundaries-and-pitfalls.md b/framework/catalog/dsh/skills/foreshadow-payoff/references/boundaries-and-pitfalls.md new file mode 100644 index 0000000..2bb020f --- /dev/null +++ b/framework/catalog/dsh/skills/foreshadow-payoff/references/boundaries-and-pitfalls.md @@ -0,0 +1,107 @@ +# 适用边界、常见误区与盲点 + +> 伏笔与回收方法的边界、失败模式、盲点和相邻方法区分在此汇总。 + +## 不适用场景 + +**《写作工具》列出的不要用此方法的情况:** + +- **解构 / 反小说 / 后现代叙事**——这类作品**刻意**让伏笔不兑现(让读者意识到"叙事的不可信"),此时 Clark 的承诺原则正是被颠覆的对象。例:Paul Auster 的迷宫式叙事。 +- **散文 / 随笔 / 抒情独白**——没有"情节"承兑机制,伏笔概念无意义。 +- **意识流 / 极简叙事(去情节化)**——元素出现又消失是合法的(无情节闭环压力)。 +- **写作前期的"灵感囤积"阶段**——伏笔管理是**修订阶段**的工具,不是初稿阶段的工具。初稿应该"先埋一堆",修订再决定"哪些留 / 删 / 兑现"。 +- **极短篇(< 1500 字)**——伏笔跨度有限,所有元素"立刻"兑现,不需要分层工具。 + +**《小说课》列出的适用边界:** + +- **适合**:短篇、超短篇、长篇关键场景 +- **不适合**:长篇的章节切换(可以用整章铺垫) +- **不适合**:节奏要求快的惊悚/悬疑(铺垫要短到极致) + +**《我能否相信自己》列出的不要用此方法的情况:** + +- **纯氛围/意识流小说**:没有传统情节结构的作品,不需要"高潮"概念 +- **灾难/战争大场面**:有时需要直接的大场面冲击,不适合用微小细节驱动 +- **超短篇(1000 字以下)**:篇幅太短,没有足够空间埋下细节并让它生长 + +**字数边界对照(两说并存,都保留)**:Clark 说 1500 字以下不需要分层工具(元素几乎立刻兑现);余华说 1000 字以下连埋设与生长的空间都没有。两者口径不同但不冲突:1000 字以下彻底不用伏笔机制,1000-1500 字可以埋但无需台账分层。 + +## 常见误区(失败模式) + +### 1. 承诺不兑现("线索失踪") + +失败模式是**承诺但不兑现**——显著元素(角色提到"A 先生的秘密"、墙上挂的猎枪、孩子的红雨衣)出现后又消失。读者记得,作者忘了,结尾没有交代。信号:第 5 章的伏笔在 25 章后无交代;读者在评论中问"那个 X 怎么了"。机制:读者对"重要元素"有"准记忆"——如果后续不提,他们会期待却失望,觉得"作者控不住结构"。对策:伏笔台账 + 兑现时间表。 + +### 2. 装饰过载 + +与"线索失踪"相反——**埋太多"假装是债务"的装饰**。把每个细节都写得像伏笔,结果兑现不了 → 读者疲劳 + 不信任作者的承诺系统。**删除测试**正是用来对抗这种失败。 + +### 3. 伏笔露形(三种形态) + +同一个误区的三种形态: + +- **作者大声宣布**(新手陷阱):把伏笔写成"作者大声宣布"("那把猎枪很重要,主角一定会用到它!")。正确做法是**埋得自然,关键是被镜头/语言显著,不必被作者宣判"重要"**。 +- **埋细节时给太多强调**:如果前段埋下细节时给了太多强调,读者会猜到后续,失去"恍然大悟"的快感。 +- **台阶被一眼看穿**:铺垫太明显,读者预先猜到结局。修正:台阶要有"无关感"。 + +### 4. 细节与高潮关联太弱 + +如果细节和高潮之间的逻辑链条不清晰,读者会觉得"太巧合了"而非"精妙"。细节必须能逻辑地推出高潮。 + +### 5. 只在高潮用一次细节 + +好的细节应该在故事中多次出现(以不同形式),形成回响。孤证式的细节爆发没有说服力。 + +### 6. 铺垫的常见错误(《小说课》错误表) + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 铺垫变"介绍" | 啰唆、啰唆 | 每个台阶只 1-3 句 | +| 铺垫太明显 | 读者预先猜到结局 | 台阶要有"无关感" | +| 铺垫不够 | 突兀、做作 | 增加台阶数 | +| 多个特殊物同时出场 | 全都突兀 | **一次只铺一个** | + +## 盲点与时代局限 + +**《写作工具》:** + +- Chekhov 原则本身是经典的(19 世纪俄国戏剧),Clark 的**独特贡献是配套的"已暴露的凶器"(Hitchcock 变体)+ 删除测试 + 伏笔台账的工作流**。如果只教"伏笔要兑现"是常识;这个方法的真正价值在"**分层 + 决策测试 + 工作流**"。 +- **长篇 / 系列小说的伏笔管理工具**:Clark 写于 2006 年(英文版),针对的主要是"中短篇小说 + 非虚构",对**网文百万字连载 / 跨 5+ 卷的系列小说**没有给出系统化方案。迁移到中文长篇 / 网文时,需要补充:台账软件(Notion / Airtable / Excel)、团队协作下的"伏笔分配表"(多人合写)、"读者已知 vs 角色已知"的双轨追踪。(中文适配) +- **类型文学的伏笔惯例不同**:悬疑/推理的"公平竞争"(Fair Play)规则(读者必须和侦探有同等线索)是 Chekhov 原则的子类,Clark 未展开;言情/玄幻的"线索失踪"容忍度比悬疑高(读者更关心情绪而非线索);这些类型差异需要本地化调整。(中文适配) + +**《我能否相信自己》:** + +- 余华主要从经典文学中举例,没有讨论当代类型小说(如网络小说)中如何使用这种技巧——类型小说的读者对伏笔更敏感,需要更隐蔽的处理。(中文适配) +- 没有讨论"红鲱鱼"(假伏笔)的使用——有时需要用假细节来误导读者,让真细节的爆发更有力。 + +**《小说课》:** + +- 无独立盲点;需要注意的边界已并入上文"不适用场景"与"常见错误表"。 + +## 与相邻方法的区分(跨领域指针) + +**来自《写作工具》:** + +- 与 `gold-coins`(沿途埋金,今 narrative-momentum)的区别:那个是"沿途奖赏"——在中段撒"小高潮 / 逸事 / 惊人事实"让读者不弃读,**不要求回收**;这个是"埋伏-兑现"——埋的每个元素都**必须回收**。前者是"节奏分布",后者是"因果闭环"。一个金币是礼物(发完就完),一把枪是债务(借了要还)。那个的"金"是奖励(节奏),这个的"枪"是债务(因果);两者并存,但功能截然不同——一个让读者"继续走",一个让读者"记住回头看"。 +- 与 `write-toward-ending`(倒推向结局,今 story-ending)的区别:那个是"结尾策略"——先锚定终局反向写作;这个是"为结尾铺路"——把通往结尾的路径标记成可被回收的伏笔。前者是"倒推",后者是"前向埋伏 + 承诺兑现"。两个方法强配对:用 write-toward-ending 定结尾,再用契诃夫之枪设计通往结尾的伏笔链。 +- 与 `inciting-incident`(触发事件 + 加码,今 story-structure)的区别:那个管"开篇的破局一击 + 中段加码",伏笔是"开局后的稳定结构"——前者是"打破平衡",后者是"维护平衡下的承诺"。两者不冲突:触发事件之后,伏笔系统开始运转。 +- 与 `mix-narrative-modes`(混合叙事模式,今 narration-pov)的区别:那个管"主线 / 折线 / 蒙太奇"的叙事模式调度;这个管"每个具体元素是否值得存在"——前者是"段落/章节级的模式",后者是"物件/对话级的内容层"。 +- 与 "show, don't tell"(Tool 27,今 show-and-omission 领域)的区别:那个管"如何显示"——伏笔管理管"显示什么 / 显示的东西是否兑现"。前者是"风格",后者是"结构"。 + +**来自《我能否相信自己》:** + +- 与 `obstacle-crossing`(写作障碍应对,已裁剪单元、不入综合 skill)的区别:本方法是情节设计技巧(如何用细节驱动高潮),obstacle-crossing 是写作过程策略(如何面对障碍)。制造障碍后,往往需要用细节来跨越障碍。 +- 与 `certainty-uncertainty-tension`(确定与不确定的张力,今 narration-pov)的区别:本方法给出确定的情节转折(细节爆发),certainty-uncertainty-tension 保留不确定性。一个是"恍然大悟",一个是"回味无穷"。 +- 与 `no-psychological-description`(不写心理写动作,今 show-and-omission)配合:细节(动作/视觉)既是心理描写的替代,也是高潮的驱动力。 + +**来自《小说课》:** + +- 与 `bifeiyu-iceberg`(冰山理论,今 show-and-omission)配合:铺垫是"水下的结构",冰山是"水下的内容"。 +- 与 `bifeiyu-momentum`(叙事动力,今 narrative-momentum)关联:铺垫 = 给"势"铺路。 +- 与 `bifeiyu-system`(体系,今 story-structure)配合:短篇铺垫极简,长篇铺垫可厚——体裁决定密度。 + +**来自《写作工具》的配合关系:** + +- `internal-cliffhanger`(章末内悬念,今 narrative-momentum):章末内悬念可作为短期伏笔的兑现触发。 +- `mix-narrative-modes`(混合叙事模式,今 narration-pov):折线叙事中可嵌入伏笔的回顾/解释。 +- `mosaic-of-detail`(细节马赛克,今 character-presentation):细节马赛克中选出的 5-9 个细节应优先考虑作为"债务"而非"装饰"。 diff --git a/framework/catalog/dsh/skills/foreshadow-payoff/references/detail-driven-climax.md b/framework/catalog/dsh/skills/foreshadow-payoff/references/detail-driven-climax.md new file mode 100644 index 0000000..67b2fab --- /dev/null +++ b/framework/catalog/dsh/skills/foreshadow-payoff/references/detail-driven-climax.md @@ -0,0 +1,112 @@ +# 细节驱动高潮:高潮从不动声色的细节里长出来 + +> 本文件管伏笔链路的兑现端:高潮怎么由前段埋下的微小细节触发。埋设登记见 [register-and-repay.md](register-and-repay.md),埋设的自然度见 [natural-staircase.md](natural-staircase.md);边界与误区见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> "故事中最辉煌的段落, 这些高潮的篇章和最终结束的篇章其实来自一个微小的和不动声色的细节, 来自类似国王挥手这样的描述, 就像是那些粗壮的参天大树其实来自细小的根须一样。" +> +> "我们总是沉醉在叙述中那些最为辉煌的段落之中, 那些出人预料和惊心动魄的段落...山鲁佐德的故事指出了这些华彩的篇章...其实来自一个微小的和不动声色的细节。" +> +> — 余华, 《什么才是故事》 + +## 方法核心:三段链路 + +故事中最出人预料、最惊心动魄的高潮,往往不是来自大场面或大转折,而是来自一个**微小的、不动声色的细节**——一个平常的动作、一个不起眼的物品、一句随口说的话。这个细节像树根一样,在叙述中悄悄生长,最终支撑起整个高潮。 + +关键机制: + +1. **细节先行**:在故事前段,以一种"让人疏忽和视而不见"的方式埋下一个细节 +2. **细节生长**:这个细节在后续叙述中被反复触及或自然发展,但读者不会意识到它的重要性 +3. **细节爆发**:到高潮时,这个细节突然成为情节转折的关键——读者才意识到"原来前面那个细节是这个意思" + +这种技巧的力量在于:高潮不是凭空降临的(那样会显得突兀),而是从已有叙述中自然生长出来的(那样会显得精妙且有说服力)。读者回溯时会发现一切早有伏笔,从而获得"恍然大悟"的快感。 + +## 案例 + +### 案例 1:《一千零一夜》——国王挥手丢戒指 + +- **问题**:如何让好人艾彼·绥尔从死刑中逃脱并重获国王信任? +- **方法论的使用**:船长释放艾彼·绥尔后,把一块大石头放入麻袋以假乱真。国王在临海的宫窗前,船长问是不是可以抛入海中,国王说抛吧——"国王说话的时候举起戴着宝石戒指的右手一挥, 一道闪光从他的手指上划到了海面, 戒指掉入了大海。"这个平常的挥手动作,让国王的权力戒指掉入海中,而戒指恰好被艾彼·绥尔捞到。 +- **结论**:一个挥手的微小细节,决定了后续情节的全部走向。 +- **结果**:艾彼·绥尔用戒指还给国王,重获信任,坏人艾彼·勾尔被处死。 + +### 案例 2:茨威格《拜占庭的陷落》——凯卡波尔塔小门 + +- **问题**:奥斯曼土耳其人久攻君士坦丁堡不下,如何让城破? +- **方法论的使用**:茨威格没有写土耳其人靠强大攻势破城,而是写了一个被遗忘的小门——凯卡波尔塔小门。它是和平时期大门紧闭时供行人出入用的,"正是因为它不具有军事意义, 罗马人忘记了它的存在。凯卡波尔塔小门敞开着, 而且无人把守, 土耳其人发现了它, 然后攻入了城中。" +- **结论**:一个不具军事意义的小门,决定了强盛一千多年的东罗马帝国的灭亡。 +- **结果**:成为"一个影响深远的决定其实来自一个日期、一个小时,甚至是来自一分钟"的经典例证。 + +### 案例 3:莎士比亚《威尼斯商人》——夏洛克忘记血 + +- **问题**:如何让夏洛克的报复失败? +- **方法论的使用**:莎士比亚让夏洛克在签订契约时,只要求"一磅肉",忘记了一个事实——割下肉会流血。这个微小的遗漏,在审判时成为鲍西娅反击的关键:"你可以割一磅肉, 但不能流一滴血。" +- **结论**:夏洛克的一个疏忽(忘记血),造就了全剧的情节跌宕和叙述紧张。 +- **结果**:成为文学史上最经典的反转之一。 + +## 可执行步骤 + +1. **确定高潮事件** + - 明确故事的核心高潮是什么(人物命运转折、真相揭露、关系破裂等) + - 完成标准:能用一句话说清高潮事件 + +2. **回溯寻找细节根须** + - 问自己:这个高潮可以由什么微小细节触发? + - 细节应该是:一个动作 / 一个物品 / 一句话 / 一个被遗忘的约定 / 一个角色的小习惯 + - 细节必须在故事前段有自然出现的理由(不能为了埋伏笔而硬加) + - 完成标准:找到一个可以触发高潮的微小细节 + +3. **在前段自然埋下细节** + - 以"让人疏忽和视而不见"的方式写出这个细节 + - 不要强调它,不要给它特殊的叙述权重 + - 最好让它融入日常场景中(如挥手、关门、随口一句话) + - 完成标准:细节已出现在故事前段,且不显得刻意 + +4. **让细节在中段悄悄生长** + - 在故事中段,可以再次触及这个细节(但仍不强调) + - 或者让细节所处的环境发生变化,为后续爆发做准备 + - 完成标准:细节与后续高潮之间有逻辑链条 + +5. **在高潮让细节爆发** + - 高潮时,让这个细节成为情节转折的关键 + - 读者应该在这一刻"恍然大悟":原来前面那个细节是这个意思! + - 完成标准:高潮由细节触发,而非凭空降临 + +6. **检查回溯有效性** + - 读者回溯时,能否发现一切早有伏笔? + - 细节在前段出现时是否自然? + - 高潮是否由细节逻辑地推出,而非强行关联? + - 完成标准:回溯时一切合理,初次阅读时不察觉 + +## 什么时候用这个单元 + +用户会在这些情境下需要"细节驱动高潮": + +1. 设计情节转折时觉得突兀,读者反馈"太巧合了" +2. 高潮写得不够有力,缺乏说服力 +3. 想学习"伏笔"的具体操作方法 +4. 写反转 / twist 时不知道怎么铺垫 +5. 故事中段平淡,想让后续高潮更有冲击力 +6. 被反馈"前面铺的东西后面没用上" + +语言信号: + +- "高潮怎么写" "情节转折" +- "伏笔怎么埋" "前后呼应" +- "反转太突兀" "太巧合了" +- "剧情设计" "plot twist" +- "前面写的细节没用上" +- "故事中段太平淡" + +## 与本领域另外两个方法的关系 + +- **与"契诃夫之枪"(本包 register-and-repay.md)的区别**:契诃夫之枪是"如果第一幕墙上挂着枪,第三幕必须开枪"——强调前后呼应。本单元更精确——不仅是呼应,而是"微小细节驱动整个高潮",细节本身就是高潮的发动机,不只是呼应元素。 +- **与"伏笔 / foreshadowing"(更宽泛的概念)的区别**:伏笔是更宽泛的概念,本单元是伏笔的一种特定高效用法——用微小不动声色的细节驱动最辉煌的高潮。 + +## 中文落地说明 + +余华的三案例都出自中文读者熟悉的经典(《一千零一夜》中译传统、茨威格历史特写、莎士比亚),方法本身无语言隔阂。中文写作落地时注意两点: + +- **古典白话传统里这套手法极成熟**:《水浒》林冲的风雪、《促织》的五次失败(见 [natural-staircase.md](natural-staircase.md))都是"细节先行 → 爆发"的中文范本,可直接对照学习。(中文适配) +- **类型小说读者对伏笔更敏感**:余华只从经典文学举例,没讨论网络小说——类型读者读得多,埋细节要更隐蔽,少给叙述权重。详见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md) 盲点一节。(中文适配) diff --git a/framework/catalog/dsh/skills/foreshadow-payoff/references/foreshadow-checklist.md b/framework/catalog/dsh/skills/foreshadow-payoff/references/foreshadow-checklist.md new file mode 100644 index 0000000..b673b46 --- /dev/null +++ b/framework/catalog/dsh/skills/foreshadow-payoff/references/foreshadow-checklist.md @@ -0,0 +1,80 @@ +# 伏笔与回收检查清单 + +> 伏笔与回收的可执行检查项,按写作进程排列:写作中 → 修订阶段 → 完稿验收。 +> 台账模板见 [foreshadow-ledger-template.md](foreshadow-ledger-template.md)。 + +## 一、写作中的场景四问 + +写场景/转折/章节末时逐条自问: + +- [ ] 写场景时:墙上这把枪会开火吗?如果不,弱化或删。 +- [ ] 写转折前:我前面给读者埋下可信的钩子了吗? +- [ ] 写章节末:这个元素是"装饰"还是"债务"?如果是债务,它在哪一章兑现? +- [ ] 通读时:用删除测试扫一遍——哪些元素删掉后故事没变轻,就该删。 + +## 二、特殊物出场前的铺垫检查 + +列出读者会觉得突兀的元素,逐项检查: + +- [ ] 特殊人物(杀人犯/乞丐诗人/性格怪癖的人)、特殊事件(不可能的巧合/超自然/极端选择)、特殊场景(异国他乡/历史时期/极端环境)都识别出来了 +- [ ] 每个特殊物出场前有 2-4 级普通同类台阶 +- [ ] 每级台阶只有 1-3 句话(铺垫变啰唆就是小说内部的肿瘤) +- [ ] 台阶彼此独立、有"无关感",读者不能一眼看出是台阶 +- [ ] 一次只铺一个特殊物(多个特殊物同时出场会全都突兀) +- [ ] 铺垫有双重功能:表层让特殊物出场自然,深层承担情节/主题/性格描写 + +## 三、细节根须检查(为高潮找伏笔) + +设计高潮/反转时逐条核对: + +- [ ] 能用一句话说清高潮事件 +- [ ] 触发高潮的微小细节已选定:一个动作 / 一个物品 / 一句话 / 一个被遗忘的约定 / 一个角色的小习惯 +- [ ] 细节在故事前段有自然出现的理由(不是为埋伏笔硬加) +- [ ] 细节以"让人疏忽和视而不见"的方式埋下,没有特殊叙述权重 +- [ ] 中段再次触及或让其环境变化,但仍不强调 +- [ ] 细节与高潮之间的逻辑链条清晰(不是强行关联) + +## 四、修订阶段:删除测试 + +仅用于修订阶段,初稿不要用(初稿时不知道哪些元素会被用上): + +对每个"装饰"候选元素问:"如果删掉它,这个场景/章节/全书是否变轻?" + +- [ ] 不变轻 → 真的只是装饰 → 删 +- [ ] 变轻 → 隐性债务 → 要么加强它(让它"显著")进伏笔台账,要么删除/弱化避免误导读者 +- [ ] 每个候选元素都有"留 / 删 / 加强"决定,理由是"删除后变轻"还是"不变轻" + +## 五、修订阶段:"去掉铺垫"测试 + +把所有铺垫台阶删掉,只看特殊物: + +- [ ] 突兀?→ 铺垫不够,加 1 级 +- [ ] 还能接受?→ 铺垫可能太多,删 1 级 +- [ ] 反而更自然?→ 你可能没真正铺垫,只是堆细节 + +## 六、完稿验收:兑现与回溯 + +**兑现核对**: + +- [ ] 台账里所有"债务"元素都兑现了,无"线索失踪"(信号:第 5 章的伏笔在 25 章后无交代;读者问"那个 X 怎么了") +- [ ] 没有"装饰过载"——没有一堆写得像伏笔却兑现不了的细节 + +**回溯有效性三问**: + +- [ ] 读者回溯时,能否发现一切早有伏笔? +- [ ] 细节在前段出现时是否自然? +- [ ] 高潮是否由细节逻辑地推出,而非强行关联? + +验收标准:**回溯时一切合理,初次阅读时不察觉。** + +## 七、快速排错表 + +| 症状 | 诊断 | 处方 | +|------|------|------| +| 读者问"那个 X 怎么了" | 承诺不兑现(线索失踪) | 补兑现,或删埋设、降显著度 | +| 读者疲劳、不信作者的承诺 | 装饰过载 | 删除测试扫一遍 | +| 读者提前猜到结局 | 伏笔露形(作者宣判/强调过多/台阶被看穿) | 显著靠镜头语言不靠宣判;台阶加"无关感" | +| 读者说"太巧合了" | 细节与高潮关联太弱 | 补逻辑链条,或换细节 | +| 高潮爆发没说服力 | 细节只在高潮用了一次 | 让细节以不同形式多次出现,形成回响 | +| 特殊物出场突兀做作 | 铺垫不够 | 增加台阶数 | +| 铺垫段又长又闷 | 铺垫变"介绍" | 每级台阶压到 1-3 句 | diff --git a/framework/catalog/dsh/skills/foreshadow-payoff/references/foreshadow-ledger-template.md b/framework/catalog/dsh/skills/foreshadow-payoff/references/foreshadow-ledger-template.md new file mode 100644 index 0000000..d6f740f --- /dev/null +++ b/framework/catalog/dsh/skills/foreshadow-payoff/references/foreshadow-ledger-template.md @@ -0,0 +1,60 @@ +# 伏笔台账与兑现时间表模板 + +> 用途:长篇/系列/网文连载在**修订阶段**登记所有显著元素,追踪每个伏笔的兑现位置。初稿阶段不要用——初稿应该先放手埋,修订再登记。 + +## 第一步:登记显著元素 + +扫描全书/当前章节,凡是命中任一"显著信号"的元素都要进台账: + +- **位置**:被放在墙/桌上/口袋等被点名的位置上 +- **重复**:被提及 2 次以上 +- **特写**:用 1 段以上篇幅描写 +- **对话**:被角色直接说出来 + +每个元素标注"装饰"或"债务": + +- **装饰**:不承担叙事债务,考虑删除或弱化 +- **债务**:必须进入兑现时间表 + +## 第二步:台账模板 + +(下表示例行仅演示格式与填法:线索归属、兑现章节、"酒吧招牌的霓虹色"等字段值为占位示意。) + +| # | 元素 | 显著信号(位置/重复/特写/对话) | 装饰/债务 | 线索归属(plot thread) | 尺度 | 埋设位置(章/卷) | 预计兑现位置(章/卷) | 实际兑现位置 | 状态 | +|---|------|------------------------------|-----------|------------------------|------|------------------|----------------------|--------------|------| +| 1 | 墙上挂的猎枪 | 位置+对话 | 债务 | 主线:复仇 | 中期 | 第 1 章 | 第 8 章 | 第 8 章 | 已兑现 | +| 2 | 孩子的红雨衣 | 特写 | 债务 | 支线:失踪案 | 长期 | 第 1 卷 | 第 5 卷(显式标注最终兑现卷) | —— | 待兑现 | +| 3 | 酒吧招牌的霓虹色 | 特写 | 装饰 | 无 | —— | 第 3 章 | 无 | —— | 删除测试后删 | + +字段说明: + +- **线索归属**:线索是人物/事件级叙事线(如"主角追查父亲死因"),伏笔是元素级承诺;一条线索可含多个伏笔,一个伏笔可跨多条线索,两者分开管理。 +- **尺度**: + - **短期**:同章/同幕内兑现(5-30 页内回收)。例:章末"她看见了那封信" → 章内"信里是离婚协议"。 + - **中期**:同卷/同一故事弧内兑现(50-200 页内回收)。例:第 1 章"父亲的旧钥匙" → 第 8 章开门。 + - **长期**:全书/全系列内回收(30 万字 / 5 本书)。例:第 1 卷"主角的母亲从未出现" → 第 5 卷"母亲身份的揭示"。 +- **状态**:待兑现 / 已兑现 / 已删除 / 已弱化。 + +## 第三步:兑现时间表(埋 → 兑现对应表) + +左边是"埋",右边是"兑现",中间是章节/卷数: + +| 埋(元素 + 位置) | 章节/卷数跨度 | 兑现(方式 + 位置) | +|-------------------|---------------|---------------------| +| | | | + +兑现校验标准: + +- 所有**短期伏笔**都在同章/同幕内兑现 +- 所有**中期伏笔**在 200 页内有兑现节点 +- 所有**长期伏笔**有显式"最终兑现卷/章"标注 +- 跨度 > 30 万字或 > 3 卷的长期伏笔:定期回顾本台账,防止"线索失踪" +- 找不到兑现点的伏笔:**删除**或**降低显著度**,不留"承诺但不兑现" + +## 网文/连载补充(中文适配) + +Clark 的台账针对中短篇,网文百万字连载/跨 5+ 卷系列需要自行补充: + +- 台账工具:Notion / Airtable / Excel +- 多人合写:加一张"伏笔分配表"(谁埋的、谁负责收) +- 双轨追踪:分别记录"读者已知"与"角色已知",两条轨道都要对得上 diff --git a/framework/catalog/dsh/skills/foreshadow-payoff/references/natural-staircase.md b/framework/catalog/dsh/skills/foreshadow-payoff/references/natural-staircase.md new file mode 100644 index 0000000..4fc32f4 --- /dev/null +++ b/framework/catalog/dsh/skills/foreshadow-payoff/references/natural-staircase.md @@ -0,0 +1,120 @@ +# 铺垫术:给读者的接受度修楼梯 + +> 本文件管伏笔链路的埋设端:怎么把特殊人物/事件埋得自然、不突兀。登记与兑现见 [register-and-repay.md](register-and-repay.md);高潮怎么从细节生长见 [detail-driven-climax.md](detail-driven-climax.md);边界与误区见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> 「铺垫就是修楼梯。二楼到一楼有三米高,一个大妈如果从二楼直接跳到一楼,大妈的腿就得断。」 + +## 方法核心 + +**铺垫 = 修楼梯**。让你的"特殊事物"通过几级"普通台阶"自然进入读者视野。 + +**关键洞察**:铺垫不是给"特殊事物"找合理性,而是给"读者的接受度"找台阶。 + +### 书中原文:奈保尔怎么写第五个乞丐 + +奈保尔写第五个乞丐(诗人沃滋沃斯)出场前,**先写了四个乞丐**。每个乞丐只用一句话: + +``` +第一个乞丐:…… +第二个乞丐:…… +下午两点,一个盲人由一个男孩引路,来取走他的那一分钱。 +第四个乞丐:…… +``` + +**结果**:第五个乞丐(沃滋沃斯)出场时,读者已经接受了"这里有很多奇怪的乞丐"——他再特殊也不突兀了。 + +**没有这四步**:一个"乞丐兼诗人"突然出现,读者会本能地觉得"太特殊、太做作"。 + +## 案例 + +### 案例 1:奈保尔四个乞丐 → 沃滋沃斯 + +- 4 个普通乞丐 → 1 个特殊诗人 +- **每个乞丐只 1 句话**——简洁是铺垫的灵魂 + +### 案例 2:施耐庵《水浒》林冲出场 + +- 写林冲"走"上梁山之前,先写**风**、**雪**、**石头**——这些"环境物"不是闲笔,是给"林冲的转变"修楼梯 +- 没有雪 → 林冲不会去烤火 → 不会离开房间 → 不会听到阴谋 → 不会杀人 → 不会上山 +- 每一级台阶都是必然 + +### 案例 3:蒲松龄《促织》驼背巫 + +- 写驼背巫之前,先写**成名搜虫、捕虫、失败、被责、寻死**——五次失败 = 五级台阶 +- 没有这五级,驼背巫的"神卜"就不显得必要 + +### 案例 4:蒲松龄《促织》斗蛐蛐 + +- 斗蛐蛐之前,必须先有**"将献公堂,惴惴恐不当意,思试之斗以觇之"**——这一句是**左腿** +- 斗蛐蛐 = **右腿** +- 没有这一句,斗蛐蛐就是不自然 + +## 可执行步骤 + +### 步骤 1:识别"特殊物" + +列出你小说里**读者会觉得突兀**的元素: + +``` +特殊人物:杀人犯 / 乞丐诗人 / 性格怪癖的人 +特殊事件:不可能发生的巧合 / 超自然事件 / 极端选择 +特殊场景:异国他乡 / 历史时期 / 极端环境 +``` + +### 步骤 2:设计 2-4 级"普通台阶" + +每个台阶是**一个独立的、普通的、看起来和主题无关的细节**: + +``` +台阶 1:写一个普通的同类物(普通乞丐) +台阶 2:再写一个普通的同类物 +台阶 3:写一个稍微特殊的同类物 +台阶 4:你的特殊物出场(已经不再突兀) +``` + +**关键**:每个台阶要"独立"——读者不能一眼看出这是台阶,要读完后才恍然。 + +### 步骤 3:保证简洁 + +**每个台阶 = 1-3 句话**。铺垫最忌讳"啰唆"——它会变成小说内部的"肿瘤"。 + +> 「简洁是短篇小说的灵魂,也是短篇小说的秘密。」——毕飞宇 + +### 步骤 4:做"去掉铺垫"测试 + +写完后,把所有铺垫删掉,看你的特殊物: + +- [ ] 突兀?→ 铺垫不够,加 1 级 +- [ ] 还能接受?→ 铺垫可能太多,删 1 级 +- [ ] 反而更自然?→ 你可能没真正铺垫,只是堆细节 + +### 步骤 5:铺垫的隐藏法则 + +**好的铺垫要有"双重功能"**: + +- 表层功能:让特殊物出场自然 +- 深层功能:本身要承担情节/主题/性格描写 + +海明威《杀手》的环境铺垫不只是"做气氛"——它同时塑造了乔治这个人物。 + +## 什么时候用这个单元 + +1. 你的"特殊人物/事件"出场时读者可能觉得突兀 +2. 短篇/开头需要快速建立世界观 +3. 主人公命运大转折前 +4. 反派/异类登场 +5. 任何"不可能的事情"在小说内部必须变得"可能" + +## 一句话总结 + +> **特殊物出场前,先让读者见 2-4 个普通同类。每个同类只 1-3 句话。** + +## 适用边界 + +- **适合**:短篇、超短篇、长篇关键场景 +- **不适合**:长篇的章节切换(可以用整章铺垫) +- **不适合**:节奏要求快的惊悚/悬疑(铺垫要短到极致) + +常见错误表见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 diff --git a/framework/catalog/dsh/skills/foreshadow-payoff/references/register-and-repay.md b/framework/catalog/dsh/skills/foreshadow-payoff/references/register-and-repay.md new file mode 100644 index 0000000..1e25c3a --- /dev/null +++ b/framework/catalog/dsh/skills/foreshadow-payoff/references/register-and-repay.md @@ -0,0 +1,132 @@ +# 埋设决策与伏笔台账:显著元素就是借款 + +> 本文件管伏笔链路的埋设端:哪些元素必须埋、怎么登记、在哪偿还。埋设怎么做到不露痕迹,见 [natural-staircase.md](natural-staircase.md);高潮怎么从细节生长,见 [detail-driven-climax.md](detail-driven-climax.md);边界与误区见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> In dramatic literature, this technique inherits the name Chekhov's Gun. In a letter he penned in +> 1889, Russian playwright Anton Chekhov wrote: "One must not put a loaded rifle on the stage if +> no one is thinking of firing it." Do you ever violate the principle of Chekhov's Gun? Do you place +> seemingly significant elements high in your work that never come into play again? +> +> — Roy Peter Clark, *Writing Tools* (Tool 29) + +契诃夫原话的通行表述:「如果没人打算开枪,就不要把上膛的步枪放到舞台上。」另一个版本:「如果第 1 幕墙上挂了一把枪,第 3 幕它必须开火。」 + +## 方法核心:三个机制 + +Clark 提出的不是单一原则,而是**一组围绕"显著元素必须被使用"的因果决策框架**,有三个核心机制: + +1. **埋伏 + 兑现的因果链**——任何"被显著引入"的元素(挂在墙上的枪、被反复提起的名字、刻意描述的物件)都在向读者**借款**。读者无意识记下这些"准记忆"。如果后续不提,读者会感到"作者控不住结构"。伏笔管理 = 借债台账管理。 +2. **分时间尺度(短 / 中 / 长)**——短篇里 3 页兑现,长篇里 30 万字兑现,系列里 5 本兑现。Clark 用 Hitchcock 的"暴露的羊腿"演示"短程伏笔"——标题里已告诉读者"羊腿是凶器",凶器当场兑现。Chekhov 原版是"中长程"——舞台第 1 幕,剧本第 3 幕。 +3. **删除测试(decision filter)**——Clark 的关键操作化工具:写完一段,问"如果删掉这个元素,故事是否变轻?"如果不变轻 → 它没承担叙事债务 → 删;如果变轻 → 它就是该被回收的伏笔。 + +**判断标准**:一个元素是"装饰"还是"债务"——取决于它是否被**显著呈现**(被镜头对准、被台词提及、被位置强调)。一旦被显著,就是借款,必须偿还。 + +**理论定位**:这是"结构-因果"层面的方法论(像 story-engine 是"问题-驱动"),不是"风格-修辞"层面(像 voice-equalizer)。它管的是"哪个元素必须存在",不是"这个元素怎么写得更好"。 + +## 操作清单(作者应自问) + +1. 写场景时:墙上这把枪会开火吗?如果不,弱化或删。 +2. 写转折前:我前面给读者埋下可信的钩子了吗? +3. 写章节末:这个元素是"装饰"还是"债务"?如果是债务,它在哪一章兑现? +4. 通读时:用删除测试扫一遍——哪些元素删掉后故事没变轻,就该删。 + +## Hitchcock 变体("已暴露的凶器") + +Chekhov 强调"枪必须开火"但**不必告诉观众它是凶器**;Hitchcock 反过来——**凶手在标题就暴露**(《Lamb to the Slaughter》"给屠夫的羔羊"=羊腿),读者看着"羊腿"登场即知其宿命,凶手戏仍成立,因"如何被用作凶器"本身仍是悬念。 + +**中文用法(中文适配)**:章名/卷名可借鉴——把关键元素**预先命名**,让读者带着"我等着看它怎么兑现"的预期进入。 + +变体给出的反直觉选项:**告诉读者你要兑现,让读者等兑现方式**。伏笔不一定"藏"——预暴露的凶器也是有效伏笔(戏剧反讽:观众比角色知道得早)。 + +## 伏笔与线索要分开管理 + +与"线索"(plot thread)的区别:线索是**人物/事件级别的叙事线**(如"主角追查父亲死因"是线索);伏笔是**具体元素级别的承诺**(墙上挂的猎枪是伏笔)。一条线索可包含多个伏笔,一个伏笔可跨多条线索。台账上两者要分别管理。 + +## 案例 + +### 案例 1:Anton Chekhov 1889 年关于"舞台上的枪"的信 + +- **问题**:戏剧/小说中如何避免"无关紧要的细节"稀释紧张感? +- **方法论的使用**:Chekhov 写信给同行,提出"如果第 1 幕墙上挂了一把枪,第 3 幕它必须开火"——这是**场景经济学的最严苛版本**:每一个被引入的显著元素都必须"做工"。 +- **结论**:元素是"装饰"还是"债务",**取决于它是否被显著呈现**。一旦被镜头/语言突出,就被读者标记为"重要",必须后续兑现。 +- **结果**:成为了西方戏剧/小说"伏笔管理"的金标准。所有关于 foreshadow、payoff、setup 的讨论都回到这条原则。 + +### 案例 2:Alfred Hitchcock《Lamb to the Slaughter》(希区柯克变体) + +- **问题**:Chekhov 说枪必须开火,但能否让读者**提前知道**它是凶器? +- **方法论的使用**:Hitchcock 在**标题**就告诉读者"羊腿会被杀"(lamb to the slaughter = 羔羊赴屠),读者带着"我等着看它怎么杀人"进入故事。戏剧张力不靠"谁干的",而靠"她怎么用一根无辜的羊腿杀人 + 警察怎么吃掉证据"。 +- **结论**:伏笔不一定"藏"——**预暴露的凶器**也是有效伏笔(戏剧反讽:观众比角色知道得早)。这种"变体"给了写作者一个反直觉选项:**告诉读者你要兑现,让读者等兑现方式**。 +- **结果**:成为了"伏笔不一定要藏"教学的标准案例;也展示了"已暴露的凶器"如何制造与 Chekhov 不同类型的悬念(what vs how)。 + +## 可执行步骤 + +### 步骤 1:建立伏笔台账(列出显著元素) + +- 列出当前章节/全书所有"被显著呈现"的元素(被镜头特写、被台词反复提及、被位置重点强调)。 +- 完成标准:每个元素被标注"装饰"或"债务";装饰项可考虑删除/弱化;债务项必须进入兑现时间表。 +- 判停条件:如果不知道哪些是显著元素,用这条判据——任何被**位置**(墙/桌上/口袋)、**重复**(提 2 次以上)、**特写**(用 1 段以上描写)或**对话**(被角色直接说出的)命中的元素。 + +台账模板见 [../references/foreshadow-ledger-template.md](foreshadow-ledger-template.md)。 + +### 步骤 2:按时间尺度分层(短 / 中 / 长) + +- **短期伏笔**:同章/同幕内(章末钩子 → 章内兑现,5-30 页内回收)。例:章末"她看见了那封信"→ 章内"信里是离婚协议"。 +- **中期伏笔**:同卷/同一故事弧内(50-200 页内回收)。例:第 1 章提到的"父亲的旧钥匙" → 第 8 章开门。 +- **长期伏笔**:全书/全系列(30 万字 / 5 本书内回收)。例:第 1 卷"主角的母亲从未出现" → 第 5 卷"母亲身份的揭示"。 +- 完成标准:每个伏笔被标注"短/中/长" + "预计在第 X 章/卷兑现"。 +- 判停条件:如果长篇伏笔跨度 > 30 万字或 > 3 卷,应**显式提示**定期回顾台账(否则就是"线索失踪"失败模式)。 + +### 步骤 3:应用删除测试(决定保留/弱化/删除) + +- 对每个标注为"装饰"的元素,问:"如果删掉它,这个场景/章节/全书是否变轻?" +- 不变轻 → 真的只是装饰 → 删。 +- 变轻 → 隐性债务,要么加强(让它"显著")以进入伏笔台账,要么删除/弱化避免误导读者。 +- 完成标准:能对每个候选元素给出"留 / 删 / 加强"决定,理由是"删除后变轻"还是"不变轻"。 +- 判停条件:不要在初稿阶段用删除测试——它在**修订阶段**最有效(初稿时你不知道哪些元素会"被用上")。 + +### 步骤 4:设计 Hitchcock 变体(选择性,非必须) + +- 问:这个伏笔是否适合**预暴露**?如果答案是"读者提前知道会更有张力"(戏剧反讽),用标题/章名/对话明示。 +- 不适合的场景:核心谜题(读者不知道才能猜)、情感爆点(读者预期外才有冲击)。 +- 适合的场景:读者已经知道"会发生什么"但"不知道会怎么发生"——把悬念从 what 移到 how。 +- 完成标准:能说出"这个伏笔是 Chekhov 经典款(藏)还是 Hitchcock 变体(暴露)"。 + +### 步骤 5:写兑现时间表(章节/卷对应) + +- 输出一张"伏笔台账 → 兑现表"——左边是"埋",右边是"兑现",中间是章节/卷数。 +- 完成标准:表格中所有"短期伏笔"都在同章/同幕内兑现;所有"中期伏笔"在 200 页内有兑现节点;所有"长期伏笔"有显式"最终兑现卷/章"标注。 +- 判停条件:如果某伏笔找不到兑现点,**删除**或**降低显著度**(不要让它成为"承诺但不兑现"——"线索失踪"失败模式)。 + +## 什么时候用这个单元 + +用户会在这些情境下需要"登记与兑现"这套方法: + +1. 长篇写到一半,发现第 3 章埋的某个角色后文没再出现——读者评论"那个 X 怎么了"? +2. 写了一堆"细节马赛克"但分不清哪些是"装饰"哪些是"债务",全留下来导致中段拖沓。 +3. 设计大长篇 30 万字 / 系列小说 5 本,不知道每个伏笔该在哪兑现——想"埋伏"但怕"埋了没收"。 +4. 写悬疑/推理:既想给读者"我猜到了"的满足,又怕"剧透式标题"让悬念全无,问"凶器能不能提前暴露"? +5. 网文连载:每一卷要兑现本卷伏笔 + 保留系列伏笔,问"短/中/长期伏笔怎么分层"? +6. 写完一个场景,觉得"这段描写很美但不知道为什么要写",但又不敢删——想确认它是否"做工"。 +7. 重读自己写的稿子,发现 5 章前一笔带过的细节现在没空间兑现——是该回头补还是删伏笔? +8. 编辑/读者反馈"你前面说的那个事没后文",但作者不记得说过什么——需要"伏笔台账"工具。 + +语言信号(用户的话里出现这些就应激活): + +- "契诃夫之枪" / "chekhov's gun" / "Chekhov 原则" +- "伏笔" / "foreshadow" / "铺垫" / "前情" +- "伏笔如何兑现" / "伏笔怎么收" / "伏笔怎么写" +- "伏笔分层" / "短期伏笔 / 中期伏笔 / 长期伏笔" / "多线伏笔" +- "线索失踪" / "线索埋了没收" / "埋了忘了" +- "显眼的凶器" / "Hitchcock 变体" / "预暴露的伏笔" +- "删除测试" / "这个细节要不要留" / "场景经济" +- "承诺但不兑现" / "前面挖的坑没填" +- "哪里该埋伏笔" / "哪里该回收" + +## 中文落地说明 + +Clark 写的是英文写作语境,迁到中文长篇/网文时注意: + +- **章回体传统天然支持 Hitchcock 变体**:章名/卷名预先点名关键元素("林教头风雪山神庙"式的章名),读者带着等待兑现的预期进入,这正是"预暴露"的中文母体。(中文适配) +- **台账工具本土化**:Clark 没有给网文百万字连载的系统方案,中文长篇需要自己补台账(Notion / Airtable / Excel)、多人合写的"伏笔分配表"、"读者已知 vs 角色已知"的双轨追踪。详见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md) 的盲点一节。(中文适配) diff --git a/framework/catalog/dsh/skills/narration-pov/SKILL.md b/framework/catalog/dsh/skills/narration-pov/SKILL.md new file mode 100644 index 0000000..634d77c --- /dev/null +++ b/framework/catalog/dsh/skills/narration-pov/SKILL.md @@ -0,0 +1,66 @@ +--- +name: narration-pov +description: | + 中文小说写作中选择视角、叙述立场和叙述模式时使用。激活场景:选视角人物并决定向读者透露多少信息;想揭示封闭组织、社区、制度的荒谬而不说教;想写开放式结局、暧昧关系、命运类故事让读者回味;想避免作者跳出来下判断、给简单答案;决定何时暂停主线去做反思、插叙、独白、闪回并落回主线。 + 关键 trigger:视角、POV、全知、限制视角、外来者视角、局外人、叙述立场、怀疑、说教、太直白、开放式结局、不确定性、留白、插叙、倒叙、意识流、内心独白、主线太平、折线落不回去、主线与折线、折线、汽笛站、卡夫卡式、fish out of water、broken line。 + 不适用于:无叙事时间的纯抒情诗或散文;千字以内的单场景小品;推理悬疑等结尾必须给出确定答案的作品;需要明确价值观引导的儿童文学;需要明确立场的议论文、社论;纯对话剧本(对话的功能见 dialogue-craft)。 + 与 theme-and-stance 交接:远距荒诞外来者(布尔加科夫式撒旦访莫斯科)的完整案例与幽默结构归 theme-and-stance;本 Skill 只保留外来者切入机制,案例见 references/outsider-entry.md 第三节指针。 +--- + +# 叙述与视角(narration-pov) + +管三件事:用谁的眼睛看(视角),站在什么立场讲(叙述立场),讲的过程怎么走(确定与不确定的张力、主线与折线的调度)。 + +## 方法索引 + +按创作动作组织。方法细节、操作步骤、判断标准、案例全文、原文摘录都在 references/ 里,本文件只做指针。 + +- **选视角人物、定信息范围**:视角是摄像头——人物看到什么读者才看得到,视角人物的判断就是隐形叙述,视角转换就是真相揭示 → references/pov-camera.md +- **落地视角限制**:五步——主视角设定卡、看世界的滤镜、知情范围与视角数量、视角转换点、用盲区藏秘密;含触发场景、适用边界、常见错误 → references/pov-execution.md +- **用外来者揭开封闭系统**:不直接批判,让一个外来者进入组织/社区/制度/文化;碰壁场景加内部人麻木做对比,荒谬自行呈现 → references/outsider-entry.md +- **立怀疑的叙述立场**:看法会陈旧、事实不会;把看法替换成事实、肯定后跟否定、写表层之下的一层、结尾不收死 → references/skeptical-stance.md +- **构造确定与不确定的张力**:方向 A 从不确定走向确定但始终没走到,方向 B 从确定走向不确定但没成功;锚点与屏障并设,让读者的想象力在两极间徘徊 → references/certainty-uncertainty.md +- **调度主线与折线**:主线运行动,折线停车上意义,折线必须落回场景锚;SCENE/BREAK 标注、比例 2:1、500 字回归、三条判停条件 → references/broken-line.md +- **边界与常见误区**:各方法的适用边界、失败模式、作者盲点、易混淆的邻近方法,随各自方法记在对应 references 文件的末尾各节 +- **执行检查清单**:设定、写作中、修订三阶段的核对清单与快速排错表 → references/narration-pov-checklist.md + +视角人物说出/想到视角之外的信息(知识诅咒逐句检查)归 show-and-omission;伏笔的埋设与回收归 foreshadow-payoff;章末钩子归 narrative-momentum;摄影机距离归 scene-craft;对话的功能归 dialogue-craft。本 skill 只管上述三件事。 + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|---------| +| references/pov-camera.md | 视角 = 摄像头三原则、开篇引文、海明威《杀手》障眼法 R 原文、四案例全文(《杀手》/《故乡》/《布莱克·沃滋沃斯》/《红楼梦》王熙凤(多视角看可卿,标题保留源单元原文))、视角的"重"和"轻"、一句话总结、中文落地 | +| references/pov-execution.md | 视角限制五步执行(主视角 yaml 卡、滤镜三问、知情范围与短篇 1-2 / 长篇每章、转换点设计、盲区藏秘密)、触发场景五条、适用边界(含第二人称慎用)、常见错误五行、跨 skill 链接四条 | +| references/outsider-entry.md | 外来者切入法:熏肉切刀引文全量、三机制(内部人麻木/外来者不适应/自行呈现)、三案例全文(《城堡》K 进村、余华 1983 北京问路、《大师和玛格丽特》撒旦访莫斯科)、六步执行、触发场景、边界三条、失败模式两条、盲点两条、易混淆两条、中文落地 | +| references/skeptical-stance.md | 怀疑主义叙述法:四条引文全量、看法陈旧/事实不陈旧/怀疑优于肯定、三实践、写作改变人、三案例全文(博尔赫斯《沙之书》、蒙田、干渴与对干渴的恐惧)、五步执行(含信号词)、边界三条、失败模式两条(含权威自负引文)、盲点两条、易混淆两条、与 certainty-uncertainty 的合并标注 | +| references/certainty-uncertainty.md | 确定性-不确定性张力:哥廷根演讲引文两段全量、方向 A/B、三案例全文(格奥尔基《悲伤的物理学》粘信封、沙拉莫夫《大夫三死》退后一步向前一步、博尔赫斯迷宫)、五步执行(锚点/屏障/自检)、边界三条、失败模式两条、盲点两条、易混淆两条、与 skeptical-stance 的合并标注 | +| references/broken-line.md | 混合叙事模式:Tool 36 英文原文全量 + 译文、unbroken/broken line 二分与火车比喻、切换三规则、两案例全文(哈姆雷特独白、《Alfie》打破第四面墙)、三步执行含判停条件、边界四条、失败模式三条(含英文引文)、盲点与时代局限四条、易混淆三条、相关 skill 记录全量、中文落地 | +| references/_coverage.md | 覆盖对照表:五个源单元全部方法点的落点核对 | +| references/narration-pov-checklist.md | 执行检查清单:视角设定卡、封闭系统与外来者、看法入侵扫描、确定-不确定张力自检、主线/折线标注诊断(含量化阈值与判停条件)、快速排错表 | + +## 脚本 + +| 脚本 | 用途 | 来源 | +|------|------|------| +| references/narration-pov-checklist.md | 叙述与视角检查清单:按写作进程排列(设定阶段视角设定卡;写作中外来者与看法入侵扫描;修订阶段张力自检、主线/折线标注诊断含 SCENE/BREAK 比例与 500 字回归判停),附快速排错表 | 五个源单元的执行步骤合并 | + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 红线 + +- 只给当前创作阶段的建议,不越权改设定主权、不绕过检测链、不复制粘贴其它 Skill 的 owner 定义。 +- 无用户明确授权不得替用户定稿或提交 Git。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/dsh/skills/narration-pov/references/_coverage.md b/framework/catalog/dsh/skills/narration-pov/references/_coverage.md new file mode 100644 index 0000000..5249337 --- /dev/null +++ b/framework/catalog/dsh/skills/narration-pov/references/_coverage.md @@ -0,0 +1,14 @@ +# narration-pov 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| bifeiyu-novel-skill/bifeiyu-perspective | references/pov-camera.md | +| bifeiyu-novel-skill/bifeiyu-perspective | references/pov-execution.md | +| wo-neng-fou-xiang-xin-zi-ji/certainty-uncertainty-tension | references/certainty-uncertainty.md | +| wo-neng-fou-xiang-xin-zi-ji/certainty-uncertainty-tension | references/skeptical-stance.md | +| wo-neng-fou-xiang-xin-zi-ji/outsider-perspective | references/outsider-entry.md | +| wo-neng-fou-xiang-xin-zi-ji/skeptical-narration | references/skeptical-stance.md | +| wo-neng-fou-xiang-xin-zi-ji/skeptical-narration | references/certainty-uncertainty.md | +| writing-tools-clark/mix-narrative-modes | references/broken-line.md | diff --git a/framework/catalog/dsh/skills/narration-pov/references/broken-line.md b/framework/catalog/dsh/skills/narration-pov/references/broken-line.md new file mode 100644 index 0000000..961577a --- /dev/null +++ b/framework/catalog/dsh/skills/narration-pov/references/broken-line.md @@ -0,0 +1,131 @@ +# 混合叙事模式:主线与折线的调度 + +> 来源单元:《写作工具》(Roy Peter Clark)writing-tools-clark/mix-narrative-modes,Tool 36 · Mix narrative modes。 +> 可执行的标注诊断流程见 [../references/narration-pov-checklist.md](narration-pov-checklist.md) 第五节。 + +## R 原文(英文全量 + 中文译文) + +> The writer tells us a story, then stops the story to tell us about the story, but then +> returns to the story. Imagine this form as a train ride with occasional whistle stops. +> +> Think of its opposite, the unbroken line. Most movies are unbroken narrative lines. +> Frodo takes possession of the ring of power and sets out on a journey to destroy it. +> On occasion, a director will break the line of narrative for some other purpose. In +> the movie Alfie, the main character stops the action, turns to the camera, and speaks +> to the audience. +> +> — Roy Peter Clark, *Writing Tools* (Tool 36)() + +译文:作家给我们讲一个故事,然后停下来讲关于这个故事的事,接着再回到故事本身。可以把这种形式想象成一趟偶尔在"汽笛站"停靠的火车旅程。想想它的反面——不断线。大多数电影就是不断的叙事线:弗罗多拿到至尊魔戒,出发去销毁它。偶尔,导演会为了别的目的打断叙事线:电影《Alfie》里,主角停下动作,转身面对镜头,直接对观众说话。(中文译文;原文) + +## 方法核心:叙事时间结构的两个极端 + +Clark 的核心二分法是关于**叙事时间结构**的两个极端: + +- **unbroken line(主线 / 不断线)**:按事件时间一路推进——Frodo 拿戒指 → 出发 → 毁戒指;James Bond 接任务 → 救世界 → 抱得美人。读者被"运"着走,沉入动作。 +- **broken line(折线 / 断线)**:在主线的某一点"鸣笛停车"——暂停动作去做解释、反思、评论、独白、跳到另一时空(回忆、闪前、意识流),再**落回**主线。 + +Clark 的核心比喻是**一趟带"汽笛站"(whistle stops)的火车**:场景 = 行进,折线 = 停车上货(意义层);列车必须重新启动。 + +何时切换?三条规则: + +1. 主线太单薄 → 加 1-2 个折线段给"altitude gain"(意义高度); +2. 折线过多读者缺氧("too much ozone")→ 立刻落回主线场景给具体人、物、动作; +3. 任何折线**必须"起落"配对**——出去解释/反思/独白,必须回到场景锚(scene anchor)。 + +判断口诀:每段尾读者是否知道"我现在在火车的哪一节、哪一站"?若是,结构正确;否则就是断线事故。() + +## 书中案例 + +### 案例 1:哈姆雷特独白("To be or not to be") + +- **问题**:在最忙乱的动作中,如何揭示人物心理而不打断节奏? +- **方法论的使用**:哈姆雷特在最紧张的剧情中**暂停动作**,长篇独白"生存还是毁灭,这是个问题"——Clark 明示:"does not advance the story, but reveals Hamlet's indecision." 这是**典型折线**:不推进动作,但揭示犹豫、抑郁、哲学化倾向。 +- **结论**:折线 = 主线(动作)中的跳出(自省 / 解释 / 评论 / 独白);节奏由动转静,但读者被"洞察"抓住,不离场。 +- **结果**:成为了"在快速动作中插入人物心理"的西方文学原典。Clark 把它作为"戏剧性折线"的标杆案例引用,与莎翁其他悲剧独白并列。 + +### 案例 2:电影《Alfie》主角对镜头独白 + +- **问题**:如何用比"内心独白"更激进的方式跳出主线? +- **方法论的使用**:主角 Alfie 停下手头动作,**直接转身面对镜头说话**——打破第四面墙,等于把读者/观众当对话者呼告。Clark 描述:"the main character stops the action, turns to the camera, and speaks to the audience. These surprise monologues reveal the corners of his character and foreshadow plot complications." +- **结论**:折线的极端形态 = 跳出"虚构世界契约"本身,把读者/观众当对话者。比哈姆雷特更激进(哈姆雷特仍是在虚构世界内说话)。 +- **结果**:成为了"打破第四面墙"的现代电影/小说标杆;在中文写作里常被类比为**第一人称元叙事**、**小说人物直接对读者说话**。 + +(以上两例均出自) + +## 执行步骤 + +1. **诊断结构 + 标注主线 / 折线** + - 取出章节 / 手稿,把每段标注为 `SCENE(主线,事件在动)` 或 `BREAK(折线:解释 / 反思 / 独白 / 插叙 / 意识流 / 旁白评论)`。 + - 完成标准:每段有清晰标注;读者一眼看出"现在是在火车上,还是停在汽笛站"。 + - 判停条件:若折线段后 500 字内无 SCENE 回归,标记为"断线事故",需补场景锚。 + +2. **检查"起落"平衡** + - 数主线与折线比例:折线 ≤ 30-40%(否则读者缺氧)。一段折线后必须接 1-2 段 SCENE。 + - 完成标准:全章 SCENE ≥ BREAK 比例约 2:1;每个 BREAK 段后 ≤ 500 字回到 SCENE。 + - 判停条件:若 BREAK 段 > 1000 字且无 SCENE 锚回,拆为更小段,或改写为 SCENE 内的对白 / 动作。 + +3. **加 altitude gain(意义层)或落回 scene(场景层)** + - 在每个长 SCENE 段后问:"读者会不会问'so what?'"——若是,加 1 段 nut paragraph 回答(给意义高度)。 + - 在每个 BREAK 段后问:"读者知道我在哪个时间、哪个场景吗?"——若是,落回具体物、人、动作(场景锚)。 + - 完成标准:任何 BREAK 段尾**必须有 scene anchor**(具体物、人物动作、可感的环境);任何长 SCENE 后**至少有 1 段 altitude**(反思、解释、主题意义)。 + - 判停条件:若一段独白/插叙尾只有抽象句而无具体动作,改写为"动作 + 短句反思"或转回 SCENE。 + +() + +## 触发场景 + +1. 写小说主线一路平铺,觉得"太平、太流水账",不知何时插一段解释/反思/独白。 +2. 想做复杂时间线(倒叙、插叙、意识流、多 POV),但写出来读者弃读——折线没"落回"。 +3. 写了一段漂亮的独白/插叙,但段落"出得去回不来"——读者在折线尾迷失"我刚才离开了哪个时间、哪个场景"。 +4. 写非虚构(报告文学、特稿、长报道),故事讲着讲着"信息密度"压垮读者,需要"场景→解释→回到场景"的呼吸。 +5. 多 POV / 多时间线小说,不知"何时切到回忆、何时切回当下、何时停在高空讲主题"。 + +语言信号:"mix narrative modes""broken line""主线 vs 折线""unbroken line""whistle stop""nut paragraph""何时跳出动作""何时回到场景""scene + altitude""意识流 vs 主线""倒叙怎么用""插叙落不回去""独白放在哪里""独白用错位置""打断第四面墙""小说节奏""章节结构""时间线设计""POV 切换""折线太多读者弃读""主线太平""何时解释何时叙事""so what 段落"。() + +## 边界:不要在以下情况使用 + +- **单场景小品 / 千字以内短篇**——没有足够长度玩主线/折线切换,折线会被压成噪音。 +- **纯抒情诗 / 散文诗**——叙事时间不是骨架,Clark 的火车比喻不适用。 +- **纯对话剧本(话剧)**——折线靠独白/旁白完成,话剧默认场内连续时间,改用 dialogue-as-action(归综合 skill dialogue-craft)。 +- **短消息 / 推文 / 短资讯**——没有"主线"载体,谈折线无意义。 + +() + +## 作者在书中警告的失败模式 + +- **bait and switch(诱骗式切换)**:开篇用叙事 lead 假装讲故事,实际通篇是信息密度。Clark 明示:"No reader wants to be fooled by a story lead that promises narrative, only to discover a body dense with information." 机制:折线挤掉了主线,读者在汽笛站下车找不到回程列车。 +- **too much ozone(高空缺氧)**:折线叠折线,读者一直停在"意义层"不见地面。Clark 借 Lemann 之例警告:"too much ozone can leave the reader feeling oxygen deprived." 信号:连续 3 段以上无场景锚(无具体人、物、动作)。 +- **whistle stop without train(汽笛站没有列车)**:一段独白/插叙**只出去不回来**——读者在段落尾不知道"我刚才离开了哪个时间、哪个场景"。机制:折线段落结尾无 scene anchor(具体物、人物动作、可感的环境)。Clark 的隐含标准:折线必须**以场景落回**,不是以抽象反思收尾。 + +() + +## 作者的盲点 / 时代局限 + +- Clark 的 broken line 例子偏**非虚构**(Nicholas Lemann 的《The Promised Land》、WSJ 特稿),小说例子偏**戏剧性独白**(哈姆雷特、Alfie、Our Town、Rocky Horror)。**当代中文长篇小说(多 POV、多时间线、心理现实主义)**的折线模式未深入展开,作者需自己类比——把"soliloquy"换成"意识流 / 内心旁白 / 时空跳转",把"altitude gain"换成"主题反思 / 作者介入"。 +- 时代局限:Clark 写于 2006 年,未涵盖**网文 / 类型小说(穿越、悬疑、多线叙事、意识流)**——这些文体的折线模式(如"现实层 / 系统层 / 记忆层"三线并行)有更激进的结构,需结合原型工具与章内钩子一起用(archetype-toolkit 归 character-design、internal-cliffhanger 归 narrative-momentum)。 +- 文化迁移:"soliloquy / 独白"在西方戏剧传统中是被观众接受的(从莎翁到现代剧);中文小说大量使用"内心独白"会被部分读者视为"作者代笔"——折线在中文写作中**密度需更低**,且落回场景的速度需更快。 +- 反例:Clark 引用的"古董色情片白大褂治疗师"做"redeeming social value"说明("so I've been told"),在中文语境下既不常见也容易触发审查,迁移时**改用哈姆雷特 / Our Town / 红楼梦判词**等更贴近中文读者的例子。 + +() + +## 容易混淆的邻近方法论 + +- 与 "show, don't tell"(Tool 27):那个管"用动作和细节显示",这个管"何时用动作、何时用解释"——前者是"如何写一个画面",后者是"何时停在画面外去讲意义"。(show, don't tell 归综合 skill show-and-omission) +- 与 "active verbs"(Tool 3):那个管"动词的力度",这个管"段落级时间结构"。(active verbs 是《写作工具》同书工具,未入本技能库) +- 与 "inciting incident"(Tool 55):那个管"开篇钩子",这个管"全程模式切换的呼吸"。(inciting incident 归综合 skill story-structure) + +() + +## 与相邻方法的区分和配合(源单元相关 skill 记录全量) + +- 与 cinematic-distances 的区别:那个管**"摄影机物理距离"**(鸟瞰到特写,Tool 34),这个管**"叙事时间结构"**(主线 vs 折线、何时离开当下动作)。一个改"看得见多近",一个改"何时离开/回到当下"。(cinematic-distances 归综合 skill scene-craft) +- 与 sentence-rhythm 的区别:那个管**"句法节奏"**(句长、停顿、对仗,Tool 18),这个管**"叙事单元时间结构"**(场景 vs 解释、独白 vs 动作的来回)。一个在句子层,一个在篇章/章节层。(sentence-rhythm 归综合 skill prose-craft) +- 与 write-toward-ending 的区别:那个管**"结尾策略"**(Tool 39,如何收束、闭合意义圆),这个管**"中段叙事模式混合"**(场景与解释、独白与动作的全程调度)。一个在末段,一个在全程。(write-toward-ending 归综合 skill story-ending) +- 与 internal-cliffhanger 的区别:那个管**"章末钩子"**(单点张力),这个管**"全程模式切换"**(段与段、章与章)。(internal-cliffhanger 归综合 skill narrative-momentum) +- 与 dialogue-as-action 的区别:那个管"对话作为单一模式的功能",这个管"对话 / 独白 / 旁白 / 场景作为模式之间的切换"——后者是更大的时间结构框架。(dialogue-as-action 归综合 skill dialogue-craft) +- 源单元相关 skill 记录:contrasts-with cinematic-distances、sentence-rhythm、write-toward-ending;composes-with dialogue-as-action(折线内的对话如何"做事")、internal-cliffhanger(折线切换点作为张力钩)、archetype-toolkit(原型决定折线的功能);depends-on:无。() + +## 中文落地说明 + +Clark 是英文书,中文落地的要点源单元已经给出:一是折线密度放低、落回场景更快——中文读者把大段"内心独白"当"作者代笔";二是把西方戏剧独白的例子换成中文读者熟悉的对应物(哈姆雷特可换《红楼梦》判词、戏曲背供),把 soliloquy 类比成意识流 / 内心旁白 / 时空跳转,把 altitude gain 类比成主题反思 / 作者介入;三是网文类型(穿越、系统、多线)的"现实层 / 系统层 / 记忆层"三线并行是比 Clark 例子更激进的折线结构,需与章内钩子配合使用。(中文落地;方法本体) diff --git a/framework/catalog/dsh/skills/narration-pov/references/certainty-uncertainty.md b/framework/catalog/dsh/skills/narration-pov/references/certainty-uncertainty.md new file mode 100644 index 0000000..09dc587 --- /dev/null +++ b/framework/catalog/dsh/skills/narration-pov/references/certainty-uncertainty.md @@ -0,0 +1,128 @@ +# 确定性-不确定性张力构造法 + +> 来源单元:《我能否相信自己》(余华)wo-neng-fou-xiang-xin-zi-ji/certainty-uncertainty-tension,出自《不确定性》演讲(2025,哥廷根大学)。 + +## R 原文 + +> "任何不确定性的对面都存在着确定性, 不确定性的出现, 是为了阻挡我们走向确定性。有时候我们走到了确定性, 有时候我们永远走不到确定性。" +> +> "这正是文学带给我们的魅力, 能够充分发挥我们的想象力, 让我们的想象力在不确定性和确定性之间徘徊, 去考虑到这些可能性的因素。" +> +> — 余华, 哥廷根大学演讲《不确定性》() + +## 方法核心 + +文学叙述的核心张力来自**确定性与不确定性之间的动态关系**。不确定性不是"没有答案",而是"阻挡我们走向确定性"——它让读者的想象力在两极之间徘徊,考虑各种可能性。 + +两种基本叙述方向: + +1. **从不确定性走向确定性,但始终没走到**:读者隐约感觉到真相,但叙述永远不给确认。格奥尔基《悲伤的物理学》中,"漂亮"这个匈牙利单词引发奶奶对爷爷的怀疑,爷爷确实有一个匈牙利女人,但奶奶永远没有抵达这个确定性——她宁愿带着不确定性死去,也不愿承担确定性带来的风险。 +2. **从确定性走向不确定性,但没成功**:结果似乎是确定的(医生要被处决),但叙述试图走向一个不确定的结局(医生救活监狱长妻儿,似乎可以不死),最终仍然回到确定性。沙拉莫夫《大夫三死》中医生第二天仍被处决。 + +好的叙述不是给出确定答案,而是让读者在确定性与不确定性之间徘徊。当不确定性比确定性更安全时,人物(和读者)会选择停在不确定性中。() + +**合并说明**:"好的叙述不是给出确定答案"与 [skeptical-stance.md](skeptical-stance.md) 的"不给出确定答案"是同一条规则——本文件管叙述结构(确定与不确定的张力怎么走),skeptical-stance.md 管叙述立场(怀疑而非肯定),立场决定结构。博尔赫斯案例两个文件都保留,角度不同:本文件取结构角度(在两极间来回走动,读者身处迷宫),skeptical-stance.md 取立场角度(怀疑、《沙之书》答案消失在无限中)。(合并标注; + skeptical-narration) + +## 书中案例 + +### 案例 1:格奥尔基《悲伤的物理学》——从不确定到确定但没走到 + +- **问题**:爷爷从匈牙利带回七个单词,其中"漂亮"让奶奶怀疑他在匈牙利有女人。 +- **方法论的使用**:爷爷确实有一个匈牙利女人(确定性),但奶奶永远没有确认——她收到一封来自匈牙利的信,看了以后什么也没说,"只是认真地又把信封粘好, 交给了她丈夫"。她宁愿带着不确定性死去,也不愿承担确定性带来的风险。 +- **结论**:叙述从不确定性(怀疑)走向确定性(真相),但人物主动停下,永远没走到。 +- **结果**:读者的想象力在"奶奶知道吗?""她为什么不确认?"之间徘徊。 + +### 案例 2:沙拉莫夫《大夫三死》——从确定到不确定但没成功 + +- **问题**:医生被判决处决,这是确定的结果。 +- **方法论的使用**:医生被拉去枪毙时,监狱长妻子难产,医生被救活监狱长妻儿,似乎可以不死(走向不确定性)。但医生认为监狱长是恶棍,退后一步宁愿去死;然后"想活下来, 哪怕再活一天一夜"又向前一步。最终第二天早上仍被处决——不确定性的尝试失败,回到确定性。 +- **结论**:从确定性(处决)出发,试图走向不确定性(不死),但没成功。 +- **结果**:读者在"他会不会死?"的悬念中经历了整个故事,最终回到确定的死亡。 + +### 案例 3:博尔赫斯——永远无法确定的叙述 + +- **问题**:博尔赫斯如何让叙述充满文学魅力? +- **方法论的使用**:博尔赫斯的叙述"总是假装地要确定下来了, 可是永远无法确定。我们耐心细致地阅读他的故事, 终于读到了期待已久的肯定时, 接踵而来的立刻是否定。" +- **结论**:博尔赫斯在确定性与不确定性之间来回走动,让读者永远在徘徊。 +- **结果**:读者身处迷宫之中,找不到出口,这正是博尔赫斯乐意看到的。 + +(以上三例均出自;案例 3 与 skeptical-stance.md 的博尔赫斯案例为同一作品、不同角度,两处都保留) + +## 执行步骤 + +1. **选择叙述方向** + - 方向 A:从不确定性走向确定性,但始终没走到(适合人物关系、秘密、真相类故事) + - 方向 B:从确定性走向不确定性,但没成功(适合命运、死亡、不可抗拒的结局类故事) + - 完成标准:明确故事采用哪种方向 + +2. **设置确定性的锚点** + - 方向 A:让读者隐约感觉到真相(通过细节、暗示),但叙述永不确认 + - 方向 B:让结局在开头就确定(如"他被判了死刑"),然后叙述试图推翻它 + - 完成标准:读者能感觉到确定性的存在,但无法抓住它 + +3. **设置不确定性的屏障** + - 方向 A:让人物主动选择不确认(像奶奶那样粘好信封),或让关键证据缺失 + - 方向 B:让人物试图改变命运(医生救人、越狱、反抗),给读者"也许会不一样"的希望 + - 完成标准:不确定性有明确的来源,不是"作者没写清楚" + +4. **让想象力在两极间徘徊** + - 不要给出最终答案 + - 可以在结尾给出一个暗示,但暗示本身应该是多义的 + - 完成标准:读者读完后会想"到底是怎么回事?"并开始自己想象 + +5. **检查张力是否有效** + - 问自己:读者能同时感觉到确定性和不确定性吗? + - 如果只有不确定性(完全没线索),读者会困惑而非回味 + - 如果只有确定性(答案太明显),读者会觉得无聊 + - 完成标准:两者并存,读者在其间徘徊 + +() + +## 触发场景 + +1. 写的故事读完就忘,没有回味空间 +2. 想写开放式结局但不知道怎么处理 +3. 想提升作品的文学性和深度 +4. 悬念设置太直白,读者一眼看穿 +5. 想让读者在阅读中主动思考和想象 +6. 写人物关系时,想保留暧昧和模糊性 + +语言信号:"故事没深度""读完就忘""开放式结局怎么写""怎么留白""怎么设置悬念""想让读者回味""文学性不够""太直白了""不确定性""暧昧""模糊"。() + +## 边界:不要在以下情况使用 + +- **推理小说/悬疑小说**:这类作品最终必须给出确定答案(谁是凶手),不确定性只存在于阅读过程中,不能在结尾保留。 +- **需要明确信息的场景**:如小说中的规则说明、世界观设定,必须确定。 +- **初学者的第一篇作品**:先学会把故事写清楚,再尝试不确定性的张力。 + +() + +## 作者在书中警告的失败模式 + +- **不确定性 = 没写清楚**:很多初学者把"留白"和"没写完"混淆。有效的不确定性是"有线索但不确认",不是"什么都没给"。 +- **为了不确定而不确定**:如果不确定性没有情感或主题的支撑,只是故弄玄虚,读者会觉得被戏弄。 + +() + +## 作者的盲点 / 时代局限 + +- 余华主要从纯文学角度讨论不确定性,没有讨论类型小说中如何平衡不确定性与读者满足感。 +- 演讲中用的例子(保加利亚小说、俄罗斯小说)较为小众,对大众读者的参考性有限。 + +() + +## 容易混淆的邻近方法论 + +- **"悬念"(suspense)**:悬念是"接下来会发生什么",本方法是"真相到底是什么"——前者是情节层面的,后者是存在层面的。 +- **"开放式结局"**:开放式结局是本方法的一种应用,但本方法也可以用在故事中间,不只是结尾。 + +() + +## 与相邻方法的区分和配合 + +- 与 [skeptical-stance.md](skeptical-stance.md):本方法是叙述结构技巧(确定性与不确定性的张力),skeptical-stance.md 是叙述立场(怀疑而非肯定)。两者经常配合——怀疑主义立场自然产生不确定性的叙述。() +- 与细节驱动高潮(detail-driven-climax)的区别:detail-driven-climax 关注情节高潮的驱动机制,本方法关注整体叙述的张力结构。一个是局部技巧,一个是全局结构。细节驱动高潮给出确定的情节转折,本方法保留不确定性,两者形成对比。(detail-driven-climax 归综合 skill foreshadow-payoff; 相关 skill 记录:composes-with skeptical-narration、contrasts-with detail-driven-climax) + +## 中文落地说明 + +方法本身无语言差异,中文写作直接可用。两个方向的中文现成参照:方向 A(有线索但不确认)接近中国古典小说的"春秋笔法"与志怪笔记里"其事可疑、不置一词"的收法,也接近当代家庭叙事里藏着不揭破的秘密(如奶奶粘信封式的动作收场);方向 B(结局开头定死、叙述试图推翻)在余华《活着》式的命运叙事里常见——读者早知道人要一个个死去,仍抱着"也许会不一样"的希望读下去。类型写作注意:悬疑推理结尾必须给确定答案,不确定性只能放在阅读过程中。(中文落地;方法本体) diff --git a/framework/catalog/dsh/skills/narration-pov/references/narration-pov-checklist.md b/framework/catalog/dsh/skills/narration-pov/references/narration-pov-checklist.md new file mode 100644 index 0000000..93eff2b --- /dev/null +++ b/framework/catalog/dsh/skills/narration-pov/references/narration-pov-checklist.md @@ -0,0 +1,85 @@ +# 叙述与视角检查清单 + +> 汇总五个源单元的可执行检查项,按写作进程排列:设定阶段 → 写作中 → 修订阶段。 +> 每条注明来源;方法细节与案例见 references/ 对应文件。 +> 视角人物说出/想到视角之外信息的逐句检查(知识诅咒)不在此表,见 show-and-omission/references/show-omission-checklist.md 第六节(一句话指针)。 + +## 一、设定阶段:视角设定卡 + +选定视角人物前逐条核对(/bifeiyu-perspective): + +- [ ] 主视角卡已填:他能看到的(列具体内容)/ 他看不到的(列具体内容)/ 他的判断标准(他怎么看世界) +- [ ] 主视角必须有限——他不能看到一切 +- [ ] 知道他看世界的"滤镜":恐惧(看到的都是威胁)/ 好奇(看到的都是机会)/ 厌倦(看到的都是无聊) +- [ ] 知情范围已划:能知道的只有他能观察到的、能推断的、别人告诉他的;对方的真实想法、历史、未来发展都在盲区 +- [ ] 视角数量受控:短篇 1-2 个主视角;长篇可流动,但不频繁(每章换视角读者会累) +- [ ] 每次视角转换都先定好要揭示什么:视角 A 看表面/误导/一面,视角 B 看另一面/真相/立体;揭示不出新东西就不换 +- [ ] 秘密有藏处:主视角不知道、但读者通过线索(飞白)能猜到——视角限制 = 戏剧张力 +- [ ] 没有用全知视角——全知视角 = 没秘密 = 没戏 +- [ ] 没有用第二人称,除非明确要做实验(主流读者不易接受) + +## 二、设定与写作中:封闭系统与外来者 + +要揭示组织/社区/制度/文化的荒谬或本质时执行(/outsider-perspective): + +- [ ] 要揭示的封闭系统已明确:它是什么(公司/社区/制度/文化/家庭),不合理性/独特性在哪里 +- [ ] 外来者角色有明确冲突点:来自哪里、为什么进入、什么习惯/价值观与系统冲突 +- [ ] 安排了 3-5 个碰壁/困惑场景,每个场景展示系统的一处不合理/独特之处 +- [ ] 只描写外来者的反应和系统的反应,没有作者跳出来解释"这个制度有多荒谬" +- [ ] 至少有一处内部人与外来者的反应对比:内部人习以为常,嫌外来者"大惊小怪""不懂规矩" +- [ ] 外来者与系统的关系有发展和结局:逐渐理解但保持批判距离,或始终被拒绝(像 K 永远进不了城堡),两种都有效 +- [ ] 外来者没有太顺利适应——适应太顺利就变成系统导游,失去揭示荒谬的功能 +- [ ] 外来者没有直接说"这个制度真荒谬"——他的不适应本身就是批判 +- [ ] 确认过系统本身确实有不合理性,不是"外来者无知"冒充"制度荒谬" + +## 三、写作中:看法入侵扫描(怀疑立场) + +通读草稿,逐条执行(/skeptical-narration): + +- [ ] 全文标出作者直接给判断/评价/结论的地方,信号词:"这说明…""由此可见…""真正的…是…""我们应该…"(中文叙述腔里的"这正是人性的悲哀""可见命运弄人"类总结句一并扫描)(后半句为中文适配补充) +- [ ] 每处看法已替换为事实:"他是个虚伪的人" → 说一套做一套的具体细节;"这个社会很冷漠" → 具体的冷漠场景(路人无视摔倒的老人) +- [ ] 至少有一处"肯定→否定"的反转:给出看似确定的结论后,跟上反面的可能(博尔赫斯式:肯定后立刻否定跟进) +- [ ] 至少有一处抵达"表层之下":不只写干渴,还写干渴后面更可怕的对干渴的恐惧;问过"这个事实背后还有什么?这个情绪的底层是什么?" +- [ ] 结尾没收死:不给确定答案,用一个多义的细节/意象/对话收尾,读者读完会继续思考 +- [ ] 怀疑没有变成虚无:怀疑是对"看法"局限性的清醒,事实仍然可靠;没有借怀疑之名什么都不呈现 + +## 四、修订阶段:确定性与不确定性张力 + +故事要让读者回味、在确定与不确定之间徘徊时执行(/certainty-uncertainty-tension): + +- [ ] 已选定叙述方向:方向 A(从不确定走向确定,但始终没走到,适合人物关系、秘密、真相类)/ 方向 B(从确定走向不确定,但没成功,适合命运、死亡、不可抗拒类) +- [ ] 确定性锚点在:方向 A 用细节、暗示让读者隐约感觉到真相但叙述永不确认;方向 B 让结局在开头就确定(如"他被判了死刑"),叙述试图推翻它 +- [ ] 不确定性屏障在:方向 A 让人物主动选择不确认(像奶奶那样粘好信封)或关键证据缺失;方向 B 让人物试图改变命运(救人、越狱、反抗),给读者"也许会不一样"的希望 +- [ ] 不确定性有明确来源,不是"作者没写清楚"——有效的不确定性是"有线索但不确认",不是"什么都没给" +- [ ] 不确定性有情感或主题支撑,不是为不确定而不确定、故弄玄虚 +- [ ] 结尾暗示是多义的,读者读完会想"到底是怎么回事?"并开始自己想象 +- [ ] 张力自检:读者能同时感觉到确定性和不确定性吗?只有不确定(无线索)→ 读者困惑;只有确定(答案太明显)→ 读者无聊 +- [ ] 确认不是推理/悬疑题材——这类结尾必须给出确定答案,不确定性只能放在阅读过程中 +- [ ] 世界观设定、规则说明等需要明确信息的地方没有误用不确定性 + +## 五、修订阶段:主线 / 折线标注诊断 + +手稿主线平铺、折线落不回去、独白插叙用错位置时执行(/mix-narrative-modes): + +- [ ] 每段已标注 `SCENE`(主线,事件在动)或 `BREAK`(折线:解释/反思/独白/插叙/意识流/旁白评论) +- [ ] 比例合格:全章 SCENE:BREAK 约 2:1,折线不超过全篇 30-40%;一段折线后接 1-2 段 SCENE +- [ ] 每个 BREAK 段后 500 字内回到 SCENE;超出 500 字未回即"断线事故",补场景锚 +- [ ] 判停:BREAK 段超过 1000 字且无 SCENE 锚回 → 拆为更小段,或改写为 SCENE 内的对白/动作 +- [ ] 任何 BREAK 段尾都有 scene anchor(具体物、人物动作、可感的环境);独白/插叙尾只有抽象句的,改写为"动作 + 短句反思"或转回 SCENE +- [ ] 任何长 SCENE 后至少有 1 段 altitude(反思、解释、主题意义)回答读者的"so what?"(nut paragraph) +- [ ] 每段尾读者都知道"我现在在火车的哪一节、哪一站"——答不上就是断线事故 +- [ ] 没有诱骗式切换(bait and switch):开篇许诺讲故事,通篇塞信息密度 +- [ ] 没有高空缺氧(too much ozone):连续 3 段以上无场景锚(无具体人、物、动作) +- [ ] 中文语境适配:内心独白密度放低、落回场景更快——大段独白会被中文读者当成"作者代笔"(中文适配;源单元文化迁移节) + +## 快速排错表 + +| 症状 | 诊断 | 处方 | +|------|------|------| +| 信息太多、没有秘密 | 视角太全知 | 限制主视角,用盲区藏秘密(一、)() | +| 批判读起来像说教 | 作者直接下判断 | 换外来者的碰壁与反应呈现(二、)() | +| 读者反馈"太直白""作者跳出来说话" | 看法入侵 | 看法替换为事实,加"肯定→否定"反转(三、)() | +| 读完就忘、没有回味 | 只有确定性没有张力 | 选方向 A/B,设锚点和屏障(四、)() | +| 读者困惑"发生了什么" | 只有不确定性没有线索 | 补确定性锚点:有线索但不确认(四、)() | +| 读者在插叙/独白尾迷路 | 折线没落回场景 | 500 字内回 SCENE,段尾补场景锚(五、)() | +| 主线太平、像流水账 | 缺意义层 | 长 SCENE 后加 1 段 altitude(五、)() | diff --git a/framework/catalog/dsh/skills/narration-pov/references/outsider-entry.md b/framework/catalog/dsh/skills/narration-pov/references/outsider-entry.md new file mode 100644 index 0000000..cd55599 --- /dev/null +++ b/framework/catalog/dsh/skills/narration-pov/references/outsider-entry.md @@ -0,0 +1,130 @@ +# 外来者切入法:用一个外来者揭开封闭系统 + +> 来源单元:《我能否相信自己》(余华)wo-neng-fou-xiang-xin-zi-ji/outsider-perspective,出自《卡夫卡和K》(1999)。 + +## R 原文 + +> "那些在已有制度里出生并且成长起来的村民, 制度的一切不合理性恰恰构成了它的合理。面对这至高无上的权威, 村民以麻木的方式保持着他们世代相传的恐惧和世代相传的小心翼翼。而K的来到, 使其制度的不合理性得到了呈现。外来者K就像是一把熏肉切刀, 切入到城堡看起来严密其实漏洞百出的制度之中, 而且切出了很薄的片, 最后让它们一片片呈卷状飞了出去。" +> +> — 余华, 《卡夫卡和K》() + +## 方法核心:三个机制 + +揭示一个封闭系统(组织、社区、制度、文化)的荒谬或本质,最有效的方式不是作者直接批判,而是**让一个外来者进入这个系统**,通过他的不适应让系统的不合理性自行呈现。 + +1. **内部人的麻木**:在已有制度中出生成长的人,制度的一切不合理性恰恰构成了它的合理。他们习惯了,不觉得有问题。 +2. **外来者的不适应**:外来者因为不适应系统的规则,能看到内部人看不到的荒谬。他的困惑和碰壁本身就是对系统的批判。 +3. **自行呈现**:作者不需要解释"这个制度有多荒谬",只需要描写外来者的不适应,读者自然会感受到系统的问题。 + +卡夫卡《城堡》是最经典的例子:K 作为土地测量员来到村子,他试图进入城堡(权威),但整个官僚制度让他处处碰壁——电话接通后听到无数声音,村长翻箱倒柜找文件,克拉姆先生仿佛生活在传说中。K 的外来者身份让城堡制度的荒谬层层暴露。() + +## 书中案例 + +### 案例 1:卡夫卡《城堡》——K 进入村庄 + +- **问题**:如何描写一个荒诞而压迫的官僚制度,而不变成政治控诉? +- **方法论的使用**:卡夫卡让土地测量员 K 在厚厚的积雪中来到村庄,他的身份本身就是模糊的(城堡说没雇过土地测量员,但又似乎雇了)。K 试图接近城堡,但整个制度让他处处碰壁:电话接通后听到无数声音(因为所有电话同时接通),村长家翻箱倒柜找有关 K 的文件,克拉姆先生仿佛生活在传说中,村民对城堡权威的敬畏到了麻木的程度。 +- **结论**:K 的外来者身份让城堡制度的荒谬自行呈现——不需要作者解释,读者通过 K 的碰壁感受到制度的不合理。 +- **结果**:《城堡》成为官僚制度批判的巅峰之作。 + +### 案例 2:余华 1983 年第一次去北京 + +- **问题**:如何呈现不同城市文化的差异? +- **方法论的使用**:余华(浙江人)第一次去北京,问路时北京人用"向南走""向北走"指路,而他习惯了浙江人的"向左转""向右转"。一个外地人在北京根本不知道东南西北。"明明可以用一种确定的方式指引你, 但是你所遇到的指引总是具有不确定性。" +- **结论**:外来者的不适应(分不清东南西北)让北京的指路文化成为一个有趣的文化观察。 +- **结果**:成为余华谈"确定性与不确定性"的生活案例。 + +### 案例 3:远距荒诞外来者(布尔加科夫式) + +- **问题**:如何用外来者揭封闭系统,而不变成直接批判? +- **方法论的使用**:引入终极外来者(如魔鬼访问一座城市),让荒谬自行呈现;叙述距离与幽默结构见 `theme-and-stance` 的 [humor-as-stance.md](../../theme-and-stance/references/humor-as-stance.md)(撒旦访莫斯科全文案例 owner 在该文件,此处不重复)。 +- **结论**:外来者机制管"谁在看";荒诞幽默的距离与结构管"什么态度在讲"——两者配合,但案例正文只保留一份。 + +(以上三例均出自) + +## 执行步骤 + +1. **确定要揭示的封闭系统** + - 这个系统是什么?(公司/社区/制度/文化/家庭) + - 它的不合理性/独特性在哪里? + - 完成标准:明确要揭示的系统及其核心特征 + +2. **设计外来者角色** + - 外来者的背景:来自哪里?为什么进入这个系统? + - 外来者的特征:天真?固执?好奇?有目的? + - 外来者与系统的冲突点:他的什么习惯/价值观与系统冲突? + - 完成标准:有一个与系统有明确冲突的外来者角色 + +3. **让外来者经历系统的规则** + - 设计 3-5 个场景,让外来者在系统中碰壁或困惑 + - 每个场景展示系统的一个不合理/独特之处 + - 不要让作者解释,只描写外来者的反应和系统的反应 + - 完成标准:有足够的场景让系统的特征自行呈现 + +4. **利用内部人的麻木做对比** + - 描写内部人对系统不合理性的习以为常 + - 内部人可能觉得外来者"大惊小怪""不懂规矩" + - 这种对比本身就是批判 + - 完成标准:至少有一处内部人与外来者的反应对比 + +5. **让外来者逐步深入(或被拒绝)** + - 外来者可能逐渐理解系统(但仍保持批判距离) + - 也可能始终被拒绝(像 K 永远进不了城堡) + - 两种走向都有效,取决于故事主题 + - 完成标准:外来者与系统的关系有发展和结局 + +6. **检查是否说教** + - 通读全文,是否有作者直接跳出来批判系统? + - 如果有,替换为外来者的经历和反应 + - 完成标准:系统的问题全部通过外来者的视角呈现,没有作者直接说教 + +() + +## 触发场景 + +1. 想写一个组织/公司/社区的故事,揭示其内部文化或问题 +2. 写批判题材但不想显得说教 +3. 想写文化冲突/文化冲击的故事 +4. 设定了一个独特的世界观/制度,不知道如何向读者展示 +5. 写"鱼离开水"(fish out of water)类型的故事 +6. 想学习卡夫卡式的叙述方式 + +语言信号:"揭示制度荒谬""组织批判""外来者视角""陌生人进入""文化冲击""fish out of water""不想说教""怎么批判不生硬""世界观怎么展示""设定怎么呈现""卡夫卡式""局外人""outsider"。() + +## 边界:不要在以下情况使用 + +- **已经以内视角展开的故事**:如果故事已经从内部人的角度写,强行加入外来者可能破坏叙事。 +- **纯个人成长故事**:如果故事核心是个人情感成长,不需要揭示系统本质,外来者视角可能多余。 +- **需要内部人专业知识的场景**:如医疗/法律/科技题材,外来者可能不懂专业内容,无法有效揭示。 + +() + +## 作者在书中警告的失败模式 + +- **外来者变成导游**:如果外来者太顺利地适应了系统,他就不再是外来者,变成了系统的导游——失去了揭示荒谬的功能。 +- **作者借外来者之口说教**:外来者不应该直接说"这个制度真荒谬",他的不适应本身就是批判。直接说教会破坏效果。 + +() + +## 作者的盲点 / 时代局限 + +- 余华主要讨论极权/官僚制度下的外来者,没有讨论日常/普通组织(如公司、学校)中如何使用外来者视角。 +- "外来者让制度不合理性自行呈现"假设制度确实有不合理性,如果系统本身是合理的,外来者的不适应只是因为他不了解——需要区分"制度荒谬"和"外来者无知"。 + +() + +## 容易混淆的邻近方法论 + +- **"鱼离开水"(fish out of water)**:这是一种喜剧类型,主要目的是搞笑。本方法的目的是揭示系统本质,幽默可能是副产品但不是主要目的。 +- **"侦探视角"**:侦探进入一个封闭社区调查案件,也是外来者。但侦探的目的是解谜,本方法的外来者目的是揭示系统——可能没有案件,只是存在本身就是批判。 + +() + +## 与相邻方法的区分和配合 + +- 与怀疑叙述(skeptical-stance.md)的区别:外来者视角是通过外来者的眼睛呈现,怀疑叙述是通过怀疑的立场呈现。外来者天然带有怀疑(因为不适应),两者有重叠但角度不同,经常配合使用。() +- 与幽默作为结构(humor-as-structure)的区别:外来者视角是叙述视角技巧(用外来者揭示系统),幽默作为结构是叙述态度(用幽默处理沉重)。两者经常配合——外来者的不适应往往产生幽默效果。(humor-as-structure 归综合 skill theme-and-stance;) + +## 中文落地说明 + +方法本身无语言差异,中文写作直接可用。中文语境里"封闭系统"的现成素材很多:单位大院、宗族村落、机关科室、寄宿学校、行业圈子。落地时注意两点:一是中文读者对"制度批判"的直白表述敏感,本方法"只写反应、不做解释"的纪律恰好是最安全的写法;二是余华的案例(北京问路)说明外来者视角不一定用于揭露荒谬,也可以用于呈现文化差异的温和观察。(中文落地;方法本体) diff --git a/framework/catalog/dsh/skills/narration-pov/references/pov-camera.md b/framework/catalog/dsh/skills/narration-pov/references/pov-camera.md new file mode 100644 index 0000000..663b287 --- /dev/null +++ b/framework/catalog/dsh/skills/narration-pov/references/pov-camera.md @@ -0,0 +1,93 @@ +# 视角是摄像头:谁在看,决定一切 + +> 来源单元:《小说课》(毕飞宇)bifeiyu-novel-skill/bifeiyu-perspective,第 2、3 章;分类:叙事·结构,难度:★★★★,主要元素:智商、直觉。案例素材:《杀手》视角转换 + 鲁迅《故乡》象征主义。 +> 视角限制的落地五步、触发场景、适用边界、常见错误见 [pov-execution.md](pov-execution.md)。 + +## 开篇原文 + +> 「人物的眼睛就是作家的眼睛。人物在'看',作家在'看',但作家不能比人物多'看'到任何东西。」() + +## 方法核心 + +**视角 = 小说里的"摄像头"。** + +- 谁在看 = 决定读者看到什么 +- 谁在看 = 决定读者看不到什么 +- 谁在看 = 决定"事实"的样貌 + +核心原则: + +1. **视角人物决定信息范围**——他看不到的,读者看不到。 +2. **视角人物的判断 = 隐形叙述**——他说"那个人可怕",读者就觉得可怕。 +3. **视角的转换 = 真相的揭示**——多个视角 = 多层真相。 + +() + +## R 原文:海明威《杀手》的障眼法 + +《杀手》开头,海明威写两个杀手进门,**通过顾客尼克的视角**: + +- 马克斯(第二人进门)被尼克看到 → **尼克忽略了阿尔**(第一人) +- **这是海明威的"障眼法"**——读者第一遍读也会忽略阿尔 + +**但是**,到中段,**通过服务员乔治的视角**: + +- 乔治送餐时先问阿尔 → **阿尔是更可怕的那个** +- **视角的转换让真相显露** + +() + +## 书中案例 + +### 案例 1(指针):海明威《杀手》(POV 轻重) + +> 对白白描角度见 `prose-craft` → [plain-description.md](../../prose-craft/references/plain-description.md)。本处只取 POV:尼克视角忽略阿尔,乔治视角让阿尔显形。 + +``` +视角 1:尼克(顾客) + → 看到马克斯,没看到阿尔 + → 读者跟着忽略阿尔 + +视角 2:乔治(服务员) + → 看到阿尔的可怕 + → 真相显露 +``` + +**视角的"重"和"轻"**——不同视角让人物重要度变化:尼克眼里马克斯重要,换到乔治的视角,阿尔才被重新称出分量。() + +### 案例 2:鲁迅《故乡》 + +- 第一人称"我"的视角 +- 视角的限制 = 思想的限制 +- "我" 看到的"故乡" = 中国的象征 + +**鲁迅的"象征主义"恰恰来自于视角的"克制"**——他不用全知视角,他只用"我"。() + +### 案例 3:奈保尔《布莱克·沃滋沃斯》 + +- 第一人称孩子视角 +- 孩子的天真 = 视角的局限 = 诗意的诞生 +- 孩子看芒果树 = 读者跟着看芒果树 = 爱情用"树"被表达 + +() + +### 案例 4:红楼梦可卿(宝玉/贾珍/凤姐三视角) + +- 多视角流动:宝玉看可卿 / 贾珍看可卿 / 凤姐看可卿 +- 不同视角下的"可卿" = 不同的形象 +- **可卿 = 多重视角的合集**——她的"死"才反逻辑 + +(;标题保留源单元原文,案例内容为宝玉/贾珍/凤姐三视角看可卿,王熙凤为三个视角人物之一;可卿之死"反逻辑"的那一面归 show-and-omission/references/anti-logic.md,此处只取多视角这一面) + +## 一句话总结 + +> **不是作家在看,是人物在看。人物看到什么决定一切。**() + +## 与相邻方法的区分和配合 + +- 视角人物在段落里说出、想到视角之外的信息(知识诅咒),逐句检查与修复归 show-and-omission/references/pov-knowledge-boundary.md;本文件管设定端——选谁看、看多少、怎么换。(跨 skill 一句话指针) +- 反逻辑经常通过"视角人物的盲点"实现;视角是"水面"和"水下"的控制器——这两条配合关系见 show-and-omission/references/anti-logic.md 与 iceberg.md。( 跨 skill 链接,落点归 show-and-omission) + +## 中文落地说明 + +本方法出自中文小说家的《小说课》,案例已含《故乡》《红楼梦》等中文作品,海明威、奈保尔两例为译作,方法本身无语言差异。中文写作要留意一个传统:古典小说"话说""且说"是说书人的全知腔,属于全知传统。作品一旦选了限制视角,就按本方法严格执行——视角人物看不到的,读者看不到;选了全知,则不必机械套用,但"全知 = 没秘密 = 没戏"的警告仍然成立。(中文落地;方法本体) diff --git a/framework/catalog/dsh/skills/narration-pov/references/pov-execution.md b/framework/catalog/dsh/skills/narration-pov/references/pov-execution.md new file mode 100644 index 0000000..b15de99 --- /dev/null +++ b/framework/catalog/dsh/skills/narration-pov/references/pov-execution.md @@ -0,0 +1,119 @@ +# 视角限制的落地:五步执行 + +> 来源单元:《小说课》(毕飞宇)bifeiyu-novel-skill/bifeiyu-perspective,第 2、3 章。 +> 方法原则与案例全文见 [pov-camera.md](pov-camera.md)。 + +## 步骤 1:选"主视角" + +```yaml +主视角:[人物 A] + 他能看到的:[列具体内容] + 他看不到的:[列具体内容] + 他的判断标准:[他怎么看世界] +``` + +**主视角必须有限**——他不能看到一切。() + +## 步骤 2:视角人物"看"的方式 + +不是"他看到了什么"——是"他怎么看": + +``` +尼克看马克斯:这是威胁我的人 +乔治看阿尔:这是更可怕的人 +→ 同一个人(阿尔)→ 两种看法 → 视角决定意义 +``` + +**检验**:你的视角人物看世界时带着什么"滤镜"? + +- 恐惧(看到的都是威胁) +- 好奇(看到的都是机会) +- 厌倦(看到的都是无聊) + +() + +## 步骤 3:限制主视角的"知情范围" + +**主视角不知道的事**: +- 对方的真实想法 +- 对方的历史 +- 未来的发展 + +**主视角能知道的事**: +- 他能观察到的 +- 他能推断的 +- 别人告诉他的 + +**短篇的视角**:1-2 个主视角。 +**长篇的视角**:可以流动,但不能太频繁(每章换视角读者会累)。 + +() + +## 步骤 4:设计"视角的转换点" + +视角的**转换** = 真相的**揭示**。 + +``` +视角 A 看:表面 / 误导 / 一面 +视角 B 看:另一面 / 真相 / 立体 +``` + +**海明威的转换**: +- 视角 A(尼克)看:马克斯重要 +- 视角 B(乔治)看:阿尔更可怕 +- 转换的瞬间 = 读者的"啊原来如此" + +**检验**:你的小说里有没有这样的转换点?如果没有,读者读到的只有"单面真相"——那不够。() + +## 步骤 5:用视角藏"秘密" + +**秘密** = 主视角不知道,但读者可以猜到: + +```yaml +秘密:王熙凤和贾蓉的关系 +视角人物:秦可卿的婆婆(不知情) +读者:通过其他线索(飞白)能猜到 +→ 视角限制 = 戏剧张力 +``` + +**不要全知视角**——全知视角 = 没秘密 = 没戏。(;"飞白"手法本身见 show-and-omission/references/anti-logic.md) + +## 触发场景 + +1. 你的小说"信息太多" → 加视角限制 +2. 你的小说"看起来全知" → 限制一个视角 +3. 你的小说"该揭示真相"了 → 转换视角 +4. 你想写"复杂人物" → 多个视角看他 +5. 你想隐藏秘密 → 视角人物的"盲点"就是秘密 + +() + +## 适用边界 + +- **适合**:所有虚构叙事 +- **短篇推荐用**单一视角(清晰) +- **长篇可以用**多视角流动(复杂) +- **慎用**:第二人称(实验性,主流读者不易接受) + +() + +## 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 全知视角 | 没秘密 | 限制主视角 | +| 视角频繁转换 | 读者混乱 | 短篇 1-2 个,长篇每章 1 个 | +| 主视角太"通透" | 假 | 视角人物要有局限 | +| 视角转换无意义 | 浪费 | 每次转换都要"显示新东西" | +| 主视角没判断 | 假 | 视角人物的判断 = 隐形叙述 | + +() + +## 跨 skill 链接(综合 skill 归属对照) + +- 与反逻辑配合:反逻辑经常通过"视角人物的盲点"实现 → show-and-omission/references/anti-logic.md +- 与冰山同源:视角是"水面"和"水下"的控制器 → show-and-omission/references/iceberg.md +- 与人物关系配合:多视角下看同一对关系 = 立体关系 → character-presentation/references/relationship-web.md +- 与篇幅系统配合:短篇视角简,长篇视角可繁 → story-structure/references/length-system.md + +( 跨 skill 链接四条全量;落点为综合 skill 层归属) diff --git a/framework/catalog/dsh/skills/narration-pov/references/skeptical-stance.md b/framework/catalog/dsh/skills/narration-pov/references/skeptical-stance.md new file mode 100644 index 0000000..fea197c --- /dev/null +++ b/framework/catalog/dsh/skills/narration-pov/references/skeptical-stance.md @@ -0,0 +1,139 @@ +# 怀疑主义叙述法:看法会陈旧,事实不会 + +> 来源单元:《我能否相信自己》(余华)wo-neng-fou-xiang-xin-zi-ji/skeptical-narration,出自《我能否相信自己》(1997)/ 博尔赫斯专题。 + +## R 原文 + +> "看法总是要陈旧过时, 而事实永远不会陈旧过时。" — 艾萨克·辛格的哥哥 +> +> "命运的看法比我们更准确。" — 古希腊人 +> +> "我喜欢怀疑不亚于肯定。" — 但丁 +> +> "按自己的能力来判断事物的正误是愚蠢的。" — 蒙田 +> +> — 余华, 《我能否相信自己》() + +## 方法核心 + +作家的叙述立场应是**怀疑主义**,而非急于给出看法(opinion)。核心洞察: + +- **看法总是陈旧过时**:任何人的看法都会被时间淘汰,权威的看法尤其容易成为笑料(IBM 董事长说五台计算机够全世界用)。 +- **事实永远不会陈旧**:事实比看法更持久,更有力量。 +- **怀疑优于肯定**:"我喜欢怀疑不亚于肯定"——怀疑让叙述保持开放,肯定让叙述封闭。 + +怀疑主义叙述的实践: + +1. **不给出确定答案**:博尔赫斯的叙述"总是假装地要确定下来了, 可是永远无法确定。读到肯定时接踵而来是否定。" +2. **只呈现事实, 不给出判断**:让读者在事实中自己得出结论,而非作者告知。 +3. **呈现更深层的真实**:不只是写"干渴",还要写"干渴后面更可怕的对干渴的恐惧"——怀疑让叙述抵达表层之下的真实。 + +写作会改变一个人:"作家长时期的写作, 会使自己变得越来越软弱、胆小和犹豫不决"——因为思维的训练将人推到深深的怀疑之中。这不是缺点,而是作家的必要品质。() + +**合并说明**:实践 1"不给出确定答案"与 [certainty-uncertainty.md](certainty-uncertainty.md) 的核心主张是同一条规则的两面——本文件管叙述立场(怀疑而非肯定),certainty-uncertainty.md 管叙述结构(确定性与不确定性的张力)。立场决定结构:怀疑主义立场自然产生不确定性的叙述结构。博尔赫斯案例两个文件都保留,角度不同:本文件取立场角度(怀疑、《沙之书》答案消失在无限中),certainty-uncertainty.md 取结构角度(在两极之间来回走动)。(合并标注; + certainty-uncertainty-tension) + +## 书中案例 + +### 案例 1:博尔赫斯——永远无法确定的叙述 + +- **问题**:如何让叙述有深度而不说教? +- **方法论的使用**:博尔赫斯的叙述充满怀疑——"总是假装地要确定下来了, 可是永远无法确定。我们耐心细致地阅读他的故事, 终于读到了期待已久的肯定时, 接踵而来的立刻是否定。"《沙之书》中一本无始无终的书,最后被藏在图书馆九十万册书中——答案消失在无限中。 +- **结论**:怀疑不是不给出答案,而是给出答案后立刻质疑它,让叙述保持开放。 +- **结果**:博尔赫斯成为"迷宫的创造者",读者找不到出口但乐在其中。 + +### 案例 2:蒙田——怀疑一切看法 + +- **问题**:如何避免被自己的看法局限? +- **方法论的使用**:蒙田说"按自己的能力来判断事物的正误是愚蠢的",因为"我们自己的看法常常充满矛盾? 多少昨天还是信条的东西, 今天却成了谎言?" 他选择怀疑主义立场,相信"任何一个命题的对面, 都存在着另外一个命题"。 +- **结论**:怀疑不是虚无,而是对"看法"的局限性的清醒认识。 +- **结果**:蒙田的随笔成为几百年后仍有生命力的经典,而他同时代人的"看法"早已过时。 + +### 案例 3:余华谈作家的看法——干渴与对干渴的恐惧 + +- **问题**:作家应该有什么样的"看法"? +- **方法论的使用**:余华引用博尔赫斯《永生》中的句子——"我一连好几天没有找到水, 毒辣的太阳、干渴和对干渴的恐惧使日子长得难以忍受。" 他指出这个句子令人赞叹,因为在"干渴"后面,博尔赫斯告诉我们还有更可怕的"对干渴的恐惧"。 +- **结论**:作家的看法不是给出答案,而是呈现比表层更深的真实——不只是干渴,还有对干渴的恐惧。 +- **结果**:这成为余华自己写作的追求——呈现事实而非看法,抵达更深层的真实。 + +(以上三例均出自) + +## 执行步骤 + +1. **识别"看法"入侵点** + - 检查文本中是否有作者直接给出的判断/评价/结论 + - 常见信号:"这说明…""由此可见…""真正的…是…""我们应该…" + - 完成标准:标出所有作者直接给出看法的地方 + +2. **将看法转化为事实** + - 把"他是个虚伪的人"转化为描写他的具体行为(说一套做一套的细节) + - 把"这个社会很冷漠"转化为描写具体的冷漠场景(路人无视摔倒的老人) + - 让事实自己说话,作者不做判断 + - 完成标准:所有看法都被替换为事实描写 + +3. **引入怀疑和反向思考** + - 对每个看似确定的结论,提出反面的可能性 + - 可以通过角色之口提出不同看法,或通过情节发展质疑初始判断 + - 博尔赫斯式:给出肯定后立刻用否定跟进 + - 完成标准:叙述中至少有一处"肯定→否定"的反转 + +4. **呈现更深层的真实** + - 不只是写表层现象(干渴),还要写表层之下的东西(对干渴的恐惧) + - 问自己:这个事实背后还有什么?这个情绪的底层是什么? + - 完成标准:至少有一处抵达"表层之下"的描写 + +5. **保留开放性** + - 结尾不给出确定答案,让读者自己思考 + - 可以用一个多义的细节/意象/对话收尾 + - 完成标准:结尾是开放的,读者读完会继续思考 + +() + +## 触发场景 + +1. 写社会/人性题材时,忍不住说教或给出简单答案 +2. 作品被反馈"太直白""作者跳出来说话了" +3. 想提升作品的思想深度和回味空间 +4. 写议论文/评论时想避免独断 +5. 不知道如何处理复杂的道德/伦理问题 +6. 想学习博尔赫斯/蒙田式的叙述方式 + +语言信号:"避免说教""不想说教""作品没深度""太直白了""作者跳出来说话了""复杂问题怎么写""道德困境""怀疑主义""博尔赫斯""不给简单答案""开放式思考"。() + +## 边界:不要在以下情况使用 + +- **需要明确立场的写作**:议论文、社论、评论需要明确的观点,不能用怀疑主义模糊立场。 +- **儿童文学**:需要明确的价值观引导,过度怀疑会让儿童困惑。 +- **纯娱乐性类型小说**:读者期待明确的善恶和结局,怀疑主义会破坏阅读快感。 + +() + +## 作者在书中警告的失败模式 + +- **权威的自负**:"权威往往是自负的开始, 就像得意使人忘形一样, 他们开始对未来发表看法了。"——作家不要以为自己的看法就是真理。 +- **怀疑变成虚无**:怀疑不是什么都不相信,而是对"看法"的局限性保持清醒。事实仍然是可靠的。 + +() + +## 作者的盲点 / 时代局限 + +- 余华主要从纯文学角度讨论怀疑主义,没有讨论在商业写作/类型小说中如何平衡"深度"和"读者满足感"。 +- "写作使人软弱、胆小和犹豫不决"是余华的个人经验,不是所有作家的必然结果。 + +() + +## 容易混淆的邻近方法论 + +- **"客观叙述"**:客观叙述是不偏不倚地呈现,本方法是主动引入怀疑和反向思考——不是中立,而是质疑。 +- **"反讽"**:反讽是说反话,本方法是真诚地怀疑——不是讽刺,而是认知上的开放。 + +() + +## 与相邻方法的区分和配合 + +- 与 [certainty-uncertainty.md](certainty-uncertainty.md) 的区别:本方法是叙述立场(怀疑而非肯定),certainty-uncertainty.md 是叙述结构(确定性与不确定性的张力)。立场决定结构——怀疑主义立场自然产生不确定性的叙述结构,两者经常配合。() +- 与"事实先于看法"(fact-over-opinion)的关系:源单元记录为 depends-on,且该方法点已在抽取阶段合并入 skeptical-narration 本单元——怀疑主义的基础是重视事实甚于看法,本文件"看法转化为事实"一节即其落点。( 相关 skill 记录全量) +- 与外来者视角(outsider-entry.md)的配合:外来者天然带有怀疑(因为不适应),用外来者揭示封闭系统时,本方法的"只呈现事实、不下判断"是其叙述纪律。(配合关系见) + +## 中文落地说明 + +方法本身无语言差异,中文写作直接可用,且执行步骤里的信号词("这说明""由此可见""真正的""我们应该")和改写例("他是个虚伪的人""这个社会很冷漠"/路人无视摔倒的老人)本来就是中文语境的原样。中文写作里"看法入侵"还有一个高发形态:借叙述腔讲大道理("这正是人性的悲哀""可见命运弄人"这类总结句),修订时可与信号词一并扫描。(中文落地;方法本体) diff --git a/framework/catalog/dsh/skills/narrative-momentum/SKILL.md b/framework/catalog/dsh/skills/narrative-momentum/SKILL.md new file mode 100644 index 0000000..ac4fb71 --- /dev/null +++ b/framework/catalog/dsh/skills/narrative-momentum/SKILL.md @@ -0,0 +1,83 @@ +--- +name: narrative-momentum +description: | + 写或改长篇小说、网文连载、章节体故事遇到动力问题时激活:情节推不动、事件之间接不上、中段塌陷读者弃读、 + 章末平淡翻不下去、高潮不爆。三台发动机:给事件接因果推力链(造势)、沿途埋小奖励(金币)、 + 在断点挂未解问题(内悬念)。 + 关键 trigger:造势 / 势 / 推力 / 情节推不动 / 情节跳跃 / 高潮不爆 / 中段无力 / + 中段塌陷且读者弃读 / sagging middle / 读者弃读 / 金币 / 沿途埋金 / gold coin / + 章末钩子 / 段末悬念 / 卷末悬念 / internal cliffhanger / 内悬念 / 钩子 / 怎么让读者翻下去 / 付费点钩子。 + (裸「中段塌陷」无弃读/钩子语境时先查 story-structure) + 不适用于:抒情散文与诗(没有叙事路径和断点);意识流、反悬念的实验叙事(靠情绪流,不靠势与钩子); + 新闻报道(倒金字塔结构)。沿途埋金不适用于 1 万字以下短篇(没有中段可埋);造势与断点钩子对短篇仍适用 + (势链要短要密)。 + 与 story-structure 交接:中段塌陷若来自里程碑错位/赌注不升,先查 story-structure;本 Skill 只管读者动力(势/金币/钩子)。 +--- + +# 叙事动力(narrative-momentum) + +读者的动力有三个来源:事件内部不可逆的推力链(势)、沿途不断捡到的小奖励(金币)、每个断点上挂着的未解问题(钩子)。势解决"情节为什么必须往前走",金币解决"读者为什么愿意继续走",钩子解决"读者为什么不得不翻页"。 + +## 方法索引 + +按创作动作组织;方法细节、案例、原文引文都在 references/,不进本文件。 + +**情节推不动、事件接不上、高潮不爆 → 造势** + +- 把事件接成 A→必然B→必然C 的不可逆链条,有势的小说情节自己跑,作者拽不动 → references/build-momentum.md +- 势的起点必须是有具体动作的事件,不是心理 → references/build-momentum.md +- 链条每一环配齐处境、心理、动作三要素:只有处境则势弱,只有动作则势假 → references/build-momentum.md +- 势要递进不能平行(轻→中→重→爆发);高潮前累足势能、力度逐级递增 → references/build-momentum.md +- 写完做删环检验:删掉任何一环还成立,这一环就没用 → references/build-momentum.md + +**中段塌陷、读者弃读 → 沿途埋金** + +- 读者不是被"意义"驱动,是被"小奖励"驱动;在开头、中段、结尾前放 surprise / insight / beauty 三类金币 → references/midway-rewards.md +- 中段(30%-70%)是塌陷高危区:每 1 万字至少 1 枚小而具体、不必推进主线的金币,连续 3 万字无金立刻补 → references/midway-rewards.md +- 随时自问"这一段给读者的当下奖赏是什么",答不出来就是平地 → references/midway-rewards.md + +**章末平淡、翻不下去 → 断点内悬念** + +- 悬念是放置问题:在句末、段末、章末、卷末、全书末之前放一个未解决的小戏剧性元素 → references/breakpoint-hooks.md +- 钩子不必是生死悬崖,具体的好奇就够,且要从叙事内部自然生长 → references/breakpoint-hooks.md +- 强化疑问、弱化答案:最后一句是问题或动作中断,不是答案总结 → references/breakpoint-hooks.md + +**三台发动机的配合与相邻方法区分** + +- 金币给满足(推力),钩子造焦虑(拉力),节奏上先给金币、再抛内悬念 → references/alternation-and-distinctions.md +- 与伏笔(长期债务)、触发事件(全局赌注)、情节反转、朝终局写等的区分,以及三法适用范围对照 → references/alternation-and-distinctions.md + +## 脚本 + +- references/momentum-checklist.md —— 动力自查三关:势链删环检验、中段金币台账、断点悬念检查;写完初稿或改稿前使用。 + +## 引用索引 + +| 文件 | 覆盖内容 | +|---|---| +| references/build-momentum.md | 造势全量:势的定义与《促织》原文解读、四案例(《促织》/林冲/《项链》/沃滋沃斯)、可执行六步、适用边界与常见错误表、一句话总结、与其他方法的关系(跨 skill 链接四条,与 alternation-and-distinctions.md 重复落点) | +| references/midway-rewards.md | 沿途埋金全量:原文摘录、三时点机制与三类金币、莎剧第 3 幕与《Huck Finn》第 21 章案例、诊断三步(含判停条件)、失败模式、盲点与中文适配 | +| references/breakpoint-hooks.md | 内悬念全量:原文摘录、五时点断点与判断标准、电视剧插播与章末诊断案例、执行三步、失败模式、盲点与中文适配 | +| references/alternation-and-distinctions.md | 推拉交替节奏、三法对照、与伏笔/触发事件/朝终局写等相邻方法的区分(各书原话保留)、势的同源方法与跨 skill 链接、适用范围对照、跨域指针 | +| references/_coverage.md | 覆盖对照表(唯一追溯文件):源单元 → 落点小节 → 方法点,含逐点明细 | +| references/momentum-checklist.md | 可执行自查:势链检验七步、中段金币台账模板、断点悬念检查四步 | + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 红线 + +- 只给当前创作阶段的建议,不越权改设定主权、不绕过检测链、不复制粘贴其它 Skill 的 owner 定义。 +- 无用户明确授权不得替用户定稿或提交 Git。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/dsh/skills/narrative-momentum/references/_coverage.md b/framework/catalog/dsh/skills/narrative-momentum/references/_coverage.md new file mode 100644 index 0000000..a2bbcdb --- /dev/null +++ b/framework/catalog/dsh/skills/narrative-momentum/references/_coverage.md @@ -0,0 +1,12 @@ +# narrative-momentum 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| bifeiyu-novel-skill/bifeiyu-momentum | references/build-momentum.md | +| bifeiyu-novel-skill/bifeiyu-momentum | references/alternation-and-distinctions.md | +| writing-tools-clark/gold-coins | references/midway-rewards.md | +| writing-tools-clark/gold-coins | references/alternation-and-distinctions.md | +| writing-tools-clark/internal-cliffhanger | references/breakpoint-hooks.md | +| writing-tools-clark/internal-cliffhanger | references/alternation-and-distinctions.md | diff --git a/framework/catalog/dsh/skills/narrative-momentum/references/alternation-and-distinctions.md b/framework/catalog/dsh/skills/narrative-momentum/references/alternation-and-distinctions.md new file mode 100644 index 0000000..3482bbc --- /dev/null +++ b/framework/catalog/dsh/skills/narrative-momentum/references/alternation-and-distinctions.md @@ -0,0 +1,106 @@ +# 推拉交替与相邻方法区分 + +> 势、金币、钩子三法的推拉交替节奏、三法对照,以及与伏笔、触发事件、朝终局写等相邻方法的区分;同一方法点有多种表述的,均保留。 + +## 三台发动机:推力、推力、拉力 + +- **势**解决"情节为什么必须往前走":事件之间不可逆的推力,A 发生 → 必然 B → 必然 C。 +- **金币**解决"读者为什么愿意继续走":段中 / 段后给予**满足 / 惊喜**,是推力(来自已得到)。 +- **钩子**解决"读者为什么不得不翻页":段末 / 章末制造**焦虑 / 好奇**,是拉力(来自未满足)。 + +## 推拉交替:先给金币,再抛内悬念 + +同一条节奏规则有两种表述,均保留: + +- 表述一:"那个管'段末 / 章末制造**焦虑 / 好奇**(让读者不得不翻页)',是拉力(来自未满足);这个管'段中 / 段后给予**满足 / 惊喜**(让读者愿意再走一段)',是推力(来自已得到)。一个制造问题,一个给奖赏。" +- 表述二:"那个是'沿途给读者奖励'(满足),这个是'在末尾制造悬念'(焦虑)。两者在节奏上交替使用:**先给金币,再抛内悬念**。"另一处表述:"那个是'给予满足'(读者读下去的动力 = 奖励),这个是'制造焦虑'(读者读下去的动力 = 解答)。两者是节奏上的'推-拉'交替。" + +组合关系: + +- 与沿途埋金:推-拉交替。 +- 与镜头距离:镜头距离末端的钩子(今属 scene-craft 场景执行)。 +- 与句子节奏:句末的 micro-cliffhanger(今属 prose-craft 语言修辞)。 +- 与故事引擎:引擎是整体拉力,金币是局部推力(今属 concept-design 概念与前提)。 +- 与朝终局写:结局是终点,金币是沿途的灯(今属 story-ending 结尾设计)。 +- 与折线叙事:折线可作为"金币"的容器(今属 narration-pov 叙述与视角)。 + +## 三法对照 + +| 方法 | 动力来源 | 作用位置 | 兑现时点 | +|---|---|---|---| +| 势 | 事件间不可逆的推力 | 整条因果链(处境/心理/动作三环相扣) | 每一步都是下一步的必要条件,环环即兑 | +| 金币 | surprise / insight / beauty 小奖励 | 段中 / 段后,重点是中段(30%-70%) | 当下即兑,"读者捡到一颗金的高兴瞬间" | +| 钩子 | 未解决的小问题 | 断点前:句末、段末、章末、卷末、全书末 | 短期兑现:1 章内或 1 段内 | + +## 与相邻方法的区分 + +同一区分多书出现的合并一条,各书原话都保留。 + +### 金币 vs 伏笔 + +《写作工具》:"那个管'埋下**未来要兑现的承诺**'——是债务;这个管'埋下**当下就回报读者的小奖赏**'——是礼物。契诃夫之枪是'种下树',沿途埋金是'种下花让读者现在就闻到香'。" + +### 钩子 vs 伏笔 + +《写作工具》:"那个是'埋伏笔'(长期债务),这个是'放钩子'(短期未答)。伏笔是 10 章后兑现,内悬念是 1 章内或 1 段内兑现。" + +三层合起来:金币是当下就兑现的礼物;钩子是 1 章或 1 段内兑现的短期未答问题;伏笔是 10 章后才兑现的长期债务。三者不要混用。 + +### 金币 vs 触发事件 + +《写作工具》:"那个管'启动故事的那一击'(大爆炸,在开头 5%-15%),是赌注;这个管'沿途持续给读者小奖励',是糖。触发事件只来一次,金币要埋 3-5 次。" + +### 钩子 vs 触发事件 + +《写作工具》两处表述: + +- "那个是'启动故事的大事件'(全局赌注),这个是'局部断点的钩子'(具体好奇)。" +- "那个是'启动故事的全局事件',这个是'维持叙事的局部钩子'。一个是开关,一个是节拍器。" + +### 金币 vs 朝终局写 + +《写作工具》:"那个管'朝终局写'的全局方向感(结局已知);这个管'中段持续给奖赏'的局部节奏。倒推向结局是'在终点放灯塔',沿途埋金是'在路上放小灯笼'。" + +### 钩子 vs 镜头距离 + +《写作工具》:"那个是'摄影机距离'在叙事中的调度,这个是'断点前的张力放置'。" + +### 金币 vs 情节反转(plot twist) + +《写作工具》:"那个管'主线的反转',是事件;这个管'中段的小奖赏',是阅读体验。曲折是 plot 层,金币是 pacing 层。" + +### 金币 vs 展示不说教 + +《写作工具》:"那个管'用具体场景替代抽象断言',是微观手法;这个管'在中段放具体的小奖赏',是宏观节奏。一枚金币可以是展示不说教的产物,但'用具体场景'不等于'埋金币'——后者必须在'读者当下能感受到奖赏'的时点。" + +### 金币 vs 细节马赛克 + +《写作工具》:"那个管'用具体物拼出人物',是人物构造;这个管'在中段用小而具体的奖赏',是结构节奏。两者都用'具体',但用途不同——一个是拼人物,一个是奖赏读者。" + +## 势的同源方法(跨 skill 链接) + +- 与莎士比亚化同源:势 = 逻辑推演的速度感(今在 theme-and-stance 主题与立场)。 +- 与铺垫术关联:铺垫 = 给势铺路(今在 foreshadow-payoff 伏笔与回收)。 +- 与反常即戏关联:反常是势的转折点(今在 character-presentation 人物呈现)。 +- 与短中长篇三种体制配合:短篇势要密要短,长篇势可慢可散(今在 story-structure 故事结构)。 + +## 适用范围对照 + +| 方法 | 适合 | 不适用 / 慎用 | +|---|---|---| +| 势 | 所有叙事;短篇特别需要,链条要短但要密 | 慎用:意识流、纯抒情(靠"情绪流"不靠"势") | +| 金币 | 长篇小说(10 万字以上)、网络小说长篇连载、报告文学长篇、非虚构长篇、系列故事 | 短篇小说(<1 万字)、散文 / 抒情随笔、新闻报道 / 通讯、诗 / 短诗 | +| 钩子 | 长篇 / 网络小说 / 章节结尾 / 段末钩子 / 卷末悬念 | 短抒情诗 / 散文、实验文学 / 反叙事、学术论文 / 说明文、刻意反悬念的开放式叙述 | + +## 跨域指针(各一句话) + +- foreshadow-payoff:契诃夫之枪管伏笔的登记与兑现(长期债务);铺垫术管铺垫给势铺路。 +- story-structure:触发事件管启动故事的那一击(全局赌注);短中长篇三种体制管短篇势密、长篇势散。 +- story-ending:朝终局写管结局已知的全局方向感。 +- concept-design:故事引擎管故事整体的拉力。 +- narration-pov:折线叙事可作金币的容器。 +- scene-craft:镜头距离管摄影机距离在叙事中的调度。 +- prose-craft:句子节奏可承载句末的 micro-cliffhanger。 +- show-and-omission:展示不说教管用具体场景替代抽象断言。 +- character-presentation:细节马赛克管用具体物拼出人物;反常即戏管反常作为势的转折点。 +- theme-and-stance:莎士比亚化与势同源(逻辑推演的速度感)。 diff --git a/framework/catalog/dsh/skills/narrative-momentum/references/breakpoint-hooks.md b/framework/catalog/dsh/skills/narrative-momentum/references/breakpoint-hooks.md new file mode 100644 index 0000000..da7777b --- /dev/null +++ b/framework/catalog/dsh/skills/narrative-momentum/references/breakpoint-hooks.md @@ -0,0 +1,105 @@ +# 内悬念:在断点挂上未解问题 + +> 本文件全量来自《Writing Tools: 55 Essential Strategies for Every Writer》(Roy Peter Clark,中文通译《写作工具》),原书 Tool 30 · To generate suspense, use internal cliffhangers。 +> 适用:长篇 / 网络小说 / 章节结尾 / 段末钩子 / 卷末悬念。 + +## 原文摘录 + +> We don't think of the cliffhanger as an internal device. We associate it with serialized film or +> television adventures with big endings. ... Any dramatic element that comes right before a break in +> the action is an internal cliffhanger. +> +> — Roy Peter Clark, *Writing Tools* (Tool 30) + +## 方法骨架 + +Clark 把"悬念"重新框架为**一个放置问题**——不是"发生了什么大事",而是"在哪里放"。 + +传统 cliffhanger = 电视连续剧的"to be continued",大生死、大爆炸,显得套路。 +**Internal cliffhanger(内悬念)** = 在**任何叙事断点**(句末、段末、章末、卷末)前**放一个未解决的小戏剧性元素**。 + +判断标准:读者此刻有一个"想知道答案"的小问题吗?如果有,强化它;如果没有,加一个。 + +关键洞见: + +- 不必是"悬崖"——可以是"他看起来什么样?"(好奇) +- 不必是"to be continued"——可以从叙事内部自然生长 +- 5 个时点:句末、段末、章末、卷末、全书末 +- 核心机制:在断点前抛"问题未答",让读者"被迫"翻下去 + +这是**节奏放置框架**——决定"在哪里制造张力"。 + +## 案例全文 + +### 案例 1:Clark 引用电视剧商业插播前的钩子 + +- **问题**:商业插播前 5 秒,如何让观众不换台? +- **方法论的使用**:电视剧编剧在每个广告前放一个"未解决的小戏剧性元素"——不是"她会死吗"(太套路),而是"他的信会怎么写?"(具体好奇)。 +- **结论**:网文章末钩子、长篇卷末悬念、段末 micro-cliffhanger 都可以借鉴此机制。 +- **结果**:成为了"内悬念 vs 外悬念"的金标准对照——内悬念是从叙事内生出的钩子,不是编剧强行加的。 + +### 案例 2:长篇小说"X 章节末尾"诊断 + +- **问题**:写完一章后,如何判断章末是否有效? +- **方法论的使用**:Clark 给出诊断——读章末最后一句,问"读者此刻有未解决的疑问吗?"如果有,这一章的结尾是有效的;如果没有,加一个。 +- **结论**:章末钩子不必"大事件",可以是"她看到桌上那封信的署名是 X"(引发好奇)。 +- **结果**:成为了长篇小说节奏管理的工具——网文作者可以每章做此诊断。 + +## 何时使用(触发场景) + +### 用户会在什么情境下需要这个方法 + +1. 写完一章后觉得"章末平淡",读者翻过去就忘了。 +2. 写网文章节需要"付费点钩子",但不想用"to be continued"套路。 +3. 写到段末不知道怎么收——"该用句号还是省略号?" +4. 长篇中段节奏失速,需要"卷末悬念"维持读者追读。 +5. 短篇需要一个"最后一句"——想给读者留个问号。 + +### 语言信号(用户的话里出现这些就应激活) + +- "内悬念" / "internal cliffhanger" +- "章末钩子" / "章末平淡" +- "段末悬念" / "段末怎么收" +- "hook" / "钩子" +- "读者翻下去" / "让读者继续读" +- "付费点钩子" +- "章节结尾怎么写" +- "卷末悬念" + +## 可执行步骤 + +1. **诊断当前断点** + - 找出章节末 / 段末 / 卷末等所有"叙事断点"。 + - 完成标准:列出所有断点位置。 + - 判停条件:若该断点是"短抒情 / 散文 / 实验文学",跳过此方法。 + +2. **检验"未解决的疑问"** + - 对每个断点,问"读者此刻有未解决的小问题吗?" + - 完成标准:每个断点都有 1 个明确的"疑问"(可以是"他看到什么?" / "她接下来怎么做?" / "X 是什么?")。 + - 判停条件:若无疑问,加一个;若有疑问但"读者不在意",调整疑问的具体性。 + +3. **强化疑问,弱化答案** + - 检查断点前一段:是否"问题抛得够具体" + "答案没给"。 + - 完成标准:最后一句 / 最后一段是"问题"或"动作中断",不是"答案总结"。 + +## 边界:不要用在此处 + +- **短抒情诗 / 散文**——抒情节奏不靠悬念推进,反而靠"留白"。 +- **实验文学 / 反叙事**——故意打破阅读期待的项目不需要"钩子"。 +- **学术论文 / 说明文**——信息传递不需要制造悬念。 +- **刻意反悬念的开放式叙述**——开放式结局 = 反向操作,不是"用错"。 + +## 失败模式(作者在书中警告) + +- **"to be continued"套路化**:失败模式是依赖"大事件中断"(她跳下悬崖)而非"内生小好奇"。信号:所有章末都是"生死未卜"或"反派出现"。机制:读者对大事件脱敏,内悬念失效。预警:章末读起来像"电视剧宣传片"。 +- **钩子过密**:失败模式是每段都抛疑问。信号:读者疲劳,问号太多反而麻木。机制:人脑对"问题未答"有承受上限,过密反而抑制翻页欲。预警:每 500 字一个钩子,密度过高。 +- **疑问但读者不关心**:失败模式是"X 的鞋带是什么颜色"这种与人物/情节无关的细节。信号:读者跳过疑问不回头。机制:读者只关心"主角命运"和"主题进展",无关细节无法制造悬念。 + +## 盲点与时代局限(含中文适配) + +- 【中文适配】Clark 写于 2006 年(英文版),电视剧模型主要指美国 22 集周播剧。中文网文"日更 1 万字"+"付费章节"的钩子模式需要单独讨论——核心是"问题未答",但密度可更高。 +- 【中文适配】短视频 / 直播时代,读者的注意力曲线更短,内悬念的"时点"需要更密集(网文可以每 200-500 字一个 micro-hook)。 + +## 相邻方法区分指针 + +内悬念与金币、伏笔、触发事件、镜头距离的区分,以及金币-钩子的推拉交替,见 references/alternation-and-distinctions.md。 diff --git a/framework/catalog/dsh/skills/narrative-momentum/references/build-momentum.md b/framework/catalog/dsh/skills/narrative-momentum/references/build-momentum.md new file mode 100644 index 0000000..1eab269 --- /dev/null +++ b/framework/catalog/dsh/skills/narrative-momentum/references/build-momentum.md @@ -0,0 +1,197 @@ +# 造势:给小说内部装上"发动机" + +> 本文件全量来自《小说课》(毕飞宇)。原书第 7 讲,核心文本为蒲松龄《促织》。 + +## 原文摘录 + +毕飞宇讲"势"字: + +> 「什么叫'势'?'势'的本意是什么?你们学过汉语,看看这个字的组合就知道了,是我们男人的两只'丸'子。没了这两个'丸'子,你就坐怀不乱了,事情到此为止……但小说的内部是没有这两只'丸子'的,一切要靠作家去给予,这就叫'造势'。」 + +蒲松龄写《促织》,在斗蛐蛐之前,写了一句看似闲笔的话: + +> "将献公堂,惴惴恐不当意,思试之斗以觇之。"(《促织》) + +毕飞宇解读: + +> "这一句话是**左腿**,迈出去了,斗蛐蛐就是**右腿**。你不迈出去是不行的。" + +- **没有这一句**:斗蛐蛐就突兀、不自然。 +- **有这一句**:斗蛐蛐是必然——成名必须先试一试。 + +**这就是"势"**:小说内部有一股推力,把情节向前推。 + +## 方法骨架:势 = 小说内部的推力 + +**势 = 小说内部的推力。** + +- **没有势的小说**:作者拽着情节走,每一段都靠作者安排。 +- **有势的小说**:情节自己跑,作者都"说不上话"。 + +**"势"的本质**:**事件之间有不可逆的推力**。A 发生 → 必然 B → 必然 C。 + +## 案例全文 + +### 案例 1:蒲松龄《促织》"思试之斗以觇之" + +``` +将献公堂(要交差) → 惴惴恐不当意(怕不合要求) → 思试之斗以觇之(先试试看) +``` + +**三步造势**: + +- 处境(要交) +- 心理(怕不合) +- 行动(先试) + +→ 斗蛐蛐是必然的 + +### 案例 2:施耐庵 林冲的"步步紧逼" + +``` +高俅陷害(误入白虎堂) → 刺配沧州道 → 路上被欺 → 草料场 → 风雪 → 石头靠门 → 听到阴谋 → 杀人 +``` + +每一步都是下一步的"势"——**没有一步是多余的,也没有一步是突变的**。 + +### 案例 3:莫泊桑《项链》"项链丢失" + +``` +舞会出风头(势) → 回家路上丢失(势) → 借的钱不够赔(势) → 必须买真的还(势) → 10 年艰辛(势) +``` + +**每个环节都在加势**——读者无法停下。 + +### 案例 4:奈保尔 沃滋沃斯的"五个反常" + +``` +反常 1:等待(势) → 反常 2:请吃芒果(势) → 反常 3:讲故事(势) → 反常 4:临死前透露(势) +``` + +**反常累加 = 势累加**——读者无法不读下去。 + +## 何时使用(触发场景) + +1. 你的情节"读不下去" → 检查势 +2. 你的情节"该推进了但推不动" → 造势 +3. 你的情节"突然跳到下一段" → 缺势 +4. 你的高潮"不够高潮" → 高潮前没累足势 +5. 你的结尾"突然结尾" → 结尾的势没到位 + +## 可执行步骤 + +### 步骤 1:识别"势的起点" + +势从**事件 A** 开始——这是势的源头: + +```yaml +势的起点:将献公堂 +势的推力:惴惴恐不当意 +势的结果:思试之斗以觇之 → 斗蛐蛐 +``` + +**关键**:势的起点必须是**有具体动作的事件**,不是心理。 + +### 步骤 2:设计"势的链条" + +**A → B → C → D**,每个都是下一步的"必要条件": + +``` +A:处境(要交) +B:心理(怕不合要求) +C:行动(先试) +D:结果(斗蛐蛐) +``` + +**检验**: + +- 删 A,B 还能发生吗?→ 不能,A 是必要 +- 删 B,C 还能发生吗?→ 不能,B 是必要 +- 删 C,D 还能发生吗?→ 不能,C 是必要 + +**全是必要** → 势到位 + +### 步骤 3:势的"三要素" + +每个势的环节要包含: + +```yaml +处境:人物此时面对什么? +心理:人物此时怎么想? +动作:人物此时做什么? +``` + +**只有处境** = 势弱(读者无感) +**只有动作** = 势假(读者不信) +**三要素齐** = 势足 + +### 步骤 4:势的"递进" + +势不能"平行"——必须**递进**: + +``` +平行的势: + A → B → C → D(每个力度一样) + +递进的势: + A(轻)→ B(中)→ C(重)→ D(爆发) +``` + +**林冲的势**:误入白虎堂(中等)→ 刺配(中等)→ 路上被欺(中等)→ 草料场(升级)→ 听到阴谋(爆发) + +**前三个是"中势"——蓄力**;最后是"大爆发"。 + +### 步骤 5:检验"删掉一个还成立" + +写完所有势的环节后: + +> "删掉中间任何一环,故事还成立吗?" + +- 删掉 A 还成立 → A 没用,删 +- 删掉 A 不成立 → A 是必要,留 +- **全删都不成立** → 势到位 + +### 步骤 6:高潮的"势能" + +高潮必须**前期累足势**。 + +**检验**: + +> "高潮前我有多少个'势'在累?" +> "每个'势'的力度递增了吗?" +> "高潮瞬间的'势'是否最大?" + +蒲松龄的斗蛐蛐:3 步势 + 多次险情 + 鸡来袭 = 高潮势足 + +## 边界与常见错误 + +### 适用边界 + +- **适合**:所有叙事 +- **短篇特别需要**:短篇篇幅短,势的链条要短但要密 +- **慎用**:意识流、纯抒情(它们靠"情绪流"不靠"势") + +### 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 势的链条断 | 情节跳跃 | 检查"删 A 还成立吗" | +| 势不递进 | 高潮不爆 | 加大高潮前的势 | +| 势太多太散 | 节奏乱 | 选 1-2 个主势 | +| 势靠巧合 | 假 | 势要靠"性格 + 现实"驱动 | +| 势变成啰唆 | 累 | 简洁是势的灵魂 | + +## 一句话总结 + +> **没有势的小说靠作者拽着走;有势的小说情节自己跑——找到那个"必然的下一步"。** + +## 与其他方法的关系 + +跨 skill 链接(各一句话指针): + +- 与莎士比亚化同源:势 = 逻辑推演的速度感(今在 theme-and-stance 主题与立场)。 +- 与铺垫术关联:铺垫 = 给势铺路(今在 foreshadow-payoff 伏笔与回收)。 +- 与反常即戏关联:反常是势的转折点(今在 character-presentation 人物呈现)。 +- 与短中长篇三种体制配合:短篇势要密要短,长篇势可慢可散(今在 story-structure 故事结构)。 + +势与金币、钩子三台发动机的推拉配合、与伏笔等相邻方法的区分,见 references/alternation-and-distinctions.md。 diff --git a/framework/catalog/dsh/skills/narrative-momentum/references/midway-rewards.md b/framework/catalog/dsh/skills/narrative-momentum/references/midway-rewards.md new file mode 100644 index 0000000..0cc6608 --- /dev/null +++ b/framework/catalog/dsh/skills/narrative-momentum/references/midway-rewards.md @@ -0,0 +1,114 @@ +# 沿途埋金:让读者在中段不弃读 + +> 本文件全量来自《Writing Tools: 55 Essential Strategies for Every Writer》(Roy Peter Clark,中文通译《写作工具》),原书 Tool 32 · Place gold coins along the path。 +> 适用:长篇小说(10 万字以上)、网络小说长篇连载、报告文学长篇、非虚构长篇、系列故事。 + +## 原文摘录 + +> Imagine you are walking on a narrow path through a deep forest. You stroll a mile, and there at +> your feet you find a gold coin. You pick it up and put it in your pocket. You walk another mile, and, +> sure enough, you see another gold coin. What will you do next? You walk another mile in search of +> another coin, of course. … The easiest thing for a reader to do, argued famed editor Barney Kilgore, +> "is to quit reading." With no gold coins for motivation, the reader may drift out of the forest. +> +> — Roy Peter Clark, *Writing Tools* (Tool 32) + +## 方法骨架 + +Clark(借 Don Fry / Barney Kilgore 的比喻)的核心洞察:**读者不是被"意义"驱动的,是被"小奖励"驱动的。** + +长篇最容易塌陷的不是开头(有 hook)和结尾(有 payoff),而是**中段**——读者热情降温、人物命运已知、情节推进乏力。在这三段"林中窄路"上,作者必须**沿途撒下金币**——surprise(惊奇)、insight(洞见)、beauty(美感)三类小奖赏,让读者每走一段就"捡到一次"。 + +Clark 给出三时点的金币机制: + +- **开头(Opening)**:Hook 不够 = 读者不进森林;开头第一枚金币 = "为什么我要走这条路"。 +- **中段(Middle)**:这是 10 万字长篇的"塌陷高危区",**必须**埋 3-5 枚"小而具体"的金币——逸事、惊人事实、机智引语、出彩金句、突然的小戏剧性时刻;**不必是 plot twist**(那是伏笔、内悬念的事),而是"读者捡到一颗金的高兴瞬间"。 +- **结尾前(Pre-Climax)**:读者已猜到结局、动力最低,需要"再次加码的金币"——重新加赌注(up the ante)、给一个意外视角、出乎意料的小场景。 + +判断标准:作者应自问"这一段给读者的**当下奖赏**是什么"。没奖赏,就是平地——读者会走出森林。 + +## 案例全文 + +### 案例 1:Shakespeare 悲剧第 3 幕的"巨大金币" + +- **问题**:5 幕悲剧从开场到结局,中段(第 3 幕)是"读者最易弃读"的——观众已经知道"主角要死",动力最低。 +- **方法论的使用**:Clark 指出 Shakespeare 在第 3 幕设计"巨大的金币"——往往是关键独白 / 突然的转折 / 戏剧性高峰(如哈姆雷特的"生存还是毁灭"、麦克白的"明日明日明日"、李尔王的暴风雨独白)。这枚金币**不是结局**(那是第 5 幕),但足以让观众"再走两英里"。 +- **结论**:伟大悲剧的"中段"不靠情节推进,而靠"读者当下能捡到的金"——这些金是**戏剧性的、感官的、可被记忆的**瞬间。 +- **结果**:Clark 用此例证明"中段奖励"不是通俗小说的专利;5 幕悲剧若无第 3 幕的"独白金币",观众会真的离场。 + +### 案例 2:Mark Twain《Huck Finn》第 21 章——拙劣莎剧演员的中段转折 + +- **问题**:42 章的长河小说,在第 21 章(地理意义的中段)如何"奖励读者"? +- **方法论的使用**:Clark 引用 Huck Finn 第 21 章——两个骗子上岸演"莎剧桥段"(the royal family on a barge),演得"拙劣到滑稽"。这不是主线剧情,但**它给读者一颗金**:一节出人意料的喜剧、一个人物间的"小对白"、一个让读者"噗"一下的瞬间。 +- **结论**:中段金币**不必推进主线**——它是给读者的"读到这里的小礼物",一个让阅读继续的理由。 +- **结果**:成为了 Clark 评价"中段不需推进剧情、只需给奖赏"的金案例;展示"逸事 / 喜剧场景 / 风格化的偏离"都是合法的金币类型。 + +## 何时使用(触发场景) + +### 用户会在什么情境下需要这个方法 + +1. 写长篇 10 万字以上,自觉"中段(30%-70%)部分读者弃读率最高"——自我诊断是中段塌陷。 +2. 网文连载写到中段,数据(收藏掉、追读降)显示"读者开始走"。 +3. 写完 5 万字发现"中段全是情节推进,没有任何'停下来的一刻'"——通读像坐长途火车,没景色。 +4. 编辑反馈"中段没高潮"——作者分不清"高潮"和"小奖励"。 +5. 问"为什么别人长篇中段我也读了 / 我的中段就乏味"——要可操作的中段设计。 + +### 语言信号(用户的话里出现这些就应激活) + +- "中段塌陷" +- "中段无力" +- "中段没动力" +- "读者弃读" +- "读者怎么不弃读" +- "写到一半没人看了" +- "sagging middle" +- "mid-novel reward" +- "沿途埋金" +- "gold coin" +- "中段没高潮" +- "故事中段奖励" +- "长篇中段怎么写" + +## 可执行步骤 + +1. **诊断中段塌陷区** + - 找出长篇的"中段"——按字数 = 30%-70% 区间,按章节数 = 中间 1/3。 + - 列出中段每章/每 1 万字的"金币清单"——每章 / 每万字有 1 个 surprise / insight / beauty 吗?没有 = 塌陷。 + - 完成标准:中段每 1 万字至少 1 枚"可被读者当下就捡到"的金币;**金币类型** = surprise(惊奇)/ insight(洞见)/ beauty(美感)三类之一;**金币特征** = 小而具体,不必推进主线。 + - 判停条件:若中段已每 1 万字有 1 枚金,无需再加;若 3 万字连续无金,立刻停下来补。 + +2. **为三时点各设 1 枚"定位金"** + - 开头(0%-10%):第一枚金 = 让读者知道"为什么我要走这条路"——hook + 第一笔奖赏。 + - 中段(30%-70%):至少 3 枚 = 逸事、惊人事实、机智引语、出彩金句、突然的小戏剧性时刻(任选类型)。 + - 结尾前(80%-95%):最后一枚 = "再走一段"的奖赏——重新加赌注、出乎意料的小场景、让读者"没想到"的瞬间。 + - 完成标准:三时点各 1 枚"定位金"已识别,中段 3 枚已就位;不与已有伏笔、触发事件、内悬念重复(它们是"承诺 / 启动 / 焦虑",这里是"奖励")。 + +3. **对每枚金币做"surprise / insight / beauty"分类** + - **surprise(惊奇)**:读者没料到的事实 / 场景 / 引用 / 巧合。 + - **insight(洞见)**:对人物 / 主题 / 世界的"我从未这样想过"的一句话。 + - **beauty(美感)**:一个意象 / 一句话 / 一段描写让读者停下来说"写得真好"。 + - 完成标准:每枚金币被标注类型;中段三类至少各占 1 枚(类型多样化防"全是 surprise"或"全是 beauty")。 + - 判停条件:若一类金币 3+ 次重复(如连续 3 章都是"美句"),改用其他类型,避免读者审美疲劳。 + +## 边界:不要用在此处 + +- **短篇小说(<1 万字)**——中段本身很短(几页),无独立"沿路"可埋;若硬埋会让短篇变松散。 +- **散文 / 抒情随笔**——散文中段是"递进式思考",不是"叙事路径",埋金反而打断沉思节奏。 +- **新闻报道 / 通讯**——报道是"倒金字塔",开头给全部信息,无"中段路径"可言。 +- **诗 / 短诗**——无中段结构。 + +## 失败模式(作者在书中警告) + +- **"中段没金币 = 弃读"**:失败模式是中段没有 surprise / insight / beauty 的小高潮,读者觉得"没东西可捡"而停止前进。Clark 称之为"long, flat, middle, as if the whole thing had been emptied out"。信号:中段连续 3+ 章无"读者会抄下来 / 告诉朋友"的瞬间;朋友的弃读点都在 30%-70%。 +- **"开头没金币 = 不进场"**:Hook 不够强 = 读者不进森林;但 hook 不等于"第一枚金"——hook 是"我看到地上有东西",第一枚金是"我捡起来放进口袋"——两者都要有。 +- **"结尾前没金币 = 烂尾"**:结尾前读者已猜到结局、动力最低,无金 = 草草收场;Clark 把它和"中段塌陷"列为"读者弃读三时点"。 + +## 盲点与时代局限(含中文适配) + +- **Kilgore 是新闻业比喻**:Barney Kilgore 是《华尔街日报》前主编,他的"沿途埋金"是**新闻业**的术语(让读者在长报道中持续得到奖赏)。Clark 把这个比喻迁移到小说,需要**注明**——小说中的"金"不必是"事实"(新闻的奖励),也可以是"人物 / 意象 / 金句"等更文学性的奖励。 +- 【中文适配】**时代局限**:Clark 的英文原版"金"偏指"small scene, anecdote, quote, surprising fact"——偏新闻/非虚构的"事实性奖励"。迁移到中文小说时,需要扩展:**人物的小顿悟、对话中一句出彩台词、意象的一次妙用、风格化的一段偏离**——这些是中文小说更常见的"金"。 +- 【中文适配】**网文 / 连载的特殊性**:Clark 写于 2006 年,网文连载还未成为主流;中文网文有"日更 5000 字"的压力,作者更容易"写完中段没时间埋金"——此方法对网文作者尤其重要,但需要本地化为"每 1 万字自检一次"。 + +## 相邻方法区分指针 + +金币与伏笔、触发事件、内悬念、朝终局写、情节反转(plot twist)、展示不说教、细节马赛克的区分,以及三台发动机的推拉交替,见 references/alternation-and-distinctions.md。 diff --git a/framework/catalog/dsh/skills/narrative-momentum/references/momentum-checklist.md b/framework/catalog/dsh/skills/narrative-momentum/references/momentum-checklist.md new file mode 100644 index 0000000..a6d4c4c --- /dev/null +++ b/framework/catalog/dsh/skills/narrative-momentum/references/momentum-checklist.md @@ -0,0 +1,64 @@ +# 叙事动力自查清单 + +> 由造势、沿途埋金、内悬念三个方法的可执行步骤重排而成。写完初稿或改稿前按关依次过;方法细节与案例原文见 references/ 对应文件。 + +## 第一关:势链检验(情节推不动、跳跃、高潮不爆时) + +对应造势方法(references/build-momentum.md)。 + +1. **找势的起点**:势从事件 A 开始。它是不是**有具体动作的事件**(不是心理)? + - 台账示例——势的起点:将献公堂;势的推力:惴惴恐不当意;势的结果:思试之斗以觇之 → 斗蛐蛐。 +2. **写成链条**:A → B → C → D,每一环都是下一环的必要条件。 +3. **逐环配三要素**:处境(人物面对什么)/ 心理(人物怎么想)/ 动作(人物做什么)。 + - 只有处境 = 势弱(读者无感);只有动作 = 势假(读者不信);三要素齐 = 势足。 +4. **删环检验**:"删掉中间任何一环,故事还成立吗?" + - 删 A 还成立 → A 没用,删;删 A 不成立 → A 是必要,留;全删都不成立 → 势到位。 +5. **递进检查**:势是平行(每环力度一样)还是递进(轻 → 中 → 重 → 爆发)?平行的要改成递进。 +6. **高潮势能三问**:"高潮前我有多少个'势'在累?""每个'势'的力度递增了吗?""高潮瞬间的'势'是否最大?" +7. **错误速查**:链条断(情节跳跃,去查"删 A 还成立吗")/ 不递进(高潮不爆,加大高潮前的势)/ 太多太散(节奏乱,选 1-2 个主势)/ 靠巧合(假,改成"性格 + 现实"驱动)/ 啰唆(累,简洁是势的灵魂)。 + +## 第二关:中段金币台账(长篇 10 万字以上 / 网文连载) + +对应沿途埋金方法(references/midway-rewards.md)。短篇(<1 万字)、散文、新闻报道、诗跳过本关。 + +1. **圈出中段**:按字数 30%-70% 区间,按章节数中间 1/3。 +2. **填台账**(按每 1 万字切段): + +| 段落区间 | 金币内容(逸事 / 惊人事实 / 机智引语 / 出彩金句 / 突然的小戏剧性时刻) | 类型(surprise / insight / beauty) | 读者的当下奖赏 | +|---|---|---|---| +| 30%-40% | | | | +| 40%-50% | | | | +| 50%-60% | | | | +| 60%-70% | | | | + +3. **判停条件**: + - 中段每 1 万字至少 1 枚"读者当下就能捡到"的金币;已每万字 1 枚则无需再加。 + - **连续 3 万字无金,立刻停下来补。** + - 中段三类(surprise / insight / beauty)至少各占 1 枚;同一类型连续重复 3+ 次就换类型,防审美疲劳。 +4. **三时点定位金核对**: + - 开头(0%-10%):第一枚金让读者知道"为什么我要走这条路"。注意 hook ≠ 金币:hook 是"我看到地上有东西",第一枚金是"我捡起来放进口袋",两者都要有。 + - 中段(30%-70%):至少 3 枚已就位。 + - 结尾前(80%-95%):读者已猜到结局、动力最低,最后一枚"再走一段"的奖赏(重新加赌注 / 意外视角 / 出乎意料的小场景)已就位。 + - 金币不与已有伏笔、触发事件、内悬念重复——它们是承诺 / 启动 / 焦虑,金币是奖励。 +5. **当下奖赏自问**:写稿中随时问"这一段给读者的当下奖赏是什么?"答不出来 = 平地。 +6. 【中文适配】中文网文按"每 1 万字自检一次"执行;中文小说的"金"优先从人物小顿悟、对话出彩台词、意象妙用、风格化偏离里找,不必限于事实性奖励。 + +## 第三关:断点悬念检查(章节体 / 连载) + +对应内悬念方法(references/breakpoint-hooks.md)。短抒情诗 / 散文、实验文学 / 反叙事、学术论文 / 说明文、刻意反悬念的开放式叙述跳过本关。 + +1. **列出断点**:句末、段末、章末、卷末、全书末——所有叙事断点的位置。 +2. **逐个检验疑问**:读每个断点的最后一句,问"读者此刻有未解决的小问题吗?" + - 有 → 断点有效,强化它。 + - 无 → 加一个。疑问必须具体,且挂钩主角命运或主题进展("他看到什么?" / "她接下来怎么做?" / "X 是什么?");"X 的鞋带是什么颜色"这类无关细节造不成悬念。 +3. **强化疑问,弱化答案**:断点前一段是否"问题抛得够具体 + 答案没给"?最后一句 / 最后一段必须是"问题"或"动作中断",不是"答案总结"。 +4. **密度与套路速查**: + - 章末全是"生死未卜""反派出现"?→ to be continued 套路化,读者已对大事件脱敏,改用叙事内生长的小好奇("他的信会怎么写?")。 + - 每 500 字一个钩子?→ 过密,超过"问题未答"的承受上限,反而抑制翻页欲。 + - 【中文适配】网文付费章节 / 日更场景密度可更高,可每 200-500 字一个 micro-hook,但仍以读者注意力上限为界。 + +## 三关之后的整体自问 + +- 势(事件推力)、金币(当下奖赏)、钩子(未解问题)是否都就位? +- 节奏是否推拉交替——先给金币,再抛内悬念——而不是一路只拉或一路只奖? +- 势、金币、钩子是否与伏笔(长期债务)、触发事件(全局赌注)区分开,没有互相冒充? diff --git a/framework/catalog/dsh/skills/novel-diagnosis/SKILL.md b/framework/catalog/dsh/skills/novel-diagnosis/SKILL.md new file mode 100644 index 0000000..7703f8b --- /dev/null +++ b/framework/catalog/dsh/skills/novel-diagnosis/SKILL.md @@ -0,0 +1,115 @@ +--- +name: novel-diagnosis +description: | + 激活场景:用户手里有一部写完或在写的小说,感觉不对劲但说不清哪里不对——"我的小说有什么问题"、 + "它缺什么"、"为什么被拒稿"、"虎头蛇尾/高开低走"、"中段疲软"、"人物写扁了"、"全是流水账没有峰值"、 + "读者很兴奋但没理解"、"收尾太硬"、"形式大于内容";或要把自己的作品和参照作品比差距;或交付诊断/ + 评论/书评结论前需要扫描一遍有没有空话。 + 关键 trigger:"诊断作品 / 小说体检 / 我的小说有什么问题 / 缺什么 / 为什么被拒 / 虎头蛇尾 / + 高开低走 / 中段疲软 / 流水账 / 写扁了 / 故事还是情节 / 后来呢 / 为什么 / 有时间没价值 / + 情节和人物谁赢 / 模式还是节奏 / 幻想还是预言 / 六便士 / 难懂 / 奇书 / 六核 / 七侧面 / + 圆桌 / 伪学者 / 怎么系统地看一部小说"。 + 不适用于:请求写作技法而非找毛病;非虚构;纯新闻速报/菜谱等时间流即内容的对象;作者习惯/心理培养问题。 + 症状已落到具体环节时不要停在本 Skill,按下表交接:结构/里程碑→story-structure;弃读/钩子→narrative-momentum; + 建角变量→character-design;登场呈现→character-presentation;对话声音→dialogue-craft;场景执行→scene-craft; + 标签画面→show-and-omission;句段修辞→prose-craft;POV 机制→narration-pov;主题/荒诞幽默→theme-and-stance; + 埋收债→foreshadow-payoff;idea/引擎→concept-design;节拍工作流→story-planning;收尾姿态→story-ending; + AI 味→diagnose-ai-flavor(须先诊断)。 +--- + +# novel-diagnosis 作品诊断 + +对一部小说做整体体检:先把问题落进维度,再用五个透镜查具体病灶,最后清理诊断结论防止空话。 + +## 方法索引 + +按诊断动作组织;方法细节、案例、引文都在 references 里,这里只给一句话和指针。 + +### 第一步 · 把问题落进维度 + +- 写作能力 = 4 元素(概念/人物/主题/结构)+ 2 技能(场景执行/写作声音)共六桶,任何问题都能落桶,任何一桶不及格整本就失败 → references/dimension-frameworks.md +- 小说复杂到无法定义,放弃定义改为看七侧面(故事/人物/情节/幻想/预言/模式/节奏),每个侧面配一种读者素质 → references/dimension-frameworks.md +- 好坏 = 维度间的动态平衡:先定位哪个维度不及格,再说清它向哪个方向失衡 → references/dimension-frameworks.md + +### 第二步 · 五个透镜查病灶 + +- 结构层:标出最近 5 个提问是"后来呢"还是"为什么",判断停在故事层还是进了情节层 → references/story-plot.md +- 意义层:查时间堆积还是价值峰值——找不到读者事后仍会回想的瞬间就是消磨 → references/time-value.md +- 张力层:看守尾处人物是否消失/死亡/沦为工具,判定情节与人物谁赢、代价多大 → references/plot-character.md +- 形式层:问全书能否用一个几何形象概括(模式)、有没有携带变化的重复元素(节奏) → references/pattern-rhythm.md +- 神异层:走六便士测试,判幻想面(戏耍)还是预言面(歌唱),再按中文志怪/神魔/仙侠谱系看接受姿态 → references/fantasy-prophecy.md + +### 第三步 · 比较诊断(有参照作品时) + +- 圆桌论:抹掉年代/流派标签,把自己的稿子和参照作品匿名并置,只比"做了什么"不比"何时写的" → references/round-table.md + +### 第四步 · 清理诊断结论 + +- 伪学者自检:扫描五大症状(没读完就分类、天才崇拜、便携词、挂生平背景、漂亮代替准确)+ 自检三问 + 最小可替换段落 → references/quack-scholar.md + +### 冲突标注 + +- Brooks 主张六桶穷尽一切写作元素;福斯特主张七侧面只是"我感兴趣的方向"、可伸缩。两条立场都保留:用六桶查盲区,用七侧面给特殊作品增补侧面,详见 references/dimension-frameworks.md。 + +## 症状→专精 Skill 路由 + +整体体检后若症状已落到具体环节,**交接给专精 Skill**,本 Skill 不再展开改稿技法。 + +| 症状 / 用户说法 | 优先 Skill | 说明 | +|---|---|---| +| 结构松散、中段塌陷、里程碑错位、赌注不升 | `story-structure` | 四箱/六里程碑/Setup-FPP 成因 | +| 章末平淡、弃读、势链断、缺钩子 | `narrative-momentum` | 势/金币/内悬念;结构成因仍可能需 `story-structure` | +| 人物扁、工具人、没弧、撞型 | `character-design` | 变量/弧线/原型 | +| 登场像形容词清单、关系网、反常瞬间 | `character-presentation` | 呈现给读者看 | +| 对话一个声音、太书面、不推动情节 | `dialogue-craft` | 说话方式 owner | +| 场景薄、使命不清、进出点弱 | `scene-craft` | 场景执行 | +| 太抽象、标签堆情绪、缺画面 | `show-and-omission` | 标签→场景;句段修辞另见 `prose-craft` | +| 句长单调、修辞密度、风格漂移 | `prose-craft` | 句段层修辞 | +| 视角穿帮、POV 切换、外来者切入机制 | `narration-pov` | 视角与叙述模式;荒诞幽默全文案例归 `theme-and-stance` | +| 主题说教、手软、沉重题材幽默/荒诞距离 | `theme-and-stance` | 主题演示与作家立场 | +| 伏笔没收、契诃夫之枪、铺垫突兀 | `foreshadow-payoff` | 仅限埋/收链,不含泛化高潮课 | +| idea 不够、引擎不清、写到一半散 | `concept-design` | 概念层 | +| 节拍表、灵感 vs 计划工作流 | `story-planning` | 概念已定后的规划流程 | +| 烂尾、拖尾、结尾姿态、开放/闭合收束 | `story-ending` | 终局倒推与收尾策略 | +| AI 味、检测链、规则注入 | `diagnose-ai-flavor` / `prevent-ai-flavor` | 须先诊断再改,见写作槽位铁律 | + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|---------| +| references/dimension-frameworks.md | 六核六桶(4 元素 + 2 技能)与七侧面框架合并、动态平衡判断、维度定位执行流程、作者自传 5 部小说与拒稿比例案例、贝内特 vs 托尔斯泰与《使节》案例、失败模式与盲点、穷尽 vs 可伸缩冲突标注、中文落地 | +| references/story-plot.md | 故事问"后来呢"情节问"为什么"、情节三条件、故事/情节合作、提问切换诊断与执行步骤、司各特《古董商人》/梅瑞狄斯《利己主义者》/贝内特 vs 托尔斯泰案例、失败模式与边界、章回小说中文落地 | +| references/time-value.md | 时间生活 vs 价值生活、双重忠诚、时间轴/价值轴征兆、执行步骤、贝内特《老妇人的故事》/托尔斯泰《战争与和平》/山鲁佐德案例、失败模式与边界、中文网文中文落地 | +| references/plot-character.md | 情节-人物拉锯元模型、三种解决(哈代式/梅瑞狄斯式/反情节式)、虎头蛇尾诊断、执行步骤与代价对策、哈代《无名的裘德》/梅瑞狄斯/纪德《伪币制造者》案例、失败模式与边界、章法中文落地 | +| references/pattern-rhythm.md | 模式 vs 节奏二分、节奏检验公式、模式的代价、节奏的失败、执行步骤、法朗士《泰伊丝》/普鲁斯特小乐句/《使节》案例、失败模式与边界、章回回目章法中文适配 | +| references/fantasy-prophecy.md | 幻想/预言孪生光柱、六便士测试、双向判断、执行步骤、《项狄传》/《白鲸记》/阿斯奎斯案例、失败模式与边界、中文志怪/神魔/仙侠转述与适用边界 | +| references/round-table.md | 圆桌论匿名并置、两两盲文对比、信念前提与代价、执行步骤、伍尔夫 vs 斯泰恩/威尔斯 vs 狄更斯/哈代 vs 司各特案例、失败模式与边界、跨朝代比较中文落地 | +| references/quack-scholar.md | 伪学者五大症状、自检三问、最小可替换段落、执行步骤、加洛韦天气分类/天才崇拜/司各特"会讲故事"案例、失败模式与边界、翻译腔/公文腔/空泛赞美词中文落地 | +| references/_coverage.md | 九个源单元的覆盖对照表 | + +## 脚本 + +| 脚本 | 用途 | +|------|------| +| references/diagnosis-workflow.md | 三步体检台账:维度定位 → 五个透镜查病灶 → 评审纪律清理结论,附征兆速查表,一份填完出诊断 | +| references/quack-scholar-scan.md | 伪学者自检扫描表:五大症状 0/1 扫描 + 自检三问 + 最小可替换段落 + 漂亮词改写 | + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 红线 + +- 只给当前创作阶段的建议,不越权改设定主权、不绕过检测链、不复制粘贴其它 Skill 的 owner 定义。 +- 无用户明确授权不得替用户定稿或提交 Git。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/dsh/skills/novel-diagnosis/references/_coverage.md b/framework/catalog/dsh/skills/novel-diagnosis/references/_coverage.md new file mode 100644 index 0000000..7cc5cde --- /dev/null +++ b/framework/catalog/dsh/skills/novel-diagnosis/references/_coverage.md @@ -0,0 +1,27 @@ +# novel-diagnosis 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| aspects-of-the-novel/fantasy-prophecy-twin | references/fantasy-prophecy.md | +| aspects-of-the-novel/fantasy-prophecy-twin | references/round-table.md | +| aspects-of-the-novel/pattern-vs-rhythm | references/pattern-rhythm.md | +| aspects-of-the-novel/pattern-vs-rhythm | references/dimension-frameworks.md | +| aspects-of-the-novel/plot-character-tug | references/plot-character.md | +| aspects-of-the-novel/plot-character-tug | references/story-plot.md | +| aspects-of-the-novel/plot-character-tug | references/round-table.md | +| aspects-of-the-novel/quack-scholar-check | references/quack-scholar.md | +| aspects-of-the-novel/round-table | references/round-table.md | +| aspects-of-the-novel/round-table | references/fantasy-prophecy.md | +| aspects-of-the-novel/round-table | references/plot-character.md | +| aspects-of-the-novel/seven-aspects | references/dimension-frameworks.md | +| aspects-of-the-novel/seven-aspects | references/time-value.md | +| aspects-of-the-novel/seven-aspects | references/story-plot.md | +| aspects-of-the-novel/seven-aspects | references/pattern-rhythm.md | +| aspects-of-the-novel/story-vs-plot | references/story-plot.md | +| aspects-of-the-novel/story-vs-plot | references/plot-character.md | +| aspects-of-the-novel/time-vs-value-life | references/time-value.md | +| aspects-of-the-novel/time-vs-value-life | references/dimension-frameworks.md | +| aspects-of-the-novel/time-vs-value-life | references/story-plot.md | +| story-engineering/six-core-competencies | references/dimension-frameworks.md | diff --git a/framework/catalog/dsh/skills/novel-diagnosis/references/diagnosis-workflow.md b/framework/catalog/dsh/skills/novel-diagnosis/references/diagnosis-workflow.md new file mode 100644 index 0000000..fa2dcd9 --- /dev/null +++ b/framework/catalog/dsh/skills/novel-diagnosis/references/diagnosis-workflow.md @@ -0,0 +1,115 @@ +# 作品诊断三步体检台账 + +用法:对一部完成或在写的小说做整体体检时从第 0 节顺着填。三段执行:**维度定位 → 五个透镜查病灶 → 评审纪律清理结论**。每节标注判断标准和落点,方法细节与案例见对应 references 文件。填完第 4 节的每条诊断必须配一个改得下去的动作,填完第 5 节才算完成。 + +--- + +## 0. 症状陈述 + +用用户自己的话写症状(不定性、先不归类): + +> ____ + +是整体"感觉不对但说不清",还是已有具体怀疑部位?____ + +## 1. 维度定位(→ references/dimension-frameworks.md) + +先不给结论,把症状逐条对照维度框架,判定问题落在哪个或哪几个维度。 + +六核之桶勾选(): + +| 桶 | 症状像不像落在这里 | 备注 | +|---|---|---| +| Concept 概念 | □ | | +| Character 人物 | □ | | +| Theme 主题 | □ | | +| Structure 结构 | □ | | +| Scene Execution 场景执行 | □ | | +| Writing Voice 写作声音 | □ | | + +七侧面失衡判断():哪个侧面过强、哪个过弱? + +> ____ 侧面过强,表现为 ____;____ 侧面过弱,表现为 ____。 + +判断标准:维度是诊断镜,不是评分表——不给维度打 1-10 分,不把维度拆成独立任务清单。 + +## 2. 五个透镜查病灶 + +对第 1 节怀疑的维度,逐个透镜过一遍。每个透镜都有判停条件,不适用就跳过。 + +### 透镜 1 · 结构层:是故事还是情节(→ references/story-plot.md) + +- 标出最近 5 个关键事件引发的提问,是"后来呢"还是"为什么": + 1. ____(后来呢 / 为什么) + 2. ____(后来呢 / 为什么) + 3. ____(后来呢 / 为什么) + 4. ____(后来呢 / 为什么) + 5. ____(后来呢 / 为什么) +- 判定:全是"后来呢" → 停在故事层;至少 2 个"为什么" → 进入情节层。判定:____ +- 故事层健康吗(读者想不想继续听)?失败征兆:走神、中途弃书、"读了两百页啥也没记住"。答:____ +- 情节层健康吗(至少 2 个"为什么"被揭示、至少 1 处悬念 = 时序断裂 + 重新整合)?答:____ + +### 透镜 2 · 意义层:有时间,有没有价值(→ references/time-value.md) + +- 时间轴症状("我花了 X 时间"、"熬过了 X 分钟"、"流水线/流水账")有没有?列 1 条:____ +- 在全书里找价值峰值(读者读完仍会回想的瞬间):找到几个?分别是?____ +- 判定:找不到任何价值峰值 = 时间堆积(消磨)。时间轴过强 / 价值轴过弱 / 平衡:____ + +### 透镜 3 · 张力层:情节和人物谁赢(→ references/plot-character.md) + +- 看守尾处:人物是否消失、死亡或沦为工具?标出至少 1 处"逻辑压倒自由"或"自由压倒逻辑"的征兆:____ +- 拉锯哪方胜出?胜出代价多大?____ +- 选择解决方式(哈代式人物牺牲 / 梅瑞狄斯式情节胜出但节制 / 反情节取消主线):____,理由("因为本作是 [类型/规模/目的],所以……"):____ +- 对策:对哈代式加 1 个圆形人物;对梅瑞狄斯式加 1 个"言犹未尽"桥段;对反情节加 1 个主线暗示。选定:____ + +### 透镜 4 · 形式层:模式还是节奏(→ references/pattern-rhythm.md) + +- 全书能否用一个几何形象/章法概括(沙漏/大循环/大教堂放射线/对偶回目章法)?是 → 模式型,形象:____;否 → ____ +- 有没有携带变化的重复元素(乐句/主题/意象,如小乐句、重现的意象)?有 → 节奏型,元素:____ +- 判停:两者皆无 → 形式感弱,走其它分析。 +- 模式型:模式阉割了什么(人物类型/情节/幻想预言)?被阉割的是不是最重要的部分?____ +- 节奏型:重复每次是否带来新意?(否则节奏死了,像高尔斯华绥的西班牙猎犬约翰)____ + +### 透镜 5 · 神异层:幻想与预言(→ references/fantasy-prophecy.md) + +- 先查适用边界:规则化类型奇幻(体系化修仙仙侠、系统流、无限流)自带接受规则,不需六便士测试;无神异的自然主义题材不用本透镜。适用吗?____ +- 有没有光柱(横贯一切、自己决定生长方向的东西)?标出至少 1 处:____ +- 走六便士测试:作品要求读者额外接受什么("接受混乱"/"接受死亡在文本外的延续"/"接受动物有灵魂"……)?____ +- 是幻想面(戏谑玩闹、随手即兴)还是预言面(语调"歌唱"的庄严之作)?____ +- 按中文志怪/神魔/仙侠谱系看接受姿态:神怪是否通人情?门槛在意愿还是能力?____ +- 双向判断:作品召唤是否合理(是)+ 读者选择不响应是否合理(是),双方都无错。____ + +## 3. 把失衡写成因果(→ references/dimension-frameworks.md) + +每条诊断写成"X 维度过强/过弱,导致 Y",不说"形式太霸道"这类空话: + +1. ____ 维度过强/过弱,导致 ____。 +2. ____。 + +## 4. 给出具体修改动作 + +每条诊断配至少一个改得下去的动作(落到段落、人物、元素): + +| 诊断 | 修改动作 | +|---|---| +| | 例:加一个圆形人物打破扁平 / 加一段倒叙揭示因果、调动读者头脑 / 插入一个价值峰值(一个让读者愣住的细节)/ 用一个携带变化的重复元素黏合散落事件 / 放宽闭环,给人物一次违背情节的举动 | + +判断标准:动作落到段落、人物、元素;"加强情节""提升深度"不算动作。 + +## 5. 清理诊断结论(评审纪律) + +- 伪学者自检:把诊断交给 references/quack-scholar-scan.md 扫一遍,重点查"最小可替换段落"(把作品名换成另一部,段落若仍成立就是空话,必须重写)。 +- 圆桌复查(仅比较类结论):抹掉年代、流派、思潮标签再看判断是否改变、为什么改变(→ references/round-table.md)。 +- 谦虚声明:在结论末尾加"以上诊断基于对作品的有限阅读,可能有盲点"。 + +## 征兆速查表 + +| 征兆 | 病灶 | +|------|------| +| 读者走神、中途弃书、读完啥也没记住 | 故事层失败:事件流不抓人() | +| 句子漂亮但没逻辑,想不起因果 | 情节层失败:因果网没建立() | +| 只记得"读了两百页",没有可回想的瞬间 | 时间堆积,无价值峰值() | +| 收尾处人物消失、死亡或沦为工具 | 情节压倒人物,拉锯未处理() | +| 重复元素只重现不发展,沦为标语 | 节奏死亡,僵化成符号() | +| 人物清单短,神异维度进不来 | 模式过强,闭环阉割人性内容() | +| 诊断里全是"有灵气/是 X 流派/反映了 X 倾向" | 伪学者式空话,须重写() | diff --git a/framework/catalog/dsh/skills/novel-diagnosis/references/dimension-frameworks.md b/framework/catalog/dsh/skills/novel-diagnosis/references/dimension-frameworks.md new file mode 100644 index 0000000..3faef1c --- /dev/null +++ b/framework/catalog/dsh/skills/novel-diagnosis/references/dimension-frameworks.md @@ -0,0 +1,171 @@ +# 维度框架:先把问题落进维度,再谈别的 + +来源:; + +两家都是"整体维度框架":不急着看具体段落,先把"写作能力"切成若干个诊断维度,让作者能说出"我缺的是哪一块"。Brooks 的六核是穷尽分桶,福斯特的七侧面是并列视角,合并成一套定位工具:六核管"问题属于哪种能力",七侧面管"作品在哪些侧面之间失衡"。 + +## 原文摘录 + +> "There is no element, no aspect of the storytelling process, that doesn't belong in one of the six buckets. Genre is a subset of concept. Setting is a subset of scene execution. Backstory is a subset of character. Subplot is a subset of structure, and unfolds in context to concept. And so on." +> +> — Larry Brooks, *Story Engineering* (2011), Part 1 + +() + +> "我之所以选择它, 是因为这个论题实在有些含糊, 无法以科学方式加以精确剖析, 而它刚好可以为我们保留最大限度的自由, 因为它意味着, 不但我们能以不同的方式来看待同一部小说, 小说作者也能以不同的方式来看待他自己的作品。有鉴于此, 我一共挑选出了七个侧面来加以探讨: 故事、人物、情节、幻想、预言、模式与节奏。" +> +> — E. M. 福斯特, 《小说面面观》第一讲 绪论 + +() + +## 方法规则 + +### A. 六核分桶:4 元素 + 2 技能 + +Larry Brooks 把"写作能力"切成 6 个互不重叠的桶,让作者精确定位"我缺什么"。6 个桶 = 4 元素 + 2 技能:() + +**4 个基本元素(elemental)——故事是"什么":** + +1. **Concept(核心前提/概念)**——故事的 what if? 种子 +2. **Character(角色)**——故事由谁经历 +3. **Theme(主题)**——故事对现实照亮什么 +4. **Structure(结构)**——故事如何按时间排列 + +**2 个执行技能(execution-driven)——故事怎么"被写出来":** + +5. **Scene Execution(场景执行)**——故事被切成场景后的单元技巧 +6. **Writing Voice(写作声音)**——文字的节奏、语调、风格 + +关键洞察:() + +- 这不是"6 种技巧",是"6 个互不重叠的全分类"——任何写作相关元素都能落到一个桶,否则就是写作盲区。 +- 4 元素是"故事要包含什么",2 技能是"故事如何被执行"。 +- 缺一不可,任何一桶不及格 = 整个故事失败。 +- 这是一个**诊断工具**——你不知道故事哪里出问题,问"这属于 6 桶的哪一桶"就能定位。 + +### B. 七侧面姿态:放弃定义,改为识别侧面 + +面对一个无法被"定义"的复杂对象(小说、艺术形式、品牌、研究领域、生活形态),放弃给它一个本质定义,改为识别它可被"侧面地"分析的若干维度。() + +核心操作: + +1. **承认"无法定义"是常态**——复杂对象太软、太杂、太没有一定之规,强行定义只会扭曲它。 +2. **改为列 N 个侧面(aspect)**——选 5-10 个可独立讨论的维度,每个侧面都是对象"被看到的合法方式"。 +3. **每个侧面要求一种读者/操作者素质**——故事的"好奇心"、情节的"头脑与记忆力"、幻想的"额外付 6 便士"——这种"侧面 + 素质"配对让抽象维度变得可诊断。 +4. **判断好坏**——优秀作品不是"满足所有侧面",而是在这 N 个侧面之间**获得动态平衡**;拙劣作品是某一侧面过强(模式阉割人性)或过弱(只剩时间堆叠)。 +5. **允许侧面之间的"光柱"(如幻想/预言)**——某些侧面不是并列的,而是**横贯**其他侧面的更高阶维度(详见 references/fantasy-prophecy.md)。 + +关键认识:七侧面的"七"不是本体论,是方法论选择。读者完全可以列出五侧面、十侧面,但必须满足"每个侧面有独立素质要求"这一硬条件,否则就是伪分类。() + +### C. 合并后的诊断姿态(两书合并点) + +- **先定位维度,再查病灶**:两家框架都不是评分表,是定位镜。不知道作品哪里出问题时,把症状逐条对照六核之桶与七侧面,判定问题落在哪个或哪几个维度。(;) +- **好坏 = 维度间的动态平衡**:Brooks 说任何一桶不及格整本就失败;福斯特说好作品是侧面之间的动态平衡,拙劣作品是某侧面过强或过弱。两家判法合用:先用六核找到不及格的桶,再用七侧面说清这个桶是怎么失衡的(哪个侧面向哪个方向倒)。(;) +- **维度数目可伸缩,但每个维度必须有独立判断标准**:六桶或七侧面可按作品伸缩,两个维度共用一个判断标准就合并。( 的"七非本体论"立场; 的"互不重叠全分类"立场) + +**冲突标注(都保留)**:Brooks 主张六桶是穷尽全分类——"故事写作过程中没有任何元素不属于这六个桶之一";福斯特明确否认完备性——七个侧面是"我感兴趣的方向",不是"小说的全部"。两条立场都保留:做诊断时用 Brooks 的"一切都能落桶"排查有没有漏掉的盲区,用福斯特的"侧面可伸缩"给特殊作品(章回体、散文体小说、类型文)临时增补侧面。不要把六桶当封闭清单去否定新维度。 + +### 判断标准 + +- 任何一桶不及格 = 整个故事失败() +- 优秀 = 侧面之间动态平衡;拙劣 = 某一侧面过强(模式阉割人性)或过弱(只剩时间堆叠)() +- 维度是诊断镜,不是评分表:不给维度打 1-10 分,不把维度拆成独立任务清单( 作者明示的失败模式) +- 每个侧面要有独立的素质要求/判断标准,否则是伪分类() + +## 操作步骤(维度定位的执行流程) + +合并两家的 E 段步骤( 四步; 五步): + +1. **承认对象复杂、无法一句话定义** + - 完成标准:明确说出"这部作品的问题太杂,强行一句话定性会扭曲它,先分维度看"作为开场。() +2. **介绍维度框架** + - 完成标准:用户能用一句话说"故事写作有 6 大能力 = 4 元素 + 2 技能",并知道小说另有七侧面可看。不要照搬英文,翻译成用户语言;用食物/建筑等类比帮助记忆。() +3. **对具体问题做归类** + - 完成标准:用户的问题/故事被归到 6 桶中的某一桶或多桶。问用户:"你的问题最像下面哪个?"然后给出 6 桶的简短解释。() +4. **识别侧面并为侧面配素质** + - 完成标准:列出至少 5 个独立侧面,每个侧面有"该侧面看到什么,隐藏什么"的说明;至少 3 个侧面配对成功(说明"为什么这种素质是这一侧面必需的")。判停条件:如果发现两个侧面要求同一素质,合并它们。不要"7"硬凑,视对象复杂度伸缩。() +5. **诊断失衡** + - 完成标准:对作品做诊断——"X 的故事侧面过强,人物侧面被阉割"或"X 平衡良好"。失衡的反模式:单侧面极致、其他侧面消失(如詹姆斯的模式阉割,见下文案例与 references/pattern-rhythm.md)。() +6. **给出动态平衡的处方,指向下一层透镜** + - 完成标准:至少 1 条"如何修复失衡"的具体建议。不要给空话(如"加强人物")——给可操作建议(如"加入至少一个圆形人物,因为该侧面目前只有扁平人物")。定位完维度就交给五个透镜(故事/情节、时间/价值、情节/人物、模式/节奏、幻想/预言)查病灶,不在维度层深入细节。(;) + - 判停条件:如果用户继续追问某桶/某侧面的细节,引导到对应透镜文件或专精 skill,不在本层继续。 + +## 案例全文 + +### 案例 1:作者自传——5 部小说按 6 桶全检查() + +- **问题**:作者自己 5 部小说,第一本 *Darkness Bound* 如何做到首稿几乎零修改卖给 NY 大出版社? +- **方法论的使用**:5 部小说都按 6 桶全维度自检:Concept(清晰)+ Character(3 维)+ Theme(隐含)+ Structure(4 箱)+ Scene(mission-driven)+ Voice(干净专业)。 +- **结论**:6 桶没有短板,首稿即可投稿。 +- **结果**:8 周写完 *Darkness Bound*;*Bait and Switch* 被 Publishers Weekly 评为 2004 年度最佳 Mass Market 书。 + +### 案例 2:拒稿诊断——失败模式按桶归类() + +- **问题**:无数被拒稿,共同的失败模式是什么? +- **方法论的使用**:把拒稿原因分类到 6 桶:Concept 不够新(10%)/ Character 太工具人(25%)/ Theme 缺失或说教(15%)/ Structure 错位(30%)/ Scene 散漫(15%)/ Voice 抢戏(5%)。 +- **结论**:6 桶框架是出版商判断"这书值不值得"的标准,不是作者的个人理论。 +- **结果**:用 6 桶预检手稿的作者,拒稿率显著下降。 + +### 案例 3:小说本体的七侧面——框架自身的展开() + +- **问题**:小说太复杂,无法被定义。 +- **方法论的使用**:福斯特列出 7 个侧面(故事/人物/情节/幻想/预言/模式/节奏),每个侧面配对一个读者素质要求。 +- **结论**:整本《小说面面观》即此框架的展开,9 讲对应 7 侧面 + 绪论 + 结论。 +- **结果**:该框架被文学评论广泛采用,"七侧面"成为小说分析的经典入口。 + +### 案例 4:贝内特 托尔斯泰《战争与和平》——单侧面过强 vs 多侧面平衡() + +- **问题**:同样写时间,为什么前者"失于伟大",后者"伟大"? +- **方法论的使用**:贝内特只展开"时间"侧面(后来呢 + 时间生活),托尔斯泰同时展开"时间"和"空间"(空间感"类似音乐的力量")。 +- **结论**:单侧面过强(贝内特)vs 多侧面平衡(托尔斯泰)。 +- **结果**:福斯特借此说明——优秀小说的标志是侧面的动态平衡,不是单一侧面的极致。 + +> 同一对比在时间/价值角度下的全文案例见 references/time-value.md(贝内特的时间生活极致、托尔斯泰的空间感 = 价值生活);在故事/情节角度下的简注见 references/story-plot.md。角度不同,多处保留。 + +### 案例 5:亨利·詹姆斯《使节》——模式压倒其他侧面() + +- **问题**:詹姆斯的小说是模式(沙漏)的胜利,但代价巨大。 +- **方法论的使用**:福斯特用七侧面诊断——模式侧面过强,阉割了人物(类型贫乏)、情节(靠关系设计)、幻想/预言(不谈哲学/信仰)。 +- **结论**:"美如期而至, 只是模样太霸道了些",单侧面的极致牺牲了其他侧面。 +- **结果**:借此福斯特区分"戏剧可以(亚里士多德规训),小说不行"。 + +> 同一作品在"模式付出了什么代价"角度下的全文案例见 references/pattern-rhythm.md(人物类型清单、衣服不脱、病不知名),角度不同,两处都保留。 + +## 常见误区与失败模式 + +- **把 6 桶当成"6 个独立任务"而不是"6 个相互交织的能力"**——实际上 6 桶共同决定故事,任何一桶不及格都毁掉整本。() +- **把 6 桶当成"必须 1-10 打分"的形式化**——它们是诊断维度,不是评分表。() +- **亚里士多德式套用**——把"开端—发展—高潮—结局"硬套到所有作品,把小说写成戏剧(戏剧化的小说)。() +- **单侧面极致**——只追求"故事好看"或"模式精美"或"人物深刻",牺牲其他侧面(如詹姆斯的模式压倒人性)。() +- **七侧面被当成"小说本体论"**——误以为福斯特给出了小说的完整本体,而非"我感兴趣的七个方向"。() + +## 边界与盲点 + +不适用场景: + +- 用户的问题已经定位到具体能力(例如"我的 Concept 不够好")——应使用对应专精 skill(concept-design、character-design、story-structure 等)。() +- 非小说写作(诗歌/学术论文/技术文档)——这是小说写作框架。() +- 用户在问"如何写一个 hook"/"如何写一个场景"——用具体创作 skill。() +- 单一因果问题("为什么 X 会发生")、纯事实查询、有明确定义边界的对象(如"什么是 HTTPS 协议")、时间紧迫/决策需要即时答案——七侧面分析需要深度思考,决策可读 references/time-value.md 快速判断。() + +作者盲点(两书都保留): + +- Brooks,2011 年传统出版视角:默认目标 = 卖 NY 出版社或好莱坞;不直接适配自出版、Kindle 时代、有声书等。6 桶未覆盖营销/读者画像/平台策略等出版商业能力。6 桶假设单一主角;群像/POV 切换小说/不可靠叙述者,6 桶需调整。() +- 福斯特,七侧面的完备性:福斯特没论证为什么是这七个,也不是六个、八个;这是"我感兴趣的方向",不是"小说的全部"。() +- 福斯特,白英美欧陆男性中心的视角:引用的作家几乎全是西方男性;19 世纪以来被边缘化的女性作家、非西方作家未被充分纳入。() +- 福斯特,现代主义巅峰期的局限:1927 年的视角,看不到 1960s 后的拉美魔幻现实主义、后现代拼贴、亚非作家群体。() + +## 易混的邻近方法论 + +- **K.M. Weiland 的"Story Structure"5 桶**:5 桶分类(Structure/Character/Scene/Dialogue/Word Choice)重叠度高,但少 Concept 和 Theme。() +- **Save the Cat 的 15 节拍**:是 Structure 一桶的细化,不是 6 桶的替代。() +- **"7 个故事原型"(Christopher Booker)**:主题原型,不构成 6 桶分类。() +- **vs MECE 分类法**:MECE 是"互不重叠,合起来穷尽",追求完备;七侧面是"列多个角度,允许交叠",追求丰富。() +- **vs SWOT / 5W1H / 波特五力**:这些是"分析工具",七侧面是"分析姿态";后者更反思,不假装客观。() +- **vs 思维导图/心智图**:七侧面是**有结构约束**(每个侧面有素质要求)的视角,不是发散联想。() + +## 中文落地 + +- 六桶名字直接中文化使用:概念、人物、主题、结构、场景执行、语言声音。中文小说诊断时,"Writing Voice"一桶要额外纳入汉语特有的语感问题(文白夹杂、翻译腔、网文口癖),见 prose-craft 的语言规则,本包不展开。 +- 七侧面用于中文作品时,"模式与节奏"侧面有本土资源可对:章回小说的对偶回目、章法就是现成的模式/节奏现象,详见 references/pattern-rhythm.md 的"中文适配"节。 +- 中文长篇(尤其网文连载)常是"人物"与"结构"两桶最易不及格:人物工具人化(追更压力下人物让位于桥段)、结构错位(上架节点代替情节节点)。诊断时优先对照这两桶。 diff --git a/framework/catalog/dsh/skills/novel-diagnosis/references/fantasy-prophecy.md b/framework/catalog/dsh/skills/novel-diagnosis/references/fantasy-prophecy.md new file mode 100644 index 0000000..47a50e3 --- /dev/null +++ b/framework/catalog/dsh/skills/novel-diagnosis/references/fantasy-prophecy.md @@ -0,0 +1,135 @@ +# 神异层透镜:戏耍还是歌唱——幻想与预言孪生光柱 + +来源: + +这是福斯特对作品神异层的诊断透镜。幻想与预言不是第八、第九个侧面,而是横贯故事、人物、情节之上的"光柱"——更高阶的维度,彼此孪生。两者都要求读者"额外付 6 便士"(接受神异、接受非理性),但姿态不同:幻想是戏耍,预言是歌唱。 + +## 原文摘录 + +> "我所说的, 是横贯它们的东西, 就像一道光柱 …… 在某一处与它们关联密切, 耐心地照亮它们所有的问题, 而在另一处又径直越过或贯穿它们, 就像它们根本不存在一样。我们应该给这束光起两个名字: 幻想和预言。" + +> "它要求我们给予某种额外的东西。它要求我们能够自我调适, 不同于艺术品所要求的调试, 这是另一种额外的调试能力。" + +> "它的方式方法乃至题材都是奇特的, 就像主展之外的附加小展, 你得在入场费之外额外再付六便士才能看得到。" + +> "我们所说的'预言', 是一种口吻, 一种语调。 …… 重要的是作者声音里的语调, 是他的歌谣。" + +> — E. M. 福斯特, 《小说面面观》第六讲 / 第七讲 + +() + +## 方法规则 + +幻想与预言是横贯故事/人物/情节之上的"光柱",**不是新的侧面,是更高阶的维度**,彼此孪生。两者对读者的要求不同,但都是"额外付 6 便士"——接受神异、接受非理性。() + +核心操作: + +1. **识别"光柱"的存在**——一部作品里,如果有某种"横贯"故事/人物/情节的东西,让你感觉"作品在自己生长,似乎在说我无法控制的事",那就有光柱。 +2. **区分幻想 vs 预言**: + - **幻想(Fantasy)**:召唤"低空/浅水/小丘间的精灵"(法翁/德律阿德斯/潘神/赫耳墨斯),是神话的低端,带着"随意的即兴感"。例:《项狄传》《朱莱卡·多卜森》《魔笛》《尤利西斯》。 + - **预言(Prophecy)**:召唤"彼方的神灵"(路西法/希腊/印度的超越),直面"融合与统一",是"歌者"而非"戏耍者"。例:陀思妥耶夫斯基《卡拉马佐夫兄弟》、梅尔维尔《白鲸记》、劳伦斯《恋爱中的女人》、艾米莉·勃朗特《呼啸山庄》。 +3. **幻想的检验**:它是否"渗透在世界的每一个角落却不能渗入'掌控世界的力量'"?是否有"随意的即兴感"? +4. **预言的检验**:它是否"像一首歌或一种声音"?是否有"粗糙的表面"(具体日常细节)之上某种"光洁柔润"的东西? +5. **6 便士测试**——检测一部作品是否召唤出幻想/预言侧面的**成本测试**:它是否要求读者在"接受常理"之外再多付一份"接受神异/接受非理性"的成本? + +关键认识:幻想和预言是孪生但不等同。幻想更像游戏(允许暂时"假装的非理性"),预言更像皈依(要求谦逊和搁置幽默感)。**不付 6 便士不代表读者无想象力,只代表他不愿响应这一要求**(例:阿斯奎斯对《淑女变狐狸》的反应)。() + +### 判断标准 + +- 检测"光柱"是否存在:标出至少 1 处作品里"横贯其他元素、似乎在说自己生长方向"的现象;如果没有,作品没有进入幻想/预言,走常规分析。( 执行步骤) +- 区分幻想 vs 预言:问"作者在戏耍(幻想)还是在歌唱(预言)?"戏耍 → 召唤"低空精灵",接受"神异作为游戏";歌唱 → 召唤"彼方神灵",接受"神异作为皈依"。( 执行步骤) +- 6 便士测试:明确说出"这部作品要求读者额外付出 X 种素质"(如"接受混乱"、"接受死亡在文本外的延续"、"接受动物有灵魂")。判停条件:如果用户表示"我无法付出 X",尊重选择,不强推。( 执行步骤) +- 检查谦逊与幽默感的暂时搁置(预言面):评估读者是否愿意"暂时不嘲笑 X";如不愿意,预言无效。福斯特明示:"幽默感,在这里很不合时宜,这种有教养者的可贵的附加品质必须被暂时搁置一旁"。( 执行步骤) +- 给出"双向"判断:明确说"作品召唤是否合理(是)+ 读者选择不响应是否合理(是)"——双方都无错。不要再做"你必须读懂它"的教育姿态。( 执行步骤) + +## 操作步骤(执行流程) + +来源: 执行段五步。 + +1. **检测"光柱"是否存在** + - 完成标准:标出至少 1 处作品里"横贯其他元素、似乎在说自己生长方向"的现象。 + - 如果没有,作品没有进入幻想/预言,走常规分析。 +2. **区分幻想 vs 预言** + - 完成标准:问"作者在戏耍(幻想)还是在歌唱(预言)?" + - 戏耍 → 召唤"低空精灵",接受"神异作为游戏";歌唱 → 召唤"彼方神灵",接受"神异作为皈依"。 +3. **应用 6 便士测试** + - 完成标准:明确说出"这部作品要求读者额外付出 X 种素质"(如"接受混乱"、"接受死亡在文本外的延续"、"接受动物有灵魂")。 + - 判停条件:如果用户表示"我无法付出 X",尊重选择,不强推。 +4. **检查谦逊与幽默感的暂时搁置(预言面)** + - 完成标准:评估读者是否愿意"暂时不嘲笑 X";如不愿意,预言无效。 + - 福斯特明示:"幽默感,在这里很不合时宜,这种有教养者的可贵的附加品质必须被暂时搁置一旁"。 +5. **给出"双向"判断** + - 完成标准:明确说"作品召唤是否合理(是)+ 读者选择不响应是否合理(是)"——双方都无错。 + - 不要再做"你必须读懂它"的教育姿态。 + +## 案例全文 + +### 案例 1:斯泰恩《项狄传》——幻想的典型() + +- **问题**:《项狄传》(1759—1767)没有超自然现象,为什么是"幻想"代表? +- **方法论的使用**:福斯特诊断——"混乱神"已经近乎人格化,整个宏大故事中"人物做得越多,得到的就越少 …… 事实趋向邪恶,不是导向未来,而是纠缠于过去"。这是"幻想"对神异的最广义使用——接受"现实可能彻底不连贯"这一前提。 +- **结论**:幻想的本质是"接受神异",不必非有精灵/天使;接受"混乱"本身就是接受神异。 +- **结果**:借此福斯特把"幻想"从"奇幻类型"扩展到"接受非理性的姿态"。 + +> 同一作品(《项狄传》)在圆桌论比较角度下的案例见 references/round-table.md 案例 1(与伍尔夫《墙上的斑点》共享同一束幻想之光),角度不同,两处都保留。 + +### 案例 2:梅尔维尔《白鲸记》——预言的代表() + +- **问题**:《白鲸记》表面是捕鲸传奇,为什么福斯特说它"难读而且无比重要"? +- **方法论的使用**:福斯特诊断——一旦捕捉到其中"飘荡的歌声",就能看到"那音韵铿锵,却断断续续,没有清晰的题解,也绝对没有向后触及怜悯与爱的宇宙,没有'二位,我做了个好梦'"。这是预言的特征:歌,不是戏。 +- **结论**:预言的核心是"语调(tone)",不是题材。梅尔维尔"歌唱"了"恶"的概念,这是小说中"对恶"最强大的处理。 +- **结果**:借此福斯特把"预言"从"宗教预言"扩展到"作者的歌唱"。 + +### 案例 3:阿斯奎斯 vs《淑女变狐狸》——6 便士测试的失败() + +- **问题**:阿斯奎斯(英国前首相)拒绝接受《淑女变狐狸》变不回淑女。 +- **方法论的使用**:福斯特诊断——阿斯奎斯"是一位真诚的文学爱好者,但他并不愿意支付额外的六个便士,又毋宁说,他愿意支付,只是期望在最后能拿回来"。 +- **结论**:拒绝付 6 便士是合法的(阿斯奎斯无错),但书因此"让他觉得不舒服"——书的召唤没生效。 +- **结果**:借此福斯特说明,6 便士测试是"双向"的——作品要求付,读者选择付或不付,双方都不必"错"。 + +## 常见误区与失败模式 + +- **约翰逊博士式"判定怪书不能流传"**——"任何剑走偏锋的东西都不会长久,比如《项狄传》,就没能流传下来!"——用惯例丈量神异。() +- **拒绝付 6 便士但假装喜欢**——阿斯奎斯式,"期望在最后能拿回来"。() +- **幻想/预言的作者自欺**——格特鲁德·斯坦因式"想砸碎时钟",但"她的失败却很有启发意义"。() +- **神秘主义滥用**——把"神异"当成万能解释,不承认只是修辞。() + +## 边界与盲点 + +不适用场景:() + +- **自然主义题材**——没有神异,6 便士测试不适用。 +- **完全日常的写作**——普通新闻、报告、菜谱,没有"光柱"。 +- **儿童文学的常规奇幻**——哈利波特式已经规则化,不需要"付 6 便士"诊断。 +- **学术写作**——要求清晰、理性,不召唤神异。 + +作者盲点:() + +- **1927 年的视角**——没看到 1960s 后的魔幻现实主义(马尔克斯)、新浪潮电影(费里尼、林奇)、后现代拼贴(品钦、巴塞尔姆)。 +- **白英美欧陆男性中心的视角**——引用的作家几乎全是西方男性;非西方的"神异"传统(中国志怪、日本怪谈、阿拉伯神话)未被充分讨论。 +- **对"接受神异"的诊断带有 20 世纪初的阶级偏见**——"高尔夫球手"和"公交车司机"是有教养者 vs 普通人的隐喻;现代的"接受神异"门槛因大众文化普及而部分降低。 + +## 易混的邻近方法论 + +- **vs 类型奇幻(Fantasy Genre)**——类型奇幻是规则化(有自己的"非理性规则"),幻想是接受神异的姿态。() +- **vs 宗教预言(Religious Prophecy)**——福斯特明示"预言"不是宗教的,是"作者声音里的语调"。() +- **vs 神秘主义(Mysticism)**——神秘主义要求皈依,幻想/预言是文学接受;两者姿态相似但目标不同。() +- **与 seven-aspects 的区别**:幻想/预言是**横贯其他侧面的光柱**(更高阶),七侧面是**并列的 N 个侧面**。 +- **与 quack-scholar-check 的区别**:幻想/预言是**作品层面的神异**,伪学者自检是**评论者层面的自检**。 +- **与 mystification 的区别**:蒙蔽是**作者隐藏技巧**,幻想/预言是**作者召唤神异**。 + +## 中文转述:志怪、神魔、仙侠传统与适用边界 + +**[中文适配]** + +福斯特以英国小说的神异传统立论,中文写作换志怪、神魔、仙侠谱系看接受门槛与姿态: + +- **门槛不在"信不信有妖怪"**:志怪有"记异为实"的传统,神怪以事实身份进入叙述,中文读者接受神异几乎不需要铺垫;真正的门槛是**神怪是否通人情**——聊斋传统写鬼狐而有人的情感,只堆奇观和设定的会被拒绝。 +- **幻想面对应《西游记》式的戏谑玩闹、志怪式的随手即兴**:把不连贯当游戏,不必要求读者严肃。 +- **预言面对应语调"歌唱"的庄严之作**:天问式诘问、谶语式预言、《红楼梦》结尾"白茫茫大地真干净"式的神话肃穆;读者付的是读史而叹式的庄重,**门槛在意愿,不在能力**。 +- **适用边界**: + - 规则化的类型奇幻(体系化修仙仙侠、系统流、无限流)自带接受规则,读者按规则付费,**不需要六便士测试**;对这些作品乱用六便士测试是误诊。 + - 无神异内容的自然主义现实题材**不用本透镜**。 + - 六便士测试真正适用的是:在常理叙事里突然引入神异、且要求读者额外接受一份"非理性"的作品(志怪笔法写现实、寓言式神魔、谶语预言体)。 + +中文落地诊断流程:走六便士测试,列出作品要求读者额外接受什么 → 判定是幻想面(戏谑玩闹、随手即兴)还是预言面(语调"歌唱"的庄严之作)→ 再按中文志怪、神魔、仙侠谱系看其接受姿态(神怪是否通人情、门槛在意愿还是能力)→ 给出双向判断(作品召唤合法,读者选择不付也合法)。 diff --git a/framework/catalog/dsh/skills/novel-diagnosis/references/pattern-rhythm.md b/framework/catalog/dsh/skills/novel-diagnosis/references/pattern-rhythm.md new file mode 100644 index 0000000..9d064fb --- /dev/null +++ b/framework/catalog/dsh/skills/novel-diagnosis/references/pattern-rhythm.md @@ -0,0 +1,133 @@ +# 形式层透镜:看画还是听乐——模式 vs 节奏 + +来源: + +这是福斯特对作品形式感的二分诊断:模式(Pattern,借自绘画)是完整可感的几何结构,处处存在;节奏(Rhythm,借自音乐)是重复与变化的结合,不必处处存在,却能从内部黏合整体。模式是"画",节奏是"乐"。小说的血肉(人物、情节、幻想)适合节奏,多过模式。 + +## 原文摘录 + +> "首先要从绘画艺术中借一个词, 称之为'模式'。然后再从音乐艺术中借一个词, 称之为'节奏'。 …… 有时候并非如此。当它不那么完整时, 我会称之为'节奏'。" + +> "模式主要来源于情节, 就像云中的一道光, 二者始终相伴, 即便到最后云消雾散, 散光依然是看得见的。" + +> "小说中的简单节奏问题, 如下阐述应该很充分了: 它或许可以定义为'重复与变化的结合'。" + +> — E. M. 福斯特, 《小说面面观》第八讲 + +() + +## 方法规则 + +小说审美侧面的**二分法**。借自绘画(模式)和音乐(节奏),用来识别作品形式感的两种不同形态。() + +核心操作: + +1. **模式(Pattern)= 完整可感的几何结构,处处存在**: + - 整本书可被一个几何/视觉形象概括(沙漏、大循环、大教堂的放射线条、普洛克路斯忒斯之床) + - 故事从一处出发经一处回到原点 + - 完整统一,处处存在 + - 适合承载美感的明确表达(亨利·詹姆斯《使节》、法朗士《泰伊丝》、卢伯克《罗马风情画》) +2. **节奏(Rhythm)= 重复与变化的结合,不必处处存在**: + - 重复的元素(主题/意象/旋律)在每次出现时携带新意义 + - 拥有自己的生命,与听众和创造者的生命都无关 + - 随盈缺带来惊喜,能在书内部黏合散落的事件 + - 适合承载不必处处存在但能黏合整体的作品(普鲁斯特《追忆似水年华》的凡德伊小乐句、托尔斯泰《战争与和平》的"宏大和弦") +3. **节奏的检验公式**: + - 重复之间是否有变化? + - 那种变化是否能调动"我们脑海中记忆的美化"? +4. **模式的代价**——福斯特明示:"美如期而至,只是模样太霸道了些"——戏剧可以(拉辛),小说不行(因为小说承载了"人性的肥满内容")。模式会"阉割"人物类型、情节、幻想/预言。 +5. **节奏的失败**——纯重复(僵化成符号)像"高尔斯华绥的西班牙猎犬约翰"绊人;梅瑞狄斯的樱花树/小艇"只重现不发展",沦为"标语条幅"。 + +关键认识:模式 vs 节奏不是好坏,是**不同形式感**。模式是"画",节奏是"乐"。但小说的血肉(人物、情节、幻想)适合节奏,不适合模式。() + +### 判断标准 + +- 诊断作品是"模式型"还是"节奏型":至少给出 1 个"几何形象"(沙漏/大循环/大教堂等)或 1 个"重复元素"(乐句/主题/意象);两者都不存在 → 形式感弱,走其它分析。( 执行步骤) +- 模式型评估代价:列出"模式阉割了什么"(人物类型、情节、幻想/预言等);被阉割的是否是你最重要的部分?是 → 模式不合适;否 → 模式可接受。( 执行步骤) +- 节奏型评估节拍:标出至少 1 个"重复 + 变化"的元素;重复是否每次都带来新意?否则节奏就死了(像高尔斯华绥的西班牙猎犬约翰)。( 执行步骤) +- 失衡方向:模式过强(牺牲人性)/ 节奏过弱(无内在节拍)/ 平衡良好。反模式:模式过强 → 普洛克路斯忒斯之床;节奏过弱 → 流水账。( 执行步骤) + +## 操作步骤(执行流程) + +来源: 执行段五步。 + +1. **诊断作品是"模式型"还是"节奏型"** + - 完成标准:至少给出 1 个"几何形象"(沙漏/大循环/大教堂等)或 1 个"重复元素"(乐句/主题/意象)。 + - 判停条件:如果两者都不存在,形式感弱,走其它分析。 +2. **对"模式型"作品评估代价** + - 完成标准:列出"模式阉割了什么"——人物类型、情节、幻想/预言等。 + - 评估:被阉割的是否是你最重要的部分?是 → 模式不合适;否 → 模式可接受。 +3. **对"节奏型"作品评估节拍** + - 完成标准:标出至少 1 个"重复 + 变化"的元素(如普鲁斯特的小乐句,或托尔斯泰的空间和弦)。 + - 评估:重复是否每次都带来新意?否则节奏就死了(像高尔斯华绥的西班牙猎犬约翰)。 +4. **诊断失衡方向** + - 完成标准:明确说"模式过强(牺牲人性)/ 节奏过弱(无内在节拍)/ 平衡良好"。 + - 反模式:模式过强 → 普洛克路斯忒斯之床;节奏过弱 → 流水账。 +5. **给出修复建议** + - 完成标准:至少 1 条具体修改(如"加入一个'小乐句'式重复元素,让散落的事件黏合"或"放宽模式的完美,让人物多面性")。 + - 不要空话(如"加强节奏")——给可操作修改。 + +## 案例全文 + +### 案例 1:法朗士《泰伊丝》——沙漏形模式的首要范例() + +- **问题**:一本沙漏形的书是什么样的? +- **方法论的使用**:福斯特诊断——帕弗纽斯(沙漠禁欲者)和泰伊丝(亚历山大港交际花)两人"相向而行、擦肩而过、交换位置,如数学般精准"。故事是"事件依照时间顺序",情节是"因果",**模式是"沙漏"**——中心相遇,两端交换。 +- **结论**:模式激发美感,模式来自情节,模式能引导我们"以整体的眼光看待这本书"。 +- **结果**:借此福斯特把"沙漏形"作为模式分析的标准入口。 + +### 案例 2:普鲁斯特《追忆似水年华》——节奏的样本() + +- **问题**:《追忆》"混乱无序,结构错乱扭曲,没有外部框架",为什么它仍然是一部完整的作品? +- **方法论的使用**:福斯特诊断——因为它有节奏,凡德伊小乐句"贯穿全书,一次又一次出现,就像一种回声,一段记忆"。这个乐句"有自己的生命,跟它的听众的生命无关,跟创造它的人的生命也无关",**"几乎就是一个独立的角色"**。 +- **结论**:节奏作为"重复与变化的结合",让没有外部框架的作品在内部黏合。 +- **结果**:借此福斯特把"节奏"作为普鲁斯特这种"无框架但完整"作品的形式感来源。 + +### 案例 3:亨利·詹姆斯《使节》——模式压倒人性() + +- **问题**:沙漏形模式的胜利,代价是什么? +- **方法论的使用**:福斯特诊断——詹姆斯"人物类型清单非常短"(观察者、平庸局外人、好心配角、美好女主角、恶棍、年轻艺术家),人物线条简单(只寥寥几笔),衣服不脱,病不知名,收入不提,仆人安静。 +- **结论**:模式为美付出的代价是阉割——"只有亨利·詹姆斯的人物才适合亨利·詹姆斯的小说,尽管他们都是不死的"。 +- **结果**:借此福斯特把"模式"从"美学胜利"翻转为"美学代价"。 + +> 同一作品在七侧面动态平衡角度下的案例见 references/dimension-frameworks.md 案例 5(模式侧面过强阉割人物/情节/幻想预言),角度不同,两处都保留。 + +## 常见误区与失败模式 + +- **模式阉割人性**——亨利·詹姆斯的"普洛克路斯忒斯之床"(詹姆斯式模式压倒人性)。() +- **节奏僵化为符号**——梅瑞狄斯的樱花树/小艇"只重现不发展"(梅瑞狄斯式节奏僵化为符号)。() +- **节拍重复绊脚**——高尔斯华绥的西班牙猎犬约翰"横在我们脚下"(高尔斯华绥式节拍重复绊脚)。() +- **追求完整闭环到伤害人性**——模式强求一律,"普洛克路斯忒斯之床"是其极端。() + +## 边界与盲点 + +不适用场景:() + +- **完全没形式感的对象**——如纯流水账日记,没有可识别的模式/节奏。 +- **真正以"无结构"为目标的实验艺术**——故意拒绝形式,不该被分析。 +- **戏剧/音乐本身**——戏剧本来就该有"模式"(亚里士多德),音乐本来就该有"节奏";这里的"模式 vs 节奏"是小说分析框架。 +- **纯功能对象**——如工具、家具,不需要"美感形式感"。 + +作者盲点:() + +- **小说 / 戏剧的形式感二分过于干净**——实际上现代戏剧(布莱希特、贝克特)早就拒绝亚里士多德模式,与福斯特的论断冲突。 +- **西方文学中心的视角**——引用的几乎全是西方小说;中国章回小说(用对仗、回目、章法作为"节奏")、日本物语(用"调"作为模式)未被充分讨论。 +- **1927 年的视角**——没看到 60 年代后的后现代拼贴、装置艺术、数字媒体的"形式感"。 + +## 易混的邻近方法论 + +- **vs 戏剧结构(三幕剧/五幕剧)**——戏剧结构是"模式"的一种,不是"节奏"。() +- **vs 蒙太奇(Montage)**——蒙太奇是"通过剪辑创造意义",节奏是"重复元素携带新意"。() +- **vs 三段式/起承转合**——这些是"模式"的具体形态,不是"节奏"。() +- **与 expansion-vs-completion 的区别**:模式/节奏是**形式感的类型**,扩展/完成是**作品终点的姿态**;前者管整体,后者管结尾。 +- **与 fantasy-prophecy-twin 的区别**:模式/节奏是**形式层**,幻想/预言是**神异层**;模式强的作品通常不召唤神异(因为已经"完整")。 +- **与"结构主义(Structuralism)"的区别**:结构主义是"找底层结构",模式是"看可感的形式",节奏是"听内在的节拍"。 + +## 中文适配 + +**[中文适配]**: + +- 章回小说的**对偶回目、开篇收场诗、章法是现成的模式资源**。回目本身就是一组组对称的几何期待,章法(起承转合、首尾呼应、草蛇灰线)让整本书可被一个结构形象概括——这就是福斯特说的"模式"。 +- **一个意象或语句每次重现都携带变化,是节奏式手法**。《红楼梦》里反复出现而每次意义不同的意象、判词、戏文,就是凡德伊小乐句式的"重复与变化的结合"。 +- **模式与节奏可以同书并用**:章法管模式(外部框架),意象重现管节奏(内部黏合),二者不冲突。 +- 中文落地诊断时:把"模式"问题问成"全书能不能用一个几何形象/章法概括",把"节奏"问题问成"有没有重复出现的意象/语句,每次是否带来新意"。警惕回目、章法把人物"阉割"成类型(模式过强),也警惕意象沦为只重现不发展的标语(节奏僵化)。 diff --git a/framework/catalog/dsh/skills/novel-diagnosis/references/plot-character.md b/framework/catalog/dsh/skills/novel-diagnosis/references/plot-character.md new file mode 100644 index 0000000..e6a1617 --- /dev/null +++ b/framework/catalog/dsh/skills/novel-diagnosis/references/plot-character.md @@ -0,0 +1,125 @@ +# 张力层透镜:情节和人物谁赢——情节与人物的拉锯战 + +来源: + +这是福斯特对"情节 vs 人物"张力的元模型诊断:情节要"因果收尾",人物要"自由发展",二者必然冲突。福斯特判断小说"虎头蛇尾"是结构必然,因为"情节需要收尾打结"。拉锯不是缺陷,是结构必然;关键不是消灭拉锯,是主动选择拉锯的解决方式。 + +## 原文摘录 + +> "情节是小说中偏于逻辑理性的一面, 它要求有悬念, 但悬念稍后便会解开; 读者可以在未知的世界里寻觅求索, 可小说作者不会迷茫。他游刃有余, 泰然自若, 居高临下总揽全局, 在这里投下一柱光, 那里藏起一个秘密 …… 不断与身为'人口贩子'的自己辩驳协商, 以期达成最佳效果。" + +> "几乎所有小说都有点儿虎头蛇尾。这是因为情节需要收尾打结 …… 若不是还有死亡与婚姻, 我真不知道大多数小说作者要怎么收场。" + +> "小说作者不得不亲力亲为, 劳心劳力, 好按时完成工作。他假装所有人物都围绕自己行动。他不断提起他们的名字, 不断动用引号让他们发声。可他们不是消失了, 就是死了。" + +> — E. M. 福斯特, 《小说面面观》第五讲 情节 + +() + +## 方法规则 + +关于情节-人物张力的**元模型**:情节要求"因果收尾",人物要求"自由发展",二者必然冲突。福斯特的诊断:小说"虎头蛇尾"是结构必然,因为"情节需要收尾打结"。() + +核心操作: + +1. **承认拉锯是结构必然**——任何"逻辑结构 + 自由参与者"的项目都面临这个张力。情节(逻辑)要收尾,人物(自由)要发展,二者必然冲突。 +2. **三种典型处理**: + - **哈代式**(人物为情节牺牲):命运凌驾人物,人物被"耗尽生命力,变得干瘪单薄"。**失败**。 + - **梅瑞狄斯式**(情节胜出):让人物暂时让步,留下"言犹未尽"的优雅。**部分成功**。 + - **反情节式(《伪币制造者》)**(取消单一主线):接受混乱,让"逻辑片段"并列。**另一种成功**。 +3. **虎头蛇尾的诊断**——多数小说在收尾处"人物消失了"或"人物死了"。福斯特明示:"若不是还有死亡与婚姻,我真不知道大多数小说作者要怎么收场"。 +4. **"情节 vs 人物"的检验**: + - 哪一方胜出?胜出的代价是什么? + - 胜出方是否阉割了对方(如哈代式让人物失去"人之为生灵所做出的努力")? +5. **"我假装所有人物都围绕自己行动"**——小说作者亲口承认这是"假装",因此需要主动决定"假装到何种程度"。 + +关键认识:拉锯不是缺陷,是结构必然。**关键不是"消灭拉锯",是"主动选择拉锯的解决方式"**。哈代式(人物牺牲)是合法的失败,梅瑞狄斯式(情节胜出)是合法的优雅,反情节(接受混乱)是合法的另一种选择。() + +### 判断标准 + +- 收尾处"人物死了/消失了"是情节压倒人物的征兆(关注"收尾"和"开头")。( 执行步骤) +- 三种解决方式的代价:选梅瑞狄斯式,人物被节制;选哈代式,人物被阉割;选反情节,读者可能困惑。( 执行步骤) +- 对策:对哈代式,加 1 个"圆形人物"摆脱扁平;对梅瑞狄斯式,加 1 个"言犹未尽"的桥段;对反情节,加 1 个"主线暗示"。( 执行步骤) + +## 操作步骤(执行流程) + +来源: 执行段五步。 + +1. **承认拉锯是结构必然** + - 完成标准:明确说出"任何'逻辑结构 + 自由参与者'的项目都有这个张力,关键不是消灭它,是选择解决方式"。 +2. **诊断拉锯的方向** + - 完成标准:至少标出 1 处"逻辑压倒自由"或"自由压倒逻辑"的具体征兆。 + - 提示:关注"收尾"和"开头"——收尾处"人物死了/消失了"是情节压倒人物的征兆。 +3. **选择拉锯的解决方式** + - 完成标准:明确说"我选哈代式(失败样本)/ 梅瑞狄斯式(节制胜出)/ 反情节(取消问题)"。 + - 理由模板:"因为 X 是 [类型/规模/目的],所以 [方式] 更合适"。 +4. **评估胜出的代价** + - 完成标准:明确说"如果我选梅瑞狄斯式,人物被节制;如果我选哈代式,人物被阉割;如果我选反情节,读者可能困惑"。 + - 给出对策:对哈代式,加 1 个"圆形人物"摆脱扁平;对梅瑞狄斯式,加 1 个"言犹未尽"的桥段;对反情节,加 1 个"主线暗示"。 +5. **设计具体修改** + - 完成标准:至少 1 条具体修改(如"在 X 段让人物做出违背情节的举动,显示自由"或"在收尾处加入'言犹未尽'的桥段")。 + - 不要空话(如"让情节更节制")——给可操作修改。 + +## 案例全文 + +### 案例 1:哈代《列王》《无名的裘德》——拉锯失败的样本() + +- **问题**:哈代是伟大的诗人,但为什么"小说只是审视,并不会发声歌唱"? +- **方法论的使用**:福斯特诊断——哈代"在架构事件时更着重的是因果关系,情节是他的设计图,人物必须服从设计图的要求"。在《无名的裘德》中,"命运的悲剧之中,始终有某个生死攸关的问题不曾得到解答,甚至没能清晰地呈现 …… 人物被迫为情节做出了太多牺牲,以至于他们被耗尽了生命力,变得干瘪单薄"。 +- **结论**:哈代式是"拉锯失败"的范本——情节压倒人物。 +- **结果**:借此福斯特说明,"命运凌驾于我们头上,而非命运借我们之手运转"是哈代小说的根本缺陷。 + +> 哈代"命运凌驾人物"在圆桌论跨时代比较角度下的案例( 司各特《威弗莱》,跨 89 年识别同一失败模式)见 references/round-table.md 案例 3,角度不同,两处都保留。 + +### 案例 2:梅瑞狄斯《利己主义者》——拉锯节制() + +- **问题**:梅瑞狄斯是"英国小说诞生以来最出色的情节设计师",但他的人物呢? +- **方法论的使用**:福斯特诊断——梅瑞狄斯"凭借他精准良好的分寸感,令情节成功胜出"。在《利己主义者》中,雷蒂西亚·黛尔的"情感冷却过程是一定要瞒着我们的",这是情节对人物的暂时让步,但让步节制,留下"言犹未尽"。 +- **结论**:梅瑞狄斯式是"拉锯节制"的范本——情节胜出但节制。 +- **结果**:借此福斯特说明,拉锯中"哪方胜出 + 胜出节制"是写作的高级技巧。 + +> 同一人物(雷蒂西亚·黛尔)在情节设计角度下的案例见 references/story-plot.md 案例 2(心境转变隐藏作为情节设计典范),角度不同,两处都保留。 + +### 案例 3:纪德《伪币制造者》——反情节的样本() + +- **问题**:拉锯可以"取消"吗? +- **方法论的使用**:福斯特诊断——纪德"将旧新两套体系并置",让"逻辑片段"并列,没有"一个'主题'",而是"生活的切片",甚至"手起刀落拦腰截断"。这是拉锯的"取消":取消单一情节主线,让多线并列。 +- **结论**:反情节是"拉锯的另一种解决"——接受混乱,不再要求情节胜出或人物胜出。 +- **结果**:借此福斯特说明,拉锯不止两种解决,还有第三种:**取消问题本身**。 + +## 常见误区与失败模式 + +- **哈代式(命运凌驾人物)**——情节压倒人物,人物被耗尽。() +- **戏剧化的小说(亚里士多德三步骤)**——把小说写成戏剧,强行收尾。() +- **多数小说的"虎头蛇尾"**——情节需要收尾,人物消失或死。() +- **追求完整闭环到伤害自由**——模式强求一律,普洛克路斯忒斯之床。() + +## 边界与盲点 + +不适用场景:() + +- **纯逻辑对象(无自由参与者)**——如数学公式、算法,没有"拉锯"。 +- **纯自由对象(无逻辑结构)**——如纯艺术装置、纯抒情诗,没有"拉锯"。 +- **纯事务性事务**——如预约、报销,不需要张力诊断。 +- **极端短篇**——几条推文,没有足够空间让拉锯显现。 + +作者盲点:() + +- **现代主义巅峰期的视角**——1927 年;当时还没有"交互叙事"(游戏)中的"玩家自由 vs 设计师情节"拉锯作为合法形式。 +- **西方文学中心的视角**——中国章回小说用"章法"作为"拉锯的解决",福斯特未充分讨论。 +- **对"反情节"的诊断有限**——纪德是少数样本,后现代文学(品钦、巴塞尔姆)的"反情节"是更激进的形式。 + +## 易混的邻近方法论 + +- **vs 戏剧冲突(Dramatic Conflict)**——戏剧冲突是"人物 vs 人物 / 人物 vs 命运",拉锯是"情节(逻辑)vs 人物(自由)";前者是戏剧内部张力,后者是小说/虚构的整体张力。() +- **vs 自由 vs 控制(Freedom vs Control)**——这是管理学概念,拉锯是文学/叙事学概念;前者管组织,后者管作品。() +- **vs 主题先行 vs 人物先行(Theme-first vs Character-first)**——这是写作教学概念,拉锯是更基础的元模型。() +- **与 story-vs-plot 的区别**:故事/情节是**单方面的诊断**,情节-人物拉锯是**双方面的张力诊断**。 +- **与 flat-vs-round-character 的区别**:拉锯是**多人物 vs 情节结构**的张力,扁/圆是**单人物**的分类。 +- **与 mystification 的区别**:蒙蔽是**作者姿态**,拉锯是**结构张力**;前者管"自然不自然",后者管"哪种要素占主导"。 + +## 中文落地 + +- 福斯特没讨论的中文资源:章回小说用"章法"作为拉锯的一种解决——分回的节拍承担了情节的收束,人物在回目之间流动,既服从章法又保留单回的鲜活。诊断章回体作品时,看分回收束是否硬把人物"写死/写没"。 +- 长篇连载(网文、连载小说)的"虎头蛇尾"高发,因为情节收尾被上架、完本节点逼着提前打结。诊断时看守尾处人物是否消失、死亡或沦为工具;修复优先用梅瑞狄斯式(情节胜出但节制,留"言犹未尽"的桥段),其次考虑加一个圆形人物摆脱扁平。 +- "反情节式"在中文语境里对应多线并置、生活切片式的小说(如部分世情小说、群像小说),诊断时不要强求它"收尾打结",改问"多线并列是否有主线暗示"。 diff --git a/framework/catalog/dsh/skills/novel-diagnosis/references/quack-scholar-scan.md b/framework/catalog/dsh/skills/novel-diagnosis/references/quack-scholar-scan.md new file mode 100644 index 0000000..e5d68f0 --- /dev/null +++ b/framework/catalog/dsh/skills/novel-diagnosis/references/quack-scholar-scan.md @@ -0,0 +1,61 @@ +# 伪学者自检扫描表 + +用法:任何诊断、评论、书评、咨询报告输出之前(或之后复查)过一遍。判断标准与症状定义全部来自 references/quack-scholar.md();本表只是可填写的扫描骨架。福斯特自承"绝大多数人都是伪学者"——扫描的目的不是证明自己不是伪学者,是诚实承认症状并重写。 + +--- + +## 1. 五大症状扫描(每个标 0/1) + +| # | 症状 | 本次输出是否出现(0/1) | 出现在哪段 | +|---|------|------|------| +| 1 | 还没读完就分类(按时间/题材/地区/天气分) | | | +| 2 | 反复求助"天赋/天才"一词(免除深究的苦役) | | | +| 3 | 用"倾向/时代背景/思潮"等便携词取代真思考 | | | +| 4 | 把对象挂到时代背景/作者生平上(放弃深入对象) | | | +| 5 | 用"漂亮"代替"准确"(很美/有灵气/有格调,说不出具体做了什么) | | | + +判停:5 个症状全部 0 → 输出可能不是伪学者的,但要警惕"不知道自己不知道"。 + +## 2. 自检三问(真诚回答,每个给"是/不是" + "为什么") + +1. 我真的读完/做完要评论的对象了吗? + - 答:____;为什么:____ +2. 我用分类/术语/倾向掩盖了理解吗? + - 答:____;为什么:____ +3. 我是否在用漂亮词逃避追问? + - 答:____;为什么:____ + +不要回避"是",诚实地承认伪学者症状。 + +## 3. 最小可替换段落检查 + +标出至少 1 个段落:把其中"X 是天才" / "X 是 X 流派" / "X 反映了 X 倾向"里的具体词替换成另一部作品,整段若仍然成立 → 这是"伪学者段落",必须重写。 + +- 段落位置:____ +- 替换测试:把 ____ 换成另一部作品,段落还成立吗?____ +- 判定:□ 成立(伪学者段落,重写) □ 不成立(保留) + +## 4. 用"具体做了什么"代替"漂亮词"(至少改写 1 段) + +| 原句(漂亮词) | 改写(具体做了什么 → 产生什么效果) | +|---|---| +| 例:这部小说很有灵气 | 例:第 X 章用 Y 细节做了 Z,让读者产生 W 感受 | +| | | + +判停:改写后句子变长或变得不流畅 → 说明之前在用修辞掩盖空洞。 + +中文常见便携词对照(→ references/quack-scholar.md 中文落地): + +| 类别 | 常见空词 | 落地要求 | +|---|---|---| +| 翻译腔 | "有翻译腔" | 指到具体句式:被字句滥用、"的"字连缀过长、"进行 + 动词"堆砌、机翻式连接词密集 | +| 公文腔 | "官样""套话" | 指到具体词:"进行/开展/予以/进一步/不断/切实"、"以……为抓手/落实/赋能"、排比凑数 | +| 空泛赞美 | 有灵气/有格调/有韵味/大气/细腻/直击心灵 | 改写成"作品在某段做了什么具体动作、产生什么效果" | + +## 5. 谦虚声明 + +在输出末尾加一句: + +> 以上评论基于我对 ____ 的有限阅读,可能有盲点。 + +这是福斯特自承"伪学者"姿态的现代版本。 diff --git a/framework/catalog/dsh/skills/novel-diagnosis/references/quack-scholar.md b/framework/catalog/dsh/skills/novel-diagnosis/references/quack-scholar.md new file mode 100644 index 0000000..d6eed25 --- /dev/null +++ b/framework/catalog/dsh/skills/novel-diagnosis/references/quack-scholar.md @@ -0,0 +1,123 @@ +# 清理诊断结论:伪学者自检 + +来源: + +这是福斯特的评审纪律之二,用于诊断输出的最后一步:扫描自己是否在用"分类 + 引用术语"代替"真正理解"。福斯特自承"绝大多数人都是伪学者",给出可识别的症状清单,让评论者/咨询者/教师在输出的同时主动扫描自己是否落入这些症状。诊断结论必须过这一关,否则就是空话。 + +## 原文摘录 + +> "我们绝大多数人都是伪学者 …… 他袭用了真学者的方法, 却并不具备相应的学识装备。还不曾理解, 甚至还不曾博览群书, 他便开始动手将它们分门别类, 这是他的第一宗罪。" + +> "按照时间分类, 1847 年之前的书, 1847 年之后的书 …… 按照内容、题材什么的分类就更傻了。旅馆文学, 起自《汤姆·琼斯》; 女性运动文学, 始于《雪莉》; 荒岛文学, 自《鲁滨孙漂流记》发端 …… 苏塞克斯文学 …… 异类书籍, 一种严肃却枯燥乏味的分支 …… 与工业主义、航天飞行、手足医疗、天气气象等相关的小说。" + +> — E. M. 福斯特, 《小说面面观》第一讲 绪论 + +() + +## 方法规则 + +识别自己是否正在用"分类 + 引用术语"代替"真正理解"的诊断框架。**福斯特自承"绝大多数人都是伪学者"**,给出可识别的伪学者症状清单,让评论者/咨询者/教师在输出的同时,主动扫描自己是否落入了这些症状。() + +**五大症状**: + +1. **症状 1:还没读完就分类**——拿到一本书/一个产品/一个问题,还没深入读完,就开始"按时间分、按题材分、按地区分、按天气活动分"。这是最常见的伪学者动作。 +2. **症状 2:反复求助"天赋"一词**——"这是 X 天才写的","X 是天才","这种事普通人做不出来"。福斯特诊断:反复说"天赋"是因为这个词**免除了深究意义的苦役**——既然是天才,就不必解释为什么好。 +3. **症状 3:用"倾向"等便携词取代真思考**——"X 反映了 Y 倾向","X 是 Z 时代的产物","X 体现了 W 思潮"。福斯特诊断:用"倾向"一词,评论者"灵魂就升华了",听众"多半抽出铅笔记笔记",但都跳过了具体文本。 +4. **症状 4:把对象跟时代背景/作者生平挂钩**——"X 是在 Y 时代背景下产生的","X 是因为 Z 童年经历才写出来的"。福斯特诊断:这是评论者的"特权",放弃深入对象的借口。 +5. **症状 5:用"漂亮"代替"准确"**——把对象修饰得"很美" / "很有灵气" / "很有格调",但说不出具体做了什么。 + +**自检三问(在做完任何评论/咨询/报告后必问)**:() + +- 我真的读完/做完要评论的对象了吗? +- 我用分类/术语/倾向掩盖了理解吗? +- 我是否在用漂亮词逃避追问? + +### 判断标准 + +- 扫描五大症状,列出本次输出中出现的所有 5 个症状,每个症状标 0/1(是否出现)。判停条件:如果 5 个症状全部 0,说明输出可能不是伪学者的;但要警惕"不知道自己不知道"的情况。( 执行步骤) +- 自检三问,每个问题都有"是/不是" + "为什么"。不要回避"是",诚实地承认伪学者症状。( 执行步骤) +- 找"最小可替换段落":至少标出 1 个段落,这个段落如果把"X 是天才" / "X 是 X 流派" / "X 反映了 X 倾向"中的具体词替换,整段就不成立。这种段落就是"伪学者段落",必须重写。( 执行步骤) +- 用"具体做了什么"代替"漂亮词":至少改写 1 段,把"X 很有灵气"改为"X 在段落 Y 中做了什么具体动作,产生了 Z 效果"。判停条件:改写后句子变长或变得不流畅,说明之前在用修辞掩盖空洞。( 执行步骤) + +## 操作步骤(执行流程) + +来源: 执行段五步。 + +1. **扫描五大症状** + - 完成标准:列出本次输出中出现的所有 5 个症状,每个症状标 0/1(是否出现)。 + - 判停条件:如果 5 个症状全部 0,说明输出可能不是伪学者的;但要警惕"不知道自己不知道"的情况。 +2. **自检三问(真诚回答)** + - 完成标准:三个问题每个都有"是/不是" + "为什么"。 + - 不要回避"是",诚实地承认伪学者症状。 +3. **找"最小可替换段落"** + - 完成标准:至少标出 1 个段落,这个段落如果把"X 是天才" / "X 是 X 流派" / "X 反映了 X 倾向"中的具体词替换,整段就不成立。 + - 这种段落就是"伪学者段落",必须重写。 +4. **用"具体做了什么"代替"漂亮词"** + - 完成标准:至少改写 1 段,把"X 很有灵气"改为"X 在段落 Y 中做了什么具体动作,产生了 Z 效果"。 + - 判停条件:改写后句子变长或变得不流畅,说明之前在用修辞掩盖空洞。 +5. **承认"我读得不够多"** + - 完成标准:在输出末尾加一句"以上评论基于我对 X 的有限阅读,可能有盲点"。 + - 这是福斯特自承"伪学者"姿态的现代版本。 + +## 案例全文 + +### 案例 1:加洛韦的"按天气分类小说"——伪学者的极端样本() + +- **问题**:一本文学小册子《小说素材与方法》按"天气在小说中的作用"分类小说。 +- **方法论的使用**:福斯特把它当作伪学者的极端样本,列出 9 种天气功能:装饰性、实用性、解说性、奠定和谐、反衬情绪、促发行动、产生控制性影响、主角、不存在。 +- **结论**:分类无意义,作者不得不承认"还需要一样东西,那就是天赋——了解九种天气分类对小说作者来说是没有用的,除非他也是个有天赋的人"。 +- **结果**:福斯特用此例说明伪学者的标志——分类学装置构造得越精美,越暴露理解的空。 + +### 案例 2:文学评论中的"天才崇拜"() + +- **问题**:很多人评论 X 作家时说"X 是天才"。 +- **方法论的使用**:福斯特诊断"他们是伪学者的好标本——他们总是热衷于谈论天赋,因为这个词一出口,就免除了深究意义的苦役"。 +- **结论**:"文学是天才们写就的。小说作者都是天才。瞧啊,就是这样,现在,我们开始为他们分类吧。"——这就是他们做的。 +- **结果**:此案例成为"天才崇拜"作为伪学者标志的经典诊断。 + +### 案例 3:司各特"按故事分类"评论() + +- **问题**:评论者说"X 作家是讲故事的高手"。 +- **方法论的使用**:福斯特诊断——"他说的东西或许都很准确,但毫无意义,因为他只是在书堆里打转,而非深入每一本之中,他要么就是根本没读过这些书,要么就是不得读书之法"。 +- **结论**:"会讲故事"是个"便携词",取代了对"讲了什么故事 / 怎么讲 / 为什么这样讲"的具体追问。 +- **结果**:福斯特借此把"会讲故事"从"正面评价"翻转为"伪学者的逃避"。 + +## 常见误区与失败模式 + +- **还没读完就分类**——"1847 年之前的书,1847 年之后的书"。() +- **用天赋逃避深究**——"文学是天才们写就的"。() +- **用"倾向"代替具体分析**——"X 反映了 Y 倾向"。() +- **用作者生平代替作品分析**——"X 因为 Y 童年经历才写出来"。() +- **把对象修饰得"很美"**——"X 很有灵气 / 很有格调"而说不出具体做了什么。() + +## 边界与盲点 + +不适用场景:() + +- **真正的历史/学术研究**——分类是合法的,不必扫描。 +- **初次接触新领域**——分类是脚手架,此时自检会阻碍学习。 +- **被要求快速输出**——自检需要时间,紧急情况不适用。 +- **评论者已经知道自己是新手**——这时扫描会显得居高临下。 + +作者盲点:() + +- **福斯特的"伪学者"自承是反讽姿态**——不要把它当成"我没学问"的谦虚,它是"我知道我的方法不够,但我选择用这种不够的方法换得自由"。 +- **现代主义巅峰期的视角**——1927 年;现代的数据驱动决策、循证医学、A/B 测试已经部分替代了"伪学者"批评。 +- **对"分类"的全盘否定过激**——某些分类(化学元素表、生物分类法)是真学问,不该被一并扫掉。 + +## 易混的邻近方法论 + +- **vs 批判性思维(Critical Thinking)**——伪学者自检更锋利,直接针对"分类学装置",批判性思维更一般化。() +- **vs 怀疑论(Skepticism)**——怀疑论质疑命题真假,伪学者自检质疑"评论姿态本身"。() +- **vs 知识谦逊(Intellectual Humility)**——知识谦逊是美德,伪学者自检是诊断;前者是心态,后者是工具。() +- **与 round-table 的区别**:伪学者自检是**反分类崇拜**的姿态,圆桌论是**反时间崇拜**的姿态。 +- **与 seven-aspects 的区别**:七侧面是**怎么建构分析**,伪学者自检是**怎么识别自己的分析是不是空的**。 + +## 中文落地 + +- 中文评论有自己的一套"便携词",同样要扫描: + - **翻译腔信号**——"被字句滥用""'的'字连缀过长""'进行 + 动词'堆砌""机翻式连接词(然而/因此/此外密集出现)"。诊断语言是否翻译腔,不能只贴"有翻译腔"标签,要指到具体句式和词。 + - **公文腔信号**——"'进行''开展''予以''进一步''不断''切实'等官样动词""'以……为抓手''落实''赋能'等套语""排比凑数、对仗堆砌"。公文腔是用程式化措辞代替具体描写。 + - **空泛赞美词**——"有灵气""有格调""有韵味""大气""细腻""直击心灵"。这些都是"漂亮代替准确",要改写成"作品在某段做了什么具体动作、产生什么效果"。 +- 落地写法(改写示范):把"这部小说很有灵气"改为"第 X 章用 Y 细节做了 Z,让读者产生 W 感受";改写后句子变长,恰好证明之前在用修辞掩盖空洞。 +- 自检三问在中文语境同样适用:我真的读完全文了吗?我在用"流派/倾向/时代背景"掩盖理解吗?我在用漂亮词逃避追问吗? diff --git a/framework/catalog/dsh/skills/novel-diagnosis/references/round-table.md b/framework/catalog/dsh/skills/novel-diagnosis/references/round-table.md new file mode 100644 index 0000000..6ff3998 --- /dev/null +++ b/framework/catalog/dsh/skills/novel-diagnosis/references/round-table.md @@ -0,0 +1,118 @@ +# 比较诊断:抹掉标签再并置——圆桌论 + +来源: + +这是福斯特的评审纪律之一,用于"把自己的作品与参照作品比差距"或"跨时代、跨流派比较"。核心动作:把所有时代、所有流派的样本"同时"放进一间圆形大房间并置阅读,故意切断时间线,让比较基于"做了什么"而非"何时写的"。 + +## 原文摘录 + +> "我们不妨想象所有小说作者是同时坐在一个圆形大房间里工作吧。在展示作品文字之前我不会提及他们的名字, 因为名字总难免附带着年代、传言等等所有我们正打算丢弃的'废牌'。" + +> "我们绝不可凝望时间的长河。另一种场景更适合我们的能力, 也就是说, 让所有小说作者同时提笔写作。" + +> — E. M. 福斯特, 《小说面面观》第一讲 绪论 + +() + +## 方法规则 + +跳出编年/年代视角,把所有时代、所有国籍的样本"同时"放到同一间圆形大房间里并置阅读。**故意切断时间线**,通过"两两成组的盲文对比"逼出概念的边界。() + +核心操作: + +1. **承认"年代视角"是污染源**——当我们说"这本书是 19 世纪的",已经带上了"过气了""经典但陈旧"等光环,这些光环让我们无法纯粹地看它做了什么。 +2. **把所有样本"匿名化"地放在一起**——不提作者名字、年代、流派,只看作品本身的文字。 +3. **两两配对做盲文对比**——福斯特反复使用此技巧:把"两位完全不同的作者"的两段文字并置,让读者先感受共性,再揭示作者(理查森 vs 詹姆斯 / 威尔斯 vs 狄更斯 / 伍尔夫 vs 斯泰恩)。 +4. **"历史滚滚向前,艺术恒久不变"作为隐含前提**——福斯特断言:人性在四百年内不发生质变,因此跨时代比较有合法性。这是此方法论的**信念前提**,不是证明。 +5. **接受代价:严格历史研究做不了**——圆桌论"无法检验传统","也无法维护传统",牺牲了考据能力换得概念穿透力。 + +关键认识:圆桌论是一种**故意"浅薄"的方法论**。福斯特自承"我读得不够多,装备不足",因此选择放弃权威,换得自由。读者模仿此方法时,也要接受"我看到的不是全部"这个限制。() + +### 判断标准 + +- 选 2-5 个跨时代/跨流派的样本,至少 2 个样本来自不同时代或流派;优先选"看起来毫不相关"的,强迫自己找共性。( 执行步骤) +- 摘录 2-3 段关键文字,不署作者、不署年代,单纯并置。判停条件:如果发现"摘录时已经选了对某作者有利的段落",重选。( 执行步骤) +- 让读者先感受共性,再揭示作者。揭示后问:"时间标签改变你的判断了吗?为什么?"( 执行步骤) +- 承认代价:圆桌论放弃严格历史研究,能看到概念穿透,但看不到影响、流派、传承。( 执行步骤) + +## 操作步骤(执行流程) + +来源: 执行段五步。 + +1. **承认"年代视角是污染源"** + - 完成标准:明确说出"我们被'X 时代' / 'X 流派'的标签干扰,让我们先去掉这些标签"。 +2. **选 2-5 个跨时代/跨流派的样本** + - 完成标准:至少 2 个样本来自不同时代或流派。 + - 提示:选样本时优先选"看起来毫不相关"的,强迫自己找共性。 +3. **匿名并置样本的关键段落** + - 完成标准:摘录 2-3 段关键文字,不署作者、不署年代,单纯并置。 + - 判停条件:如果发现"摘录时已经选了对某作者有利的段落",重选。 +4. **让读者先感受共性,再揭示作者** + - 完成标准:问"如果不知道作者是谁,你会怎么比较?" + - 揭示作者后,再问"时间标签改变你的判断了吗?为什么?" +5. **承认圆桌论的代价** + - 完成标准:明确说"圆桌论放弃严格历史研究,我们能看到的概念穿透,但看不到影响、流派、传承"。 + +## 案例全文 + +### 案例 1:弗吉尼亚·伍尔夫 斯泰恩《项狄传》——同一束幻想之光() + +- **问题**:伍尔夫(1917)和斯泰恩(1759)看似毫无关系,凭什么放在一起? +- **方法论的使用**:福斯特匿名并置两段文字,让读者先感受到"两人都从一个小物事开始任意翱翔,然后回归",才揭示作者。 +- **结论**:两人在 150 年间共享同一种"幻想"笔法。 +- **结果**:圆桌论证明——时间标签在这里无意义,"做了什么"是唯一有效的比较单位。 + +> 《项狄传》在幻想典型角度下的案例见 references/fantasy-prophecy.md 案例 1("混乱神"、接受现实不连贯),角度不同,两处都保留。 + +### 案例 2:威尔斯 狄更斯《远大前程》——同一对葬礼() + +- **问题**:两场葬礼,一场 1910,一场 1861,看似无关。 +- **方法论的使用**:福斯特匿名并置两段描述葬礼的段落,让读者看到"两人都用细节引人入胜、都厌恶虚伪、都把幽默与社会批评结合"。 +- **结论**:威尔斯和狄更斯有相同的"视角和技巧"(比较两个花瓶和两个玻璃樽)。 +- **结果**:圆桌论证明——时代相近的两人在 49 年间共享了同样的写作姿态。 + +### 案例 3:哈代 司各特《威弗莱》——同样的命运凌驾人物() + +- **问题**:哈代(1903)和司各特(1814)命运悲剧的处理方式相同还是不同? +- **方法论的使用**:福斯特用圆桌论比较两人的"命运凌驾人物"手法,跨 89 年仍发现同样问题。 +- **结论**:这是"情节的过度胜利"这一失败模式的跨时代存在。 +- **结果**:圆桌论能识别**失败模式的跨时代一致性**,比"哈代学司各特"的简单历史叙事更准确。 + +> 哈代"命运凌驾人物"在拉锯失败角度下的案例见 references/plot-character.md 案例 1,角度不同,两处都保留。 + +## 常见误区与失败模式 + +- **天才崇拜**——"文学是天才们写就的",拒绝并置。() +- **倾向崇拜**——"用'倾向'一词代替真思考"。() +- **编年学家误用**——把"流派的形成"和"创作行为的本质"混淆。() +- **按天气分类**——伪学者把小说按"天气在故事中的作用"分类。() + +## 边界与盲点 + +不适用场景:() + +- **需要严格历史研究**——"X 是怎么影响 Y 的",圆桌论回答不了。 +- **需要时效性建议**——"X 股票明天会涨吗",圆桌论完全不适用。 +- **被比较的样本属于同一时代/流派**——没有跨时代/跨流派时,普通对比即可,圆桌论是杀鸡用牛刀。 +- **对象本身强烈受时间影响**——比如"Unix 哲学在 1970s vs 2020s 的不同",这种时间维度本身就是对象的一部分。 + +作者盲点:() + +- **"人性四百年不变"是信念,不是证明**——福斯特承认"蟹行"运动可能缓慢到两百年内看不到,但他选择"以人性不变为前提"。 +- **圆桌论的"自由"是有限制的**——福斯特读得不够多(他自承),因此"他选择的方法刚好符合他的能力",不一定符合所有人。 +- **现代主义巅峰期的视角**——1927 年;没看到 60 年代后的拉美魔幻、后现代拼贴、亚非作家。 + +## 易混的邻近方法论 + +- **vs 文学比较研究(Comparative Literature)**——圆桌论是"反方法的姿态",比较文学是"有方法论的学科"。() +- **vs 文学史(Literary History)**——圆桌论刻意回避文学史,文学史刻意构建文学史。() +- **vs 经典化(Canonization)**——圆桌论不是"选经典",是"看所有样本"。() +- **与 seven-aspects 的区别**:圆桌论是**怎么比较样本**(方法论),七侧面是**怎么拆解一个样本**(分析框架)。 +- **与 quack-scholar-check 的区别**:圆桌论是**反时间崇拜**的姿态,伪学者自检是**反分类崇拜**的姿态。 +- **与"历史研究"的区别**:圆桌论**明确放弃**严格历史研究能力,换得概念穿透。 + +## 中文落地 + +- 圆桌论特别适合中文语境的诊断:把自己的稿子和《红楼梦》《儒林外史》《金瓶梅》或现代网文、类型小说的段落抹掉年代标签并置,只比"做了什么"(怎么开场、怎么让人物登场、怎么收尾),避免"这是古典的/这是网文的"这类标签先入为主。 +- 中文文学史常被"朝代分期"绑架(唐传奇、宋话本、明清章回、五四新文学、当代网络文学),圆桌论的匿名并置可以穿透这些分期,看具体手法是否真的高下立判。 +- 代价同样适用:圆桌论看不出"谁影响了谁"。中文作品的师承、流派问题(如某作家是否学某家)要靠文学史研究,圆桌论不负责。 diff --git a/framework/catalog/dsh/skills/novel-diagnosis/references/story-plot.md b/framework/catalog/dsh/skills/novel-diagnosis/references/story-plot.md new file mode 100644 index 0000000..8d792d6 --- /dev/null +++ b/framework/catalog/dsh/skills/novel-diagnosis/references/story-plot.md @@ -0,0 +1,123 @@ +# 结构层透镜:是故事还是情节——问"后来呢"还是问"为什么" + +来源: + +这是福斯特对叙事结构层的诊断透镜:一部作品(或一个章节)现在激发的到底是好奇心("后来呢?")还是因果理解("为什么?")。故事层只要好奇心,情节层另要头脑和记忆力。这是一个可主动切换的提问法,既能用来分析别人作品,也能用来自检自己写的章节。 + +## 原文摘录 + +> "'国王死了, 接着王后也死了', 这是故事。'国王死了, 王后悲伤过度, 也死了', 这是情节。时间顺序仍在, 但更凸显的是其中蕴含的因果关系。" + +> "以'王后之死'为例, 如果这是个故事, 我们会问: '然后呢?' 如果是个情节, 我们的问题则是: '为什么?'" + +> "好奇心是人类最低级的本能之一 …… 一个会问你有多少兄弟姊妹的人绝不会是个讨人喜欢的家伙 …… 要掌握'情节', 我们必须调动头脑和记忆力。" + +> — E. M. 福斯特, 《小说面面观》第二讲 / 第五讲 + +() + +## 方法规则 + +区分两个层次的叙事提问:**故事只需要好奇心**(问"后来呢"),**情节还需要头脑和记忆力**(问"为什么")。这是个可主动切换的提问法,不仅用于分析,还用于写作。() + +核心操作: + +1. **故事 = 时间顺序的事件流**——"国王死了,然后王后死了"——只要记住时间线就够,不需要联系。 +2. **情节 = 因果关系的网络**——"国王死了,因此王后悲伤过度也死了"——必须把当下事实与前文联系起来。 +3. **提问切换作为诊断**——当你问"然后呢",你在故事层;当你问"为什么",你在情节层。这个切换不消耗,但能精准告诉你当前在哪一层。 +4. **情节需要三个条件**: + - **头脑**:把事实与前文联系起来看,容许暂时不理解 + - **记忆力**:每个举动、每个词都有意义,无冗余 + - **悬念**:制造时序断裂 + 重新整合 +5. **故事与情节不互相排斥**——优秀小说同时需要两者。先用故事把读者拉进来(激发好奇心),再用情节满足读者(调动头脑)。 + +关键认识:故事是低等但不可或缺的;情节是高等但有代价。"你只想要故事 → 像山鲁佐德的暴君丈夫那样,听完就忘;你只想要情节 → 智力有余但缺入口"。两者平衡是写作的关键。() + +### 判断标准 + +- 标出最近 5 个提问,看是"然后呢"还是"为什么":全是"然后呢"→ 叙事停留在故事层;至少 2 个"为什么"→ 进入情节层。( 执行步骤) +- 故事层健康的标志:读者/听众想继续听下去。失败征兆:读者走神、中途放弃、只记得"我读了 200 页,啥也没记住"。( 执行步骤) +- 情节层健康的标志:至少 2 个关键事实/事件有"为什么"被揭示,至少 1 处"悬念"被设计(时序断裂 + 重新整合)。失败征兆:读者/听众"看完就忘,想不起发生了什么","作者/讲者的话很漂亮但没有逻辑"。( 执行步骤) + +## 操作步骤(执行流程) + +来源: 执行段五步。 + +1. **识别当前叙事的"提问"在哪一层** + - 完成标准:标出最近 5 个提问,至少 3 个是"然后呢"还是"为什么"。 + - 判停条件:如果全部是"然后呢",叙事停留在故事层;如果有至少 2 个"为什么",进入情节层。 +2. **检查故事层是否健康** + - 完成标准:故事层是否做到了"读者/听众想继续听下去"?如果是"听不下去",是故事层问题(事件流不吸引)。 + - 故事层失败的征兆:读者走神、中途放弃、只记得"我读了 200 页,啥也没记住"。 +3. **检查情节层是否健康** + - 完成标准:至少 2 个关键事实/事件有"为什么"被揭示,至少 1 处"悬念"被设计(时序断裂 + 重新整合)。 + - 情节层失败的征兆:读者/听众"看完就忘,想不起发生了什么","作者/讲者的话很漂亮但没有逻辑"。 +4. **诊断失衡** + - 完成标准:判断是"故事过强,情节过弱"(如司各特)还是"情节过强,故事过弱"(如梅瑞狄斯某些篇)。 + - 反模式:故事过强 → 像山鲁佐德丈夫的"暴君",听完就忘;情节过强 → 像纯学术论文,智力有余但缺入口。 +5. **给出修复建议** + - 完成标准:至少 1 条具体修改(如"加入一段倒叙,把'国王为什么死'揭示出来,调动读者的头脑")。 + - 不要空话(如"加强情节")——给可操作修改。 + +## 案例全文 + +### 案例 1:司各特《古董商人》——故事 = 绦虫式时间叙述() + +- **问题**:司各特为什么会讲故事。 +- **方法论的使用**:福斯特逐句分析《古董商人》开篇,说明故事靠"然后呢"运作,每个新人物(埃迪·奥奇特里、亚瑟·沃德杜尔、格里兹尔小姐)都被引入只是为了"让事件一个接着一个发生"。 +- **结论**:司各特是"故事"大师,但牺牲了"激情"和"思想"。 +- **结果**:借此福斯特区分"故事高手"和"小说家"——前者只满足好奇心,后者同时满足好奇心和头脑。 + +### 案例 2:梅瑞狄斯《利己主义者》——情节设计的高手() + +- **问题**:梅瑞狄斯为什么被称为"英国小说诞生以来最出色的情节设计师"。 +- **方法论的使用**:福斯特用雷蒂西亚·黛尔的"心境转变隐藏"作为情节设计的典范——她的心理过程不能提前揭示,否则"高雅喜剧"就毁了。 +- **结论**:情节的胜利要求"瞒着读者",让人物为情节暂时让步。 +- **结果**:与哈代形成对比——哈代让人物为情节做出太多牺牲,人物被耗尽;梅瑞狄斯懂得节制。 + +> 同一人物(雷蒂西亚·黛尔)在情节-人物拉锯角度下的案例见 references/plot-character.md 案例 2(拉锯节制),角度不同,两处都保留。 + +### 案例 3:贝内特 托尔斯泰《战争与和平》——故事/情节角度简注() + +- **问题**:两本都写时间,为什么后者伟大,前者"失于伟大"? +- **方法论的使用**:福斯特比较——贝内特只展开"时间生活"(故事 + 时间维度),托尔斯泰同时展开"时间生活"和"空间感"(情节的因果 + 空间的张力)。 +- **结论**:贝内特"有时间,没价值";托尔斯泰"有时间,有价值,有空间"。 +- **结果**:借此说明——优秀小说不是单侧面(时间故事)的极致,而是多侧面的平衡。 + +> 同一对比的动态平衡角度全文案例见 references/dimension-frameworks.md 案例 4,时间/价值角度全文案例见 references/time-value.md 案例 1、2。角度不同,多处保留;本处是故事/情节结构层的简注。 + +## 常见误区与失败模式 + +- **故事 → 情节的胜利代价**——梅瑞狄斯式的"情节胜出"必须节制,否则人物被耗尽(夏洛蒂·勃朗特式偷走人物"知无不言")。() +- **情节 → 命运的过度胜利**——哈代式,人物被命运凌驾,失去"人之为生灵所做出的努力"(哈代式命运凌驾)。() +- **戏剧化的小说**——把亚里士多德三步骤硬套到所有小说,牺牲小说的开放性。() +- **只想要故事**——山鲁佐德的暴君丈夫,听完就忘(高尔夫球手式"故事 > 一切")。() + +## 边界与盲点 + +不适用场景:() + +- **纯新闻速报**——时间流本身就是内容(如"今天发生了 X、Y、Z"),不需要因果。 +- **菜谱/操作指南**——步骤本身就是内容,不需要因果(除非涉及"为什么先放盐后放糖"等原理)。 +- **纯娱乐八卦**——八卦就是要"然后呢"的故事层,情节太重反而无趣。 +- **紧急通知**——"X 系统挂了,请立即重启"——故事就是内容。 + +作者盲点:() + +- **现代主义巅峰期的视角**——1927 年;当时还没有"信息图/视频/数据可视化"等更现代的叙事形态,故事/情节二分以文字为基础。 +- **对"悬念"的诊断不够展开**——福斯特用"悬念"作为情节的关键,但没深入讨论"悬疑小说"(Whodunit)这种特殊形态。 +- **西方文学中心的视角**——引用的案例几乎全是英美欧陆小说;东方文学(如中国章回小说、日本物语)的"故事 vs 情节"结构未被充分讨论。 + +## 易混的邻近方法论 + +- **vs 戏剧结构(Dramatic Structure:三幕剧/起承转合)**——福斯特明确反对硬套戏剧结构到小说。() +- **vs 5W1H / 金字塔原理**——这些是"如何组织汇报"的工具,不区分"故事"和"情节"。() +- **vs Hero's Journey(英雄之旅)**——这是个特定的"情节模型",不涵盖"故事"层。() +- **与 time-vs-value-life 的区别**:故事/情节二分是**叙事结构层**,时间/价值二分是**生活/意义层**;前者管"读起来的感觉",后者管"活起来的感觉"。 +- **与 plot-character-tug 的区别**:故事/情节是**单方面的诊断**,情节-人物拉锯是**双方面的张力诊断**。 + +## 中文落地 + +- 章回小说天然强在故事层:"欲知后事如何,且听下回分解"的回末套语就是"后来呢"的钩子,故事层资源是现成的。诊断中文古典式作品先别急着骂"只有故事",要问故事层是否健康(读者想不想听下去)。 +- 中文作品的情节层("为什么")常藏在对偶回目、草蛇灰线的伏笔里,不在显性因果句里。诊断时把回末悬念逐个标记,区分"只勾'后来呢'的"和"勾'为什么'的",再看两类钩子的比例。 +- "故事过强"在中文语境里的典型症状是章回体式的连环事件堆叠(一个接一个桥段,读者只记"后来呢");"情节过强"的典型症状是推理化、概念化的小说——因果讲得滴水不漏,但读者进不了门。 diff --git a/framework/catalog/dsh/skills/novel-diagnosis/references/time-value.md b/framework/catalog/dsh/skills/novel-diagnosis/references/time-value.md new file mode 100644 index 0000000..5cc11c6 --- /dev/null +++ b/framework/catalog/dsh/skills/novel-diagnosis/references/time-value.md @@ -0,0 +1,122 @@ +# 意义层透镜:有时间,有没有价值——时间生活 vs 价值生活 + +来源: + +这是福斯特对叙事意义层的诊断透镜:一部作品(乃至一次体验、一场会议、一段关系)处于"时间堆积"(低强度的时间堆叠,如流水账)还是"价值峰值"(高强度的体验,即使短暂也值得)。故事/情节透镜管"读起来的感觉",这个透镜管"活起来的感觉"。 + +## 原文摘录 + +> "无论日常生活的真实面目如何, 它其实都是由双重生活所构成的, 亦即, 时间维度的生活与价值维度的生活。我们的行为泄露了我们的双重忠诚。'我只看了她五分钟, 可那是值得的。'在这么一个简单的句子里, 你便表达了双重的忠诚。" + +> "所谓'故事', 就是讲述时间维度里的生活。扩展到完整的'小说', 则同时还应当包含价值维度的生活, 需要用到的工具我们将在以后谈到。它同样提供双重的忠诚。" + +> — E. M. 福斯特, 《小说面面观》第二讲 故事 + +() + +## 方法规则 + +日常生活/叙事/产品/关系的**二元分解**:时间生活(按"分钟/小时"测量,关心"在什么之前/之后"——线性序列)与价值生活(按"强度/高度"测量,关心"我看了她五分钟,可那是值得的"——非线性,摆脱暴君式的时钟)。() + +核心操作: + +1. **承认"双重生活"是常态**——任何体验/叙事/产品,都同时处于时间轴和价值轴上。两者不是非此即彼,是**双重忠诚**。 +2. **时间轴的可诊断征兆**: + - "我花了 X 时间"(不带任何价值判断) + - "我熬过了 X 分钟" + - "X 天都在做 Y" + - "流水线 / 流水账 / 同样的事情一遍又一遍" +3. **价值轴的可诊断征兆**: + - "X 真的值得" + - "我看了她五分钟,可那是值得的" + - "那一瞬间我感到..." + - "改变了我对 Y 的看法" +4. **小说/叙事的"双重忠诚"**——好的叙事既给读者时间享受(故事),又给读者价值享受(情节、人物、幻想、预言、模式、节奏)。单侧面的极致是失衡。 +5. **"价值生活"≠ 主观偏好**——它有客观成分,如"我愿意为它付出代价(哪怕短暂)"/"它让我在事后还回想"。 + +关键认识:价值生活不能脱离时间生活存在(你必须花时间才能有体验),但时间生活可以脱离价值生活存在(无意义的时间堆积)。后者是消磨,前者是体验。() + +### 判断标准 + +- 时间轴过强的征兆:单纯堆叠事件,没有强度/高度变化。( 执行步骤) +- 价值轴过弱的征兆:体验平淡,事后不回想,没有"超越'当然'的底蕴"。( 执行步骤) +- 失衡方向三分:时间轴过强(消磨)/ 价值轴过强(稀缺)/ 平衡良好(双重忠诚)。( 执行步骤) + +## 操作步骤(执行流程) + +来源: 执行段五步。 + +1. **承认"双重生活"是起点** + - 完成标准:明确说出"任何体验都同时处于时间轴和价值轴,我们做的是双重忠诚的诊断"。 +2. **诊断时间轴** + - 完成标准:列出"我花了 X 时间在 Y 上"等时间堆积症状,至少 1 条。 + - 时间轴过强的征兆:单纯堆叠事件,没有强度/高度变化。 +3. **诊断价值轴** + - 完成标准:列出"我感到...","那一刻...","X 改变了我"等价值峰值征兆,至少 1 条。 + - 价值轴过弱的征兆:体验平淡,事后不回想,没有"超越'当然'的底蕴"。 +4. **判断失衡方向** + - 完成标准:明确说"时间轴过强(消磨)/ 价值轴过强(稀缺)/ 平衡良好"。 + - 反模式:时间轴过强 → 消磨;价值轴过强 → 短暂但不可持续;平衡 → 双重忠诚。 +5. **给出修复建议** + - 完成标准:至少 1 条具体修改(如"在长会议中加 1 个'价值峰值'瞬间——一个故事 / 一个对比 / 一个让听众愣住的细节")。 + - 不要空话(如"提高会议质量")——给可操作修改。 + +## 案例全文 + +### 案例 1:贝内特《老妇人的故事》——时间生活的极致() + +- **问题**:贝内特写索菲亚和康斯坦斯从童年到老年的消亡,时间成为真正的主角。 +- **方法论的使用**:福斯特诊断——这本书"有力、真挚、悲伤,却依旧不免失于伟大",因为"它没有'当然'之上的底蕴",只有时间生活,没有价值生活。 +- **结论**:贝内特的"时间生活"做到了极致(索菲亚死、康斯坦斯死、老狗艰难爬去看食盆),但缺乏"超越'当然'的底蕴"。 +- **结果**:借此福斯特区分"健全完整的真实"(贝内特)vs "伟大的真实"(托尔斯泰)。 + +### 案例 2:托尔斯泰《战争与和平》——空间感 = 价值生活() + +- **问题**:为什么托尔斯泰不让人沮丧,贝内特让人沮丧? +- **方法论的使用**:福斯特诊断——托尔斯泰在时间维度外**拓展出了空间维度**,"空间感是令人振奋的,它拥有类似音乐的力量";贝内特只有时间。 +- **结论**:空间感 = 价值生活的一个具体形态,它让读者"穿行在俄罗斯大地"时"和弦宏伟嘹亮"。 +- **结果**:借此福斯特把"价值生活"具象化为"空间 / 音乐 / 美感"。 + +### 案例 3:山鲁佐德的"故事" vs "情节"——时间/价值的实际例子() + +- **问题**:山鲁佐德为什么能活下来? +- **方法论的使用**:福斯特诊断——山鲁佐德的故事"只是为了活下去"的时间序列("后来呢?然后呢?还有吗?"),但她故事的"价值"在于"她的言辞优雅细腻、观点开明宽容、情节巧妙新颖、德行高尚美好"。 +- **结论**:山鲁佐德"用故事(时间生活)喂饱暴君的好奇心,用情节(价值生活)真正打动他"。 +- **结果**:借此说明,即使在"最底层的讲故事"场景中,价值生活也已经存在——没有纯粹的"时间"。 + +> 贝内特 vs 托尔斯泰这对案例在动态平衡角度下见 references/dimension-frameworks.md 案例 4,在故事/情节角度下的简注见 references/story-plot.md 案例 3。角度不同,多处保留。 + +## 常见误区与失败模式 + +- **只有时间生活**——贝内特式,"失于伟大"(贝内特式只有时间维度)。() +- **试图彻底砸碎时间**——格特鲁德·斯坦因式,失败(斯坦因式彻底打碎时间)。() +- **强行让时间生活 = 价值生活**——伪学者的"按时间分类"。() + +## 边界与盲点 + +不适用场景:() + +- **真正需要时间记录的对象**——如工作时长、专注度计时,时间本身就是数据。 +- **完全没时间投入的"白嫖"判断**——"我 X 都没花过时间,凭啥评价"——此时时间/价值二分不适用。 +- **必须以时间为唯一指标的场景**——如工作薪酬计算,时间就是钱的单位。 +- **紧急事件**——"X 系统挂了",时间就是全部。 + +作者盲点:() + +- **"双重生活"的二分太干净**——现代神经科学发现"价值感"和"时间感"在脑中相互调制,不是两个独立维度。 +- **以小说为原型,未必适用所有叙事**——短视频、播客、信息图、互动叙事等新形态的"时间/价值"关系可能更复杂。 +- **未充分讨论"价值生活"的多样性**——福斯特把"价值"具象化为"空间/音乐/美感",但"道德价值"/"实用价值"/"情感价值"等未被分别讨论。 + +## 易混的邻近方法论 + +- **vs 体验经济/体验设计**——Pine & Gilmore 的"体验经济"以"消费体验"为单位,时间/价值二分更基础。() +- **vs 心流/巅峰体验**——Csikszentmihalyi / Maslow 的"高峰体验"是个体心理状态,时间/价值二分是"诊断工具"。心流是"完全沉浸"的状态,时间/价值二分是"体验是否有意义"的诊断;心流常落入价值峰值,但也有不进入心流的价值峰值。() +- **vs 工作-生活平衡**——后者是"工作 vs 私人时间"的比例,时间/价值二分是"任何时间是否有价值"的诊断。() +- **与 story-vs-plot 的区别**:时间/价值二分是**意义层**,故事/情节二分是**结构层**;前者管"活起来的感觉",后者管"读起来的感觉"。 +- **与 expansion-vs-completion 的区别**:时间/价值是**对体验的诊断**,扩展/完成是**对作品终点的姿态**;前者管中间,后者管结尾。 + +## 中文落地 + +- 时间/价值两轴在中文叙事里同样适用。章回小说的"且听下回分解"是时间轴的牵引(让人想知道后来呢),价值峰值则常出现在"停下来不走"的段落:诗词、曲赋、即景联句、一场戏的工笔细描。诊断中文作品时问:"除了事件流,有没有让人事后回想的段落?" +- 中文网文连载天然拉长"时间轴"(日更、追更),诊断时尤其要警惕时间堆积——"我追了三百章"本身不是价值;要找出全书的价值峰值(读者事后仍会引用的场面、台词、意象),找不到即时间堆积。 +- 修复方向在中文语境里可落地为:在长事件流中插入一个价值峰值瞬间——一个让读者愣住的细节、一段停下来细写的场面、一句能被引用的话。不要空喊"提升深度"。 diff --git a/framework/catalog/dsh/skills/prose-craft/SKILL.md b/framework/catalog/dsh/skills/prose-craft/SKILL.md new file mode 100644 index 0000000..1eb9605 --- /dev/null +++ b/framework/catalog/dsh/skills/prose-craft/SKILL.md @@ -0,0 +1,76 @@ +--- +name: prose-craft +description: | + 中文小说的语言与修辞领域:写稿或改稿时调整句子层与段落层的文本。激活场景:段落读起来单调催眠,句长或主谓位置需要诊断;满纸抽象,读者既看不见也摸不着,怀疑卡在官僚话、套话、公文腔;重大场景(死亡、战争、重病)用力过猛,或日常场景没有文气;抒情太直白变滥情;想用白描立人物;文本或人物温度不稳、没有辨识度;风格漂移,想逐根杠杆诊断声音。 + 关键 trigger:"句法节奏" / "主谓先行" / "右分支句" / "句长" / "模式转折" / "boom boom bang" / "翻译腔" / "抽象梯子" / "太抽象" / "能给我个例子吗" / "给我个例子" / "由抽象到具体" / "怎么写得有深意" / "用力过猛" / "修辞密度" / "克制" / "back off" / "show off" / "抒情" / "滥情" / "白描" / "基础体温" / "声音均衡器" / "graphic equalizer" / "风格漂移" / "风格诊断" / "找到自己的声音" / "三十个杠杆"。 + 不适用于:诗歌;实验文学与故意打破语法的项目;翻译文本(应保留原语节奏);纯动作戏(无抽象层与修辞校准需求);公文、教科书、工具书、学术论文、商业文案等非叙事文体。 + 与 show-and-omission 交接:「太抽象 / 读者看不见」若主要是情绪/性格标签堆叠,归后者做标签→场景;本 Skill 管句段修辞、句长、修辞密度与声音杠杆。 +--- + +# 语言修辞(prose-craft) + +给中文小说的语言装上一组可调的旋钮:句子节奏、抽象层级、修辞密度、情感出口、白描立人、文本体温、声音杠杆,每个方法都落到可执行的操作与判断标准。 + +## 方法索引 + +### 调整句子节奏 +- **主谓先行**:默认主谓放句首当火车头拉车厢,主谓远置只留给悬念、发现、庄重场景。 → references/sentence-rhythm.md +- **句长控速**:长句载着读者走,短句踩刹车,五种句长各有战略目的,相邻五句不许单轨。 → references/sentence-rhythm.md +- **翻译腔检测**:查"是"字句、被动语态、长定语后置三个信号,英语方法按"先动作后修饰"和逗号节奏在中文落地。 → references/sentence-rhythm.md + +### 安放抽象与具体 +- **下梯子**:问"能给我一个例子吗",从抽象词下到看得见摸得着的物。 → references/abstraction-ladder.md +- **上梯子**:问"那是什么意思",从琐碎的物上到一句能被引用的判断。 → references/abstraction-ladder.md +- **中段自检**:官僚话、套话、四字格、意境堆叠都是困在梯子中段,读者既看不见也摸不着。 → references/abstraction-ladder.md + +### 校准场景修辞 +- **退一步与进一步**:修辞密度与主题温度成反比,重场景克制、轻场景炫技,用 1-10 温度计评分并以广岛幸存者检验自查。 → references/rhetoric-density.md +- **先建模式再打破**:平行铺陈后在结尾换一词,通篇克制后破例靠近一次,句法层与情感层是同一门手艺。 → references/pattern-and-break.md + +### 处理情感 +- **抒情不抒发**:不写"我多么 X",写一个动作,小说家只传递情感不宣告。 → references/lyric-restraint.md +- **情感段密度**:冷段七成、温段两成、热段一成,热段不连续超过两段。 → references/lyric-restraint.md + +### 用最少字立人 +- **白描**:不写"他很 X",写一个等于 X 的动作,删虚词,检验动作代表性与动态密度。 → references/plain-description.md + +### 诊断与调校风格 +- **基础体温**:文本写最惨与最美的事时的默认温度就是辨识度,人物各有体温,温度反差即戏。 → references/base-temperature.md +- **声音均衡器**:风格是约三十根杠杆的合成设定而不只是用词,逐根标注、对照基线、一次只调一到三根。 → references/voice-equalizer.md + +## 引用索引 + +| 文件 | 覆盖内容 | +|---|---| +| references/sentence-rhythm.md | 句法节奏三轴:主谓先行、句长控速、模式转折(轴 2 指针),翻译腔检测与中文落地,失败模式 | +| references/abstraction-ladder.md | 抽象梯子上下爬、中段陷阱、Matalene 诊断、中文中段信号(文言腔、四字格、公文腔、意境陷阱) | +| references/rhetoric-density.md | 修辞密度与主题温度成反比、主题温度计、广岛/Koch/斯皮尔伯格对照、中文三家对照与网文规则并存 | +| references/pattern-and-break.md | 先建稳模式再打破一处:句法层模式转折 + 情感层克制中的破例,两书合并一条 | +| references/lyric-restraint.md | 抒情不抒发、抒情信号词、情感翻译成动作、情感段密度 70/20/10、用"懂"代替"说" | +| references/plain-description.md | 白描:拒绝形容词、虚词清理、动作代表性、动态密度,蒲松龄/鲁迅/海明威案例 | +| references/base-temperature.md | 基础体温:作家体温分类表、人物体温、温度一致性、温度反差即戏、温度定位技法 | +| references/voice-equalizer.md | 声音均衡器:三十杠杆清单、E.B. White 与海明威/菲茨杰拉德案例、调音三步、中文杠杆补充 | + +## 脚本 + +- references/revision-checklist.md —— 语言修辞改稿清单:句子、梯子、温度、情感、白描、体温、杠杆七遍逐项自查,附三十杠杆基线台账模板。 + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 红线 + +- 只给当前创作阶段的建议,不越权改设定主权、不绕过检测链、不复制粘贴其它 Skill 的 owner 定义。 +- 无用户明确授权不得替用户定稿或提交 Git。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/dsh/skills/prose-craft/references/_coverage.md b/framework/catalog/dsh/skills/prose-craft/references/_coverage.md new file mode 100644 index 0000000..7ae0157 --- /dev/null +++ b/framework/catalog/dsh/skills/prose-craft/references/_coverage.md @@ -0,0 +1,15 @@ +# prose-craft 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| bifeiyu-novel-skill/bifeiyu-base-temp | references/base-temperature.md | +| bifeiyu-novel-skill/bifeiyu-lyric-pass | references/lyric-restraint.md | +| bifeiyu-novel-skill/bifeiyu-lyric-pass | references/pattern-and-break.md | +| bifeiyu-novel-skill/bifeiyu-paiban | references/plain-description.md | +| writing-tools-clark/back-off-show-off | references/rhetoric-density.md | +| writing-tools-clark/ladder-of-abstraction | references/abstraction-ladder.md | +| writing-tools-clark/sentence-rhythm | references/sentence-rhythm.md | +| writing-tools-clark/sentence-rhythm | references/pattern-and-break.md | +| writing-tools-clark/voice-equalizer | references/voice-equalizer.md | diff --git a/framework/catalog/dsh/skills/prose-craft/references/abstraction-ladder.md b/framework/catalog/dsh/skills/prose-craft/references/abstraction-ladder.md new file mode 100644 index 0000000..3df5f73 --- /dev/null +++ b/framework/catalog/dsh/skills/prose-craft/references/abstraction-ladder.md @@ -0,0 +1,123 @@ +# 抽象梯子:在"看见"与"理解"之间上下爬 + +> 来源:《写作工具》(Roy Peter Clark《Writing Tools》)ladder-of-abstraction —— Tool 22 "Climb up and down the ladder of abstraction",借用 S. I. Hayakawa《Language in Thought and Action》的抽象梯子模型。 +> 中文中段信号(文言腔、四字格、公文腔、意境陷阱)为中文适配内容,单独成节。 + +## 原文摘录(全量) + +以下引文均出自。 + +> Beware of the middle, the rungs of the ladder where bureaucracy and technocracy lurk. Halfway up, +> teachers are referred to as full-time equivalents, and school lessons are called instructional +> units. … Carolyn Matalene taught me that when I write prose that the reader can neither see nor +> understand, I'm probably trapped halfway up the ladder. +> +> — Roy Peter Clark, *Writing Tools* (Tool 22, quoting S. I. Hayakawa's *Language in Thought and Action*) + +> Two questions will help you make this tool work. "Can you give me an example?" will drive the +> speaker down the ladder. But "What does that mean?" will carry him aloft. +> +> — Roy Peter Clark, *Writing Tools* (Tool 22) + +## 方法骨架 + +Clark 借 Hayakawa 的"抽象梯子"作为最核心的认知模型之一: + +- **梯子是垂直的**——从底部**感官可触的具体物**("沾血的刀"、"啤酒拉环"、"念珠")到顶部**指向意义的抽象词**("自由"、"尊严"、"审美体验"),语言分布在一条连续的梯子上。 +- **两个方向的操作问题**: + - **"能给我一个例子吗?"** → 把说话者/作者**往下推**,从抽象滑到具体,把概念翻译成读者能看见的物。 + - **"那是什么意思?"** → 把说话者/作者**往上推**,从具体升到抽象,把分散的物拢成一个可被引用为格言的意思。 +- **中段是雷区**——官僚话、套话、新词(中文里也包括"系统化方案"、"全方位提升"、"教学单位"、"赋能"、"抓手")都集中在梯子中段。读者**既看不见**(缺具体物)**也摸不着**(缺概念),只感到"言之无物"。 +- **健康写作 = 反复上下爬**——好作者一段中既给具体场景(下梯)又给一句能记住的判断(上梯)。坏写作**困在中段**,既不诱人也无深意。 + +这是"显示 vs 告诉"的**操作版**:不是"哪个对",而是"上下都做、配比恰当"。 + +## 书中的案例 + +### 案例 1:Carolyn Matalene 的"既看不见也摸不着"诊断() + +- **问题**:一段散文读者读后无感——既不"被感动"(没有具体物)也不"被说服"(没有概念判断)。 +- **方法的使用**:Matalene 教 Clark——**读者既看不见也理解不了**,几乎一定是困在了梯子中段。这是一条**诊断式启发法**:不分析修辞、不分析结构,先问"读者此刻看到什么?理解到什么?"两者都缺 = 卡中段。 +- **结论**:给写作者一个"自检三问"——这一段我给出**哪个能看见的物**?给出**哪个能引用的判断**?两个都缺或两者皆糊 = 立刻下梯或上梯补救。 +- **结果**:Clark 把这条作为 Tool 22 的核心警告;Carolyn Matalene 因此成为中段陷阱的"命名者"。 + +### 案例 2:Hayakawa 的"show-and-tell"与 Mickey Mantle 棒球卡() + +- **问题**:怎么向 5 岁小孩讲清"梯子"? +- **方法的使用**:Clark 借用童年回忆——**展示** 1957 年 Mickey Mantle 棒球卡 = 梯子底部(一个具体的物,一个能触摸的卡片);**讲述** Mickey 1956 年有多伟大 = 梯子往上爬(从"这张卡"到"伟大"这个意思)。一次"show-and-tell"既演示了下梯也演示了上梯。 +- **结论**:任何一段好散文都是一场微型"show-and-tell"——给一个具体物 + 把它提升为一个意思。抽象梯子不是"工具",是**所有写作的默认结构**。 +- **结果**:成为"显示-告诉配比"理论的童年原型;说明梯子不是抽象思辨,是写作者每天的肌肉动作。 + +## 操作步骤 + +1. **下梯——"能给我一个例子吗?"** + - 找一段被诊断为"太抽象"的文字(议论文段落、主题句、人物观点段)。 + - 问作者(或自己代作者问):"**能给我一个例子吗?**" + - 强制产出**至少 1 个能看见/能触摸的具体物**(物件、动作、场景、感官片段)。 + - 完成标准:段落里出现至少 1 个"只有这里才有"的具象细节;读者能闭上眼睛"看见画面"。 + - 判停条件:若作者继续用抽象词("自由"、"尊严")回答,把抽象词本身当成"物"再问一次——"自由的什么?哪一刻的尊严?穿什么衣服?在哪个房间?",直到给出具体物。 +2. **上梯——"那是什么意思?"** + - 找一段被诊断为"太散"或"只是描述"的文字(纯景物、纯对话、纯情节)。 + - 问作者(或自己代作者问):"**那是什么意思?**" + - 强制产出**至少 1 句能脱离上下文仍能成立的判断**——读者可以摘抄、引用、记住的"格言句"。 + - 完成标准:段落里出现至少 1 句**能脱离本段仍站得住**的命题(像 Tolstoy "幸福的家庭都是相似的"那种抽象判断的硬度,但不一定是 5 字)。 + - 判停条件:若作者继续描述("然后他看见……"),问"为什么这个细节重要?它指向什么?",直到给出一句可被引用的判断。 +3. **中段自检——"读者此刻既看不见也摸不着吗?"** + - 取出写完的一段,做**两项扫描**: + - **看**扫描:删去所有抽象名词后,还剩几个能看见的物?≥ 1 个 → 至少触底;0 个 → 卡中段偏顶。 + - **摸**扫描:删去所有具体描写后,还剩几句能引用的判断?≥ 1 句 → 至少触顶;0 句 → 卡中段偏底。 + - 完成标准:任何一段都至少"触底一次 + 触顶一次"——可分别在不同位置触(底部+顶部),不要求同一句同时完成。 + - 判停条件:触底触顶都不及格 = 全段卡中段 = 重写或加具体物 + 加抽象判断。 + +## 中文落地【中文适配】 + +Clark 的抽象梯子写于 2006 年美国语境,迁移到中文小说时需要本地化: + +1. **中文的"中段陷阱"更隐蔽**——中文有一套自带的"中段化"路径,Clark 未涵盖: + - **文言/半文言化**:写作者一认真就滑向"其情可悯"、"悲夫"、"呜呼"等四字/六字短语(既不具体到"父亲的手在抖"也不抽象到"存在的焦虑",而是困在文言的中段)。 + - **四字格 / 套话堆叠**:"感人至深"、"催人泪下"、"气势恢宏"等四字格是中文自带的中段;表面上"凝练",其实两边都不着地。 + - **党政公文腔入侵小说**:这是 2010 年后中文小说的**新型陷阱**——党政干部小说、行业小说里"系统化推进"、"闭环管理"、"压实责任"等新词泛滥,Clark 时代(2006)的英文没有这套。 + - **过度抒情 / "意境"陷阱**:中文写作者容易"为意境而意境"——堆叠意象(月亮/古井/白发)却从不落到一个具体动作或一个清晰判断,这恰是中段。 +2. **时代局限**:Clark 写于 2006 年,未涵盖 2010 年后兴起的**网文/微博/微信文体**——这些文体的中段陷阱形态不同(emoji 堆叠、口号化短句、梗词循环),需要单独分析。 +3. **与"语言华丽"的混淆**:中文写作者常把"抽象梯子"误读为"语言要朴素";实则**梯子与辞藻无关**——华丽辞藻(明喻、排比、骈文)同样可以下梯到具体,也可以困在中段;判断标准是**读者能看见什么 / 能记住什么**,不是词藻繁简。 + +## 失败模式(作者在书中警告) + +1. **抽象梯子"卡在中段"(ce08)**——失败模式:写作时既不"上梯"也不"下梯",一直停在"教学单位"、"全方位学习"、"系统化方案"等灰色官僚话。信号:**满纸抽象名词 + 模糊动词**;既没有任何"看得见/摸得着"的具体物,也没有任何"可被引用为格言"的高层抽象。机制:Hayakawa 抽象梯子中段是"既不诱人也无深意"的区域——读者既不被具体物抓住,也不被判断说服。**自检信号**: + - 句子充满"系统化"、"全方位"、"解决方案"、"赋能"等词; + - 删掉所有抽象词后,没有任何一个具体物; + - 也没有任何一句脱离上下文仍能成立的判断。 +2. **显示-告诉配比失调**——失败模式:整章只有"显示"(景物清单)或整章只有"告诉"(议论);读者读后**没东西可记住**(没有可摘抄的判断)或**没东西可感受**(没有可想象的画面)。机制:显示-告诉是梯子两端,**好散文是一场微型 show-and-tell**——只做一端 = 体验缺损。 + +## 边界(不适用场景) + +- **抒情诗 / 极简写作**——诗的合法位置**就在中段之上**;纯意象堆叠、拒绝下梯是诗的标准姿态。如果你写的是诗,ladder 不适用,只适用 ladder 的"上梯"动作。 +- **工具书 / 教科书**——教科书的合法位置**就在中段**("教学单位"在教育学里**就是**该被称呼的);ladder 的"中段陷阱"是针对**小说和叙事散文**的警告,不是普适铁律。 +- **极简动作戏(无抽象层需求)**——纯打斗、纯追逐、纯感官场面,ladder 没有着力点;改用镜头距离(scene-craft 域 cinematic-distances)控节奏。 +- **政府公文 / 工作报告(本就是中段)**——如果写作者**就是**要写公文(而不是想写小说),不要拿"中段陷阱"去批评;ladder 警告的是**小说里**出现公文话。 + +## 容易混淆的邻近方法 + +- 与 "show, don't tell"(Tool 27):那个管"用动作和细节显示人物",强调**不要用性格形容词**;这个管"语言在梯子上的垂直位置",既包括下梯(显示)也包括上梯(判断/格言)。**Show-don't-tell 是 ladder 的下梯部分,不是 ladder 的全部**。相关方法点归 show-and-omission 域。 +- 与 "Get the name of the dog"(Tool 14):那个管"用一个极具体的感官细节替代一千个形容词";是 ladder 下梯操作的**最锐利**版本,但只负责下梯,不负责上梯。 +- 与 "Mission statement"(Tool 40):那个是动笔前的"对内承诺书"——内容层;ladder 是单段写作的"上下爬"操作——句子层。两者不重叠。 +- 与 "Theme" / 主题:主题是**全文级**的抽象命题;ladder 是**段落级**的抽象-具象切换。主题写不好通常也卡在 ladder 中段,但**主题是 ladder 的目标**,ladder 是**到达主题的脚手架**。 +- 与声音均衡器(本包 `voice-equalizer.md`):那个管"作者声音的均衡器旋钮"(句长、人称、距离、典故、隐喻密度等 30+ 杠杆)。这个管"语言在抽象-具象之间的**垂直位置**"——是 voice 的其中一个旋钮,但有自己的独立操作逻辑(上下爬)。ladder 是 voice 的一个**重要分量**,不是全部。 +- 与退一步/进一步(本包 `rhetoric-density.md`):那个管"严肃度 × 作者在场度"的校准(广岛幸存者要克制,Koch 市长的胡闹可以炫技)。这个管"语言层级的垂直位置",**与严肃度无关**——严肃的死亡场景照样需要具体物(下梯),轻佻的喜剧照样可以有格言(上梯)。 +- 与细节马赛克(character-presentation 域 mosaic-of-detail):那把"具体到 9 类的细节"作为人物搭建的零件;ladder 是**何时下梯**的工具(需要细 → 用 mosaic);mosaic 是 ladder 下梯时的**物料来源**。 +- 与叙事模式混合(narration-pov 域 mix-narrative-modes):那个管"主线 / 折线 / 蒙太奇"等叙事模式调度;ladder 的"果仁段落"模式恰好是 mix-narrative-modes 的"上梯子"版本。 +- 与句法节奏(本包 `sentence-rhythm.md`)的搭配:上梯产出的格言句配短句刹车;抽象句与具体句的交替,就是梯子的上下爬在句子层的体现。 +- 与镜头距离(scene-craft 域 cinematic-distances)的搭配:梯子中段在哪个镜头距离上暴露最明显,中段自检就重点看哪里。 +- **本方法的地位**:抽象梯子**几乎是基础工具**——它的"两个方向提问"几乎每个场景都需要自我诊断。**先于** voice-equalizer / mosaic-of-detail 使用。 + +## 激活场景与信号 + +场景: + +1. **主题句 / 议论文体段落**——写一段"关于自由"、"关于爱"、"关于现代性"的议论,写完发现全是抽象名词堆叠,读者读后记不住任何一句话。 +2. **哲学 / 思辨小说写作**——想写一部带哲学内核的长篇(加缪式、伯恩哈德式、毕飞宇《平原》式),不知道"哲学思考怎么落到具体场景里";满稿理念满天飞,但场景空转。 +3. **描写与议论的平衡**——一段话要么从头到尾都是景物(纯下梯),要么从头到尾都是抒情判断(纯上梯);不知道何时该下、何时该上。 +4. **党政公文 / 学术风入侵小说**——议论文里出现"系统化推进"、"全方位覆盖"、"赋能场景化"等词;不知道这些是**中段陷阱信号**。 +5. **人物观点的呈现**——写一个"有思想"的角色,结果对白像论文答辩——只有抽象判断,没有具体例证;读者觉得"这人不像人,像作者在自说自话"。 + +信号:"太抽象了" / "空" / "理念悬空" / "读着读着睡着了" / "满纸抽象" / "没有画面" / "看不见摸不着" / "哲学小说怎么写" / "思辨小说" / "观念小说" / "主题先行怎么破" / "能给我个例子吗" / "给我个例子" / "具体化一下" / "怎么落" / "怎么落到一页" / "描写和议论" / "景和情" / "叙事和议论" / "夹叙夹议" / "官僚话" / "套话" / "官腔" / "新词太多" / "像政府报告" / "ladder of abstraction" / "抽象梯子" / "上梯子" / "怎么写得有深意" / "下梯子" / "由抽象到具体" / "Hayakawa" / "主题句" / "thesis statement" / "中心句太硬" / "议论太多" / "没故事" / "都是道理" / "文以载道"。 diff --git a/framework/catalog/dsh/skills/prose-craft/references/base-temperature.md b/framework/catalog/dsh/skills/prose-craft/references/base-temperature.md new file mode 100644 index 0000000..2c2f479 --- /dev/null +++ b/framework/catalog/dsh/skills/prose-craft/references/base-temperature.md @@ -0,0 +1,174 @@ +# 基础体温:找到你(和笔下人物)的辨识度 + +> 来源:《小说课》(毕飞宇)bifeiyu-base-temp —— 第 3 章,风格·辨识,难度三星,依赖要素:性格、直觉。案例来源:鲁迅冷/巴金热/张爱玲冷 + 整本书。 + +> "正如每个人都有自己的基础体温一样,每一个作家也都有他自己的基础体温。"() + +## 原文摘录 + +毕飞宇对中国现代作家的"基础体温"分类: + +| 作家 | 基础体温 | 风格关键词 | +|-----|---------|----------| +| 鲁迅 | 最低(之一) | 冷、阴、硬——"阴刚" | +| 巴金 | 最高 | 滚烫、赤子之心、赤子之情 | +| 张爱玲 | 极低 | 冰雪聪明、看透一切 | +| 沈从文 | 温 | 田园、温情 | +| 莫言 | 热 | 狂野、奔放 | +| 苏童 | 凉 | 唯美、颓废 | +| 毕飞宇本人 | 中偏冷 | 温中带冷 | + +**关键洞察**:每个作家(和每个人物)都有自己的"基础体温"——这是辨识度的核心。 + +## 方法骨架 + +**基础体温 = 你的文字散发出的"温度"**。 + +不是题材的温度——是**语言的温度**。两个作家写"死亡": + +- 鲁迅的死亡:冷峻、残酷、"死一般的寂静" +- 张爱玲的死亡:华美、苍凉、"生命是一袭华美的袍" +- 沈从文的死亡:田园、诗意 + +**你的基础体温决定你的辨识度**——读者读你的第一段就能"认出你"。 + +## 书中的案例() + +### 案例 1:鲁迅——冷/阴刚 + +- "死一般的寂静" +- "和光同尘" +- 一针见血,冷静到残酷 +- 基础体温 = 冷 + +**这种冷不是没感情——是把感情压到水底**。 + +### 案例 2:巴金——热 + +- 滚烫、赤子之心 +- 一辈子没降温 +- 基础体温 = 烫 + +### 案例 3:张爱玲——冰雪聪明 + +- 太聪明、太明白 +- 她的冷是"看穿了一切的冷" +- 基础体温 = 冷 + 通透 + +### 案例 4:莫言——狂野 + +- 狂野奔放 +- 基础体温 = 烫 + 狂 + +### 案例 5:蒲松龄《促织》——"冷中含热" + +- 整体冷(社会残酷、命运不公) +- 但有"小虫"那一段——全篇最温暖的瞬间 +- **冷是常态,热是反常——反常即戏** + +("小虫"案例在本包 `lyric-restraint.md` 与 `pattern-and-break.md` 里从"克制中的破例"角度分析;这里从温度反差角度保留,角度不同,都留。) + +## 操作步骤 + +### 步骤 1:找"你"的体温 + +问自己: + +> "我写最惨的事时,文字是什么温度?" +> "我写最美的事时,文字是什么温度?" + +- 都是冷 → 基础体温 = 冷(鲁迅型) +- 都是热 → 基础体温 = 热(巴金型) +- 冷热并存 → 复杂型(要看哪个是"默认") + +**检验**:写三段你最常用的文字,让陌生人猜"这是谁写的"——猜得到的程度 = 辨识度。 + +### 步骤 2:找"人物"的体温 + +每个人物也要有体温: + +```yaml +林冲:忍(冷+热并存) + - 表面冷(忍) + - 内心热(被逼急了会爆发) + +王熙凤:泼辣(热) + - 表面热(掌控一切) + - 内心冷(毒设相思局) + +成名:迁讷(凉) + - 表面凉(顺从) + - 内心热(为了儿子不惜一切) +``` + +**检验**:删掉所有形容词,读者能从动词/名词的温度里"感觉到"人物的体温吗? + +### 步骤 3:用"温度"检验一致性 + +你的人物有"冷"的特征吗?看看他的所有动作: + +- ❌ 林冲说"我受够了"(太直白、不像他的温度) +- ✅ 林冲默默把石头靠门(冷的、内敛的) + +**检验**:你的人物做的所有事,是不是都在"他的温度"内? + +### 步骤 4:温度的反差 = 戏剧性 + +**温度的反差是好戏**: + +``` +人物平时冷 → 突然热 = 戏 +人物平时热 → 突然冷 = 戏 +人物表面温度 ≠ 内心温度 = 戏 +``` + +**《促织》的最暖瞬间**:整篇冷,"小虫"那一段突然暖——读者瞬间被击中。 + +**检验**:你的小说里有没有"温度反差"的瞬间? + +### 步骤 5:用温度定位风格 + +确定你(和你的作品)的温度后: + +| 温度 | 适合题材 | 适合技法 | +|-----|---------|---------| +| 冷 | 残酷、批判、人性 | 白描、冰山、留白 | +| 热 | 激情、革命、爱情 | 排比、反复、呐喊 | +| 凉 | 唯美、抒情 | 慢镜头、细节 | +| 温 | 日常、人情 | 白描、对话 | +| 复杂 | 史诗、命运 | 多视角、反差 | + +## 边界 + +- **适合**:所有文学创作、风格定位 +- **不适合**:纯工具文(说明书、新闻) +- **慎用**:考试作文(要有"中立温度") + +## 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 温度不稳 | 像几个人写的 | 找到基础体温并坚持 | +| 温度单一 | 平面 | 找"温度反差"作为戏剧点 | +| 模仿别人的温度 | 没辨识度 | 找到你自己的"默认温度" | +| 人物都一个温度 | 平面 | 给主要人物不同温度 | + +## 一句话总结 + +> **你的基础体温就是你——找到它,坚持它,偶尔反它(反差即戏)。** + +## 相关方法点 + +- 与白描(本包 `plain-description.md`)配合:白描是"冷温度"的主要技法。 +- 与抒情不抒发(本包 `lyric-restraint.md`)关联:抒情节制是"冷温度"的核心。 +- 与人物命运(character-presentation 域 bifeiyu-character-fate)关联:性格决定温度。 +- 与心慈手狠(theme-and-stance 域 bifeiyu-mercy-ruth)关联:大师级的"心慈手狠"是一种"冷温度下的热"。 +- 与声音均衡器(本包 `voice-equalizer.md`)呼应:Clark 把风格拆成约三十根杠杆,其中"㉓ 立场温度(冷/热)"与"㉔ 情感强度"大致对应基础体温的位置;体温是中文本土的比喻式诊断,杠杆是工程化拆解,两套可以互相印证。 + +## 激活场景 + +1. 你的文字"读起来像 X 不像你" → 基础体温没找到 +2. 你的文字"没辨识度" → 找基础体温 +3. 你想学某个作家的写法 → 找他的基础体温 +4. 你的人物"性格不清" → 给人物一个基础体温 +5. 你写多人物/多视角 → 每个人物要不同基础体温 diff --git a/framework/catalog/dsh/skills/prose-craft/references/lyric-restraint.md b/framework/catalog/dsh/skills/prose-craft/references/lyric-restraint.md new file mode 100644 index 0000000..bf898c1 --- /dev/null +++ b/framework/catalog/dsh/skills/prose-craft/references/lyric-restraint.md @@ -0,0 +1,199 @@ +# 抒情不抒发:小说家只是"懂得" + +> 来源:《小说课》(毕飞宇)bifeiyu-lyric-pass —— 第 7 章,修辞·情感,难度四星,依赖要素:性格、直觉。案例来源:《促织》"小虫"的克制 + 整本书。 +> "克制中的破例"与《写作工具》的句法层模式转折是同一方法点,两书合并的一条在 `pattern-and-break.md`。 + +> "小说家只是'懂得',然后让读者'懂得',这个'懂'是关键。张爱玲说,因为'懂得',所以慈悲。"() + +## 原文摘录 + +蒲松龄《促织》里,成名的儿子变成了一只小促织。 + +**整篇小说用"虫"**——冷静、客观、距离感。 + +**唯独一处**——孩子跳到成名袖口那一段: + +> "壁上小虫忽跃落襟袖间。" + +**"小虫"——不是"虫",是"小虫"**。 + +**毕飞宇解读**: + +> "这是蒲松龄唯一失去冷静的时刻。……即使克制如蒲松龄,他也有失去冷静的时刻。" + +**两个克制**: + +1. 通篇用"虫"——理性、距离 +2. 唯独这里用"小虫"——感性、靠近 + +**没有直接抒情**——但读者**瞬间被击中**。 + +## 方法骨架 + +**小说的抒情 = 不抒发**。 + +**核心洞察**:小说和诗歌/散文不同——**小说家不抒发情感,只"传递"情感**。 + +``` +诗歌/散文的抒情:"我多么伤心啊!" +小说的抒情:(不写"我伤心")写一个具体动作,让读者感到伤心 +``` + +**小说家的工作**: + +- 懂得情感 +- 不直接说情感 +- 让读者**自己懂**情感 + +## 书中的案例() + +### 案例 1(指针):蒲松龄《促织》「小虫」(冰山) + +> 留白/冰山全文 owner:`show-and-omission` → [iceberg.md](../../show-and-omission/references/iceberg.md)。抒情克制要点:全篇用「虫」,唯独「小虫」一处失控。 + +### 案例 2(指针):莫泊桑《项链》「发红的手」(心慈手狠) + +> 作家立场/手软案例 owner:`theme-and-stance` → [mercy-ruth.md](../../theme-and-stance/references/mercy-ruth.md)。抒情克制要点:不写代价议论,只写「发红的手」。 + +### 案例 3:鲁迅《故乡》闰土叫"老爷" + +- 不写"我多么难过" +- 写闰土叫"老爷" + 母亲劝 + 闰土的"自我检讨" +- 读者自己懂:自然的崩溃、阶级的可怕 +- (同一案例在本包 `plain-description.md` 里从"不写形容词只写动作和对话"的角度再次引用,角度不同,两处都保留。) + +### 案例 4:曹雪芹 王熙凤"款步提衣上楼" + +- 不写"她多么爱美、多么空虚" +- 写她"款步提衣" +- 读者自己懂:欲望和伪装 + +### 案例 5:奈保尔 沃滋沃斯临死前 + +- 不写"我多么爱你" +- 沃滋沃斯把孩子搂在怀里说"那故事是假的" +- 读者自己懂:他的孤独和他的爱 + +## 操作步骤 + +### 步骤 1:识别"抒情冲动" + +写每段时问自己: + +> "我是不是在'告诉读者我很感动'?" + +- 是 → ❌ 删掉抒情段 +- 不是 → ✅ 继续 + +**关键信号**: + +- "我多么 X" +- "我感到 X" +- "我的心 X" +- "我泪流满面" +- "我无法用语言表达" + +→ **全部删掉** + +### 步骤 2:把"抒情"翻译成"动作" + +| ❌ 抒情 | ✅ 动作 | +|-------|-------| +| 我多么舍不得你 | 我转身走了三次都回来 | +| 她太美了 | 她的眼睛里有光 | +| 这个地方真荒凉 | 门口的草长到了窗台 | +| 他心里很乱 | 他的手指不停敲桌面 | +| 我很感动 | 我的眼睛湿了 | +| 我爱这个孩子 | 我每天给孩子抓萤火虫 | + +**检验**: + +- 删掉"抒情"句子后,小说还成立吗?→ ✅ 抒情是多余 +- 删掉"动作"句子后,小说还成立吗?→ ❌ 动作是必要 + +### 步骤 3:克制中的"破例" + +**最高级的抒情** = 通篇克制 + **唯一一次的"破例"**: + +``` +《促织》:通篇"虫" + 唯一"小虫" +《项链》:通篇冷静 + 唯一"发红的手" +《红楼梦》王熙凤:通篇优雅 + 唯一"款步提衣" +``` + +**破例 = 满盘皆输中的一子**——读者瞬间被击中。 + +**检验**:你的小说有没有"克制 + 破例"的瞬间? + +(本步骤与 Clark 的句法层模式转折是同一方法点,两书合并的完整条目见 `pattern-and-break.md`。) + +### 步骤 4:用"懂"代替"说" + +**小说家的工作**: + +> "我懂这个情感,我不需要说它——我让读者也懂。" + +**张爱玲**:"因为懂得,所以慈悲。" + +**操作方法**: + +- 写一个具体动作 +- 不解释、不抒情 +- 留一个"空"让读者填 + +**检验**: + +- 读者读完后会"啊我懂了"→ 抒情到位 +- 读者读完后"你告诉我什么"→ 抒情失败 + +### 步骤 5:检验"情感段"密度 + +小说里**情感段不能太密**——多了就滥: + +```yaml +冷段 70% +温段 20%(过渡) +热段 10%(爆点) + +热段不能连续 2 段以上 +冷段不能连续 10 段以上(读者会累) +``` + +**检验**:你的小说里"热段"是不是**短而有力**? + +## 边界 + +- **适合**:所有虚构叙事 +- **特别适合**:悲剧、现实主义 +- **慎用**:意识流(它恰恰要直接抒情) +- **不适用**:纯散文、纯抒情诗 + +## 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 抒情直白 | 像散文 | 改用动作 | +| 抒情太密 | 滥情 | 情感段 ≤ 10% | +| 没有"破例" | 平面 | 加一个"克制中的破例" | +| 抒情变说教 | 主题先行 | 删掉说教,只留动作 | +| 抒情用"形容词" | 假 | 用"动词+名词" | + +## 一句话总结 + +> **小说家不告诉读者"我感动"——小说家让读者"自己感动"。** + +## 相关方法点 + +- 与冰山理论(show-and-omission 域 bifeiyu-iceberg)同源:抒情不抒发 = 冰山理论在情感上的应用。 +- 与白描(本包 `plain-description.md`)配合:白描是抒情不抒发的主要技法。 +- 与基础体温(本包 `base-temperature.md`)关联:基础体温决定"抒情的方式"。 +- 与心慈手狠(theme-and-stance 域 bifeiyu-mercy-ruth)关联:心慈手狠 = 抒情不抒发的高级形态。 +- 与退一步/进一步(本包 `rhetoric-density.md`)呼应:重大场景两者都要求作者退后、让动作说话。 + +## 激活场景 + +1. 你的人物"该抒情了"但你写出来像散文 → 改用"具体动作" +2. 你写了"我多么 X" → 删掉,改用一个动作 +3. 你的情感段"太直白" → 用"克制"代替 +4. 你的悲剧"不够悲" → 删掉抒情,让动作说话 +5. 你想"感动读者" → 不要感动他——让他自己感动 diff --git a/framework/catalog/dsh/skills/prose-craft/references/pattern-and-break.md b/framework/catalog/dsh/skills/prose-craft/references/pattern-and-break.md new file mode 100644 index 0000000..6d6d830 --- /dev/null +++ b/framework/catalog/dsh/skills/prose-craft/references/pattern-and-break.md @@ -0,0 +1,94 @@ +# 先建稳模式,再打破一处:模式转折与克制中的破例 + +> 本条为两书合并的方法点(同一方法点多书出现,合并一条、保留各书视角与引文): +> - 《写作工具》(Roy Peter Clark《Writing Tools》)sentence-rhythm —— Tool 8,句法层的模式转折(pattern-twist); +> - 《小说课》(毕飞宇)bifeiyu-lyric-pass —— 情感层的"克制中的破例"。 +> +> 合并理由:两条说的是同一门手艺——先建立稳固模式,再在关键处故意打破一次,打破处获得额外分量。Clark 用在句子层,毕飞宇用在情感层。 + +## 方法原则 + +- 先用平行、重复、克制(句式、节奏、词汇、意象,或通篇的称呼与冷静)建立稳固模式,让读者形成预期; +- 在结尾或关键处故意"反一手"——换词、变奏、加异常、靠近一次; +- 打破的那一处获得超出模式本身的额外强调或情感冲击; +- **只在关键处用**——高潮、转折点、情感峰值;不是每段都转折,通篇克制破得太多就等于没有破。 + +这是"出人意料"的高效版本:意外感来自你亲手建立的模式,不是不可预测的奇袭。 + +## Clark 的句法层:模式转折() + +### 原文摘录 + +> A pure parallel construction would be "Boom, boom, boom." Parallelism with a twist gives us +> "Boom, boom, bang." ... By breaking the pattern, he lends more emphasis to the final element. +> +> — Roy Peter Clark, *Writing Tools* (Tool 8) + +### 操作与案例 + +- 纯粹的平行结构是 "Boom, boom, boom";带转折的平行是 "Boom, boom, bang"——最后打破一处,末尾元素获得额外强调。 +- Martin Luther King《I Have a Dream》:"Let freedom ring from ... [pattern] ... from Stone Mountain of Georgia!"——最后一句打破模式,获得额外强调。 +- 判断标准(来自本方法的操作步骤):检查关键场景(高潮、转折点、情感峰值)是否有"模式-转折";每个关键场景至少有 1 处"建立模式 + 打破"的结构;**不是每段都要"模式转折",只在关键处用**。 + +## 毕飞宇的情感层:克制中的破例() + +### 原文摘录:《促织》的"虫"与"小虫" + +蒲松龄《促织》里,成名的儿子变成了一只小促织。 + +**整篇小说用"虫"**——冷静、客观、距离感。 + +**唯独一处**——孩子跳到成名袖口那一段: + +> "壁上小虫忽跃落襟袖间。" + +**"小虫"——不是"虫",是"小虫"**。 + +**毕飞宇解读**: + +> "这是蒲松龄唯一失去冷静的时刻。……即使克制如蒲松龄,他也有失去冷静的时刻。" + +**两个克制**: + +1. 通篇用"虫"——理性、距离 +2. 唯独这里用"小虫"——感性、靠近 + +**没有直接抒情**——但读者**瞬间被击中**。 + +### 三部作品的破例样式 + +**最高级的抒情** = 通篇克制 + **唯一一次的"破例"**: + +``` +《促织》:通篇"虫" + 唯一"小虫" +《项链》:通篇冷静 + 唯一"发红的手" +《红楼梦》王熙凤:通篇优雅 + 唯一"款步提衣" +``` + +**破例 = 满盘皆输中的一子**——读者瞬间被击中。 + +**检验**:你的小说有没有"克制 + 破例"的瞬间? + +## 中文形式【中文适配】 + +"先建模式再打破"在中文里有特殊形式(来自 的本地化注记): + +- **四字格堆叠 + 突然短句**:"他走了 / 没有回头。" +- **对仗 + 打破**:"长亭外,古道边,芳草碧连天" + "他死了。" + +## 判断标准与常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 到处打破 | 模式没建起来,打破处没有分量 | 先把模式建够,只留一处打破 | +| 只有模式没有打破 | 单调催眠,没有意外 | 在关键处加一处反手 | +| 在非关键处用 | 强调被稀释 | 只在高潮、转折、情感峰值用 | +| 破例超过一次 | 破例贬值,走向滥情 | 通篇只留唯一一次,把最重的一击留给它 | + +(Clark 明确"不是每段都要模式转折";毕飞宇的破例纪律是"唯一一次"——两条出处一致,都指向同一件事:打破的分量来自稀缺。) + +## 激活信号 + +- "boom boom bang" / "模式转折" / "pattern-twist" / "平行结构" +- "克制中的破例" / "破例" / "小虫" / "唯一一次" +- "先建立模式再打破" / "结尾怎么来一下" diff --git a/.agent/skills/prose-craft/references/plain-description.md b/framework/catalog/dsh/skills/prose-craft/references/plain-description.md similarity index 100% rename from .agent/skills/prose-craft/references/plain-description.md rename to framework/catalog/dsh/skills/prose-craft/references/plain-description.md diff --git a/framework/catalog/dsh/skills/prose-craft/references/revision-checklist.md b/framework/catalog/dsh/skills/prose-craft/references/revision-checklist.md new file mode 100644 index 0000000..4f41c98 --- /dev/null +++ b/framework/catalog/dsh/skills/prose-craft/references/revision-checklist.md @@ -0,0 +1,100 @@ +# 语言修辞改稿清单(prose-craft) + +用法:初稿完成后按七遍顺序逐项过。每遍只列判断标准,方法细节与案例见对应 references/ 文件。不是每遍每次都用:句子遍、情感遍几乎必用,杠杆遍只在长篇风格出问题时用。 + +## 第一遍:句子(references/sentence-rhythm.md) + +- [ ] 每句的主谓位置已用 X 光标出(X 光 = 结构化透视标记,逐句标出主语和动词的落点),再判断先行还是远置 +- [ ] 每段 70% 以上句子主谓先行;主谓远置只出现在悬念、发现、庄重处 +- [ ] 主谓远置没有越过警戒线(英文 18 词分隔 = 致命;中文以"读者要不要回头重读"为准) +- [ ] 相邻五句至少出现三种不同长度;没有短-短-短或长-长-长的单轨 +- [ ] 每段至少一个短句刹车;中文长句用句号刹车,不用逗号连拖 +- [ ] 翻译腔三信号为零:"是"字句不超标、被动不滥用、没有长定语后置 +- [ ] 关键场景(高潮、转折、情感峰值)至少一处"建立模式 + 打破"(references/pattern-and-break.md) + +## 第二遍:梯子(references/abstraction-ladder.md) + +- [ ] 每段至少触底一次:删掉抽象名词后还剩至少一个看得见的物 +- [ ] 每段至少触顶一次:删掉具体描写后还剩至少一句可引用的判断 +- [ ] 中段信号词扫描零命中:"系统化 / 全方位 / 解决方案 / 赋能 / 抓手"、四字格套话("感人至深""催人泪下""气势恢宏")、半文言("其情可悯""呜呼""悲夫")、公文腔("闭环管理""压实责任") +- [ ] 意境式意象(月亮、古井、白发)都落到了一个具体动作或一句清晰判断上 +- [ ] "太抽象"的段落问过"能给我一个例子吗",直到给出具体物;"太散"的段落问过"那是什么意思",直到给出可引用的判断 + +## 第三遍:温度(references/rhetoric-density.md) + +- [ ] 当前场景严肃度打了 1-10 分(10 = 亲人死亡、战争屠杀;1 = 日常打趣);评分犹豫时按默认保守(更克制) +- [ ] 修辞密度与温度成反比:温度 8-10 → 密度 2-3;温度 5-7 → 密度 5-6;温度 1-4 → 密度 8-10 +- [ ] 重大场景自检:让一个广岛幸存者来读这段,他会觉得用力过猛吗?会就更克制 +- [ ] 日常场景自检:放进 Koch 式胡闹场景够炫技吗?不够就加修辞 +- [ ] 网文 / 爽文提示:反比不是铁律(莫言"重说重"同样成立,关键是与主题匹配),但重场景保留克制工具 + +## 第四遍:情感(references/lyric-restraint.md) + +- [ ] 直白抒情信号词零命中:"我多么 X""我感到 X""我的心 X""我泪流满面""我无法用语言表达" +- [ ] 每删一处抒情都换成了一个动作;删掉抒情句小说仍成立(抒情多余),删掉动作句小说不成立(动作必要) +- [ ] 全篇有且只有一次"克制中的破例"(references/pattern-and-break.md) +- [ ] 情感段密度:冷段约 70%、温段约 20%、热段约 10%;热段不连续超过两段,冷段不连续超过十段 + +## 第五遍:白描(references/plain-description.md) + +- [ ] 人物出场段没有"他很 X",一律改成了动作 +- [ ] 虚词清理:"的、了、着、于是、然后"能删就删;"很、非常、特别"全删;"我看到/我听到"删掉直接进画面 +- [ ] 每个白描动作能代表人物整体:换一个人物、换一个场景还成立的动作,换掉 +- [ ] 白描段至少三分之一的字是动词或名词性动作(全是名词的静态白描 = 死的描写) +- [ ] 没有拒绝一切形容词:该用"鬼魅""青灰色"就用 + +## 第六遍:体温(references/base-temperature.md) + +- [ ] 全篇默认温度已确定(看写最惨与最美的事时是什么温度),前后一致 +- [ ] 主要人物各有体温;每个人物的动作都在他的温度内(林冲不说"我受够了",他默默把石头靠门) +- [ ] 有意识地布置了温度反差:平时冷突然热/平时热突然冷/表面温度 ≠ 内心温度,至少一处 +- [ ] 温度与技法匹配:冷配白描、留白;热配排比、呐喊;凉配慢镜头、细节;温配白描、对话;复杂配多视角、反差 + +## 第七遍:杠杆(references/voice-equalizer.md) + +- [ ] 按下方台账标注至少 25 根杠杆的当前位置;长篇检查前 10 章与后 10 章的杠杆一致性(声音漂移) +- [ ] 选定基线(模仿对象或自己最满意的一章),X 光阅读 3-5 章读出基线位置表 +- [ ] 找出差值最大的 5-8 根杠杆,每次只动 1-3 根,改写 500-1000 字验证;调完反而更不像 → 回退换一根 +- [ ] 模仿纪律:只学基线的 1-2 根标志杠杆,其余保持自己的;模仿是参考不是替换 + +## 三十杠杆基线台账模板 + +复制下表,逐根填写当前稿与基线的位置(高/中/低),标出差值与是否调整。前 30 根是 Clark 原表,后 5 根是中文补充杠杆(见 references/voice-equalizer.md 中文落地节)。 + +| 杠杆 | 层 | 当前稿 | 基线 | 差值 | 是否调整 | +|---|---|---|---|---|---| +| ① 句长分布(短/中/长) | 句法 | | | | | +| ② 句型变化(主谓前置/后置) | 句法 | | | | | +| ③ 主谓位置 | 句法 | | | | | +| ④ 主动/被动比 | 句法 | | | | | +| ⑤ 修辞密度 | 句法 | | | | | +| ⑥ 段落长短 | 句法 | | | | | +| ⑦ 标点使用密度 | 句法 | | | | | +| ⑧ 词汇正式度(口语/书面) | 词汇 | | | | | +| ⑨ 抽象-具体比 | 词汇 | | | | | +| ⑩ 方言/俚语比例 | 词汇 | | | | | +| ⑪ 典故来源(古典/现代/无) | 词汇 | | | | | +| ⑫ 行业行话密度 | 词汇 | | | | | +| ⑬ 对话密度 | 声音 | | | | | +| ⑭ 引语 vs 对话比例 | 声音 | | | | | +| ⑮ 内心独白比例 | 声音 | | | | | +| ⑯ 第一/第三人称 | 声音 | | | | | +| ⑰ 人物视角距离 | 声音 | | | | | +| ⑱ 视觉细节 | 感官 | | | | | +| ⑲ 听觉细节 | 感官 | | | | | +| ⑳ 嗅觉/触觉/味觉 | 感官 | | | | | +| ㉑ 修辞(明喻/暗喻)密度 | 感官 | | | | | +| ㉒ 距离(远/近) | 修辞 | | | | | +| ㉓ 立场温度(冷/热) | 修辞 | | | | | +| ㉔ 情感强度 | 修辞 | | | | | +| ㉕ 节奏点(短句爆点) | 修辞 | | | | | +| ㉖ 框架方式(全知/限知) | 修辞 | | | | | +| ㉗ 章节切分 | 结构 | | | | | +| ㉘ 空白使用 | 结构 | | | | | +| ㉙ 章节标题风格 | 结构 | | | | | +| ㉚ 段首句惯例 | 结构 | | | | | +| 补1 对仗/骈文密度 | 中文补充 | | | | | +| 补2 四字格/成语密度 | 中文补充 | | | | | +| 补3 七字句/五言节奏点 | 中文补充 | | | | | +| 补4 语气词密度(呢/啊/吧/嗯) | 中文补充 | | | | | +| 补5 标点中文化(顿号、省略号、引号) | 中文补充 | | | | | diff --git a/framework/catalog/dsh/skills/prose-craft/references/rhetoric-density.md b/framework/catalog/dsh/skills/prose-craft/references/rhetoric-density.md new file mode 100644 index 0000000..dbfd81c --- /dev/null +++ b/framework/catalog/dsh/skills/prose-craft/references/rhetoric-density.md @@ -0,0 +1,106 @@ +# 修辞密度校准:退一步与进一步(back off / show off) + +> 来源:《写作工具》(Roy Peter Clark《Writing Tools》)back-off-show-off —— Tool 21 "Know when to back off and when to show off"。 +> 中文三家对照(鲁迅/张爱玲/莫言)与网文规则并存为中文适配内容,含规则冲突标注。 + +## 原文摘录(全量) + +以下引文出自。 + +> Here's a tool of thumb that works for me: The more serious or dramatic the subject, the more +> the writer backs off, creating the effect that the story tells itself. The more playful or inconsequential +> the topic, the more the writer can show off. Back off or show off. +> +> — Roy Peter Clark, *Writing Tools* (Tool 21) + +## 方法骨架 + +Clark 提出**强反直觉**的校准法则:**主题重量与修辞密度成反比**。 + +- **反直觉的核心**: + - 重大场景(严肃主题、悲剧、死亡)→ **克制**(back off)→ 简单句、短句、人物自己动作 + - 轻微场景(日常、轻佻、不重要)→ **炫技**(show off)→ 修辞、典故、声音展示 +- 判断标准:在场景的"严肃度"和写作者的"在场度"之间做校准。 +- Clark 引用两个对照案例: + - **广岛幸存者演讲**(Tool 21,严肃度极高)= "有礼貌地道歉 / 占用了我们的时间"——**最克制的开场** + - **Koch 市长胡闹**(Tool 21,严肃度极低)= 全套剧场式修辞——**最炫技的笔法** +- 机制:情感是有限资源。**重度场景 + 重度修辞 = 情感透支 → 读者反而冷漠**。严肃场景的克制反而是"高密度情感传递"。 +- 斯皮尔伯格的对照:Schindler's List 用克制(黑白 + 长镜头 + 极少台词)、《拯救大兵瑞恩》用暴露(慢镜头 + 抖动 + 大量音效)——同样严肃场景,前者有效,后者审美疲劳。 + +这是**校准决策框架**——用主题的温度计,调节写作者的"声音音量"。 + +## 书中的案例 + +### 案例 1:John Hersey《广岛》"有礼貌的开场"() + +- **问题**:写广岛原子弹爆炸幸存者,如何让读者不被"重大"压垮? +- **方法的使用**:Hersey 让 6 位幸存者各自讲述。广岛幸存者(old woman)在演讲台开始时**先为占用时间道歉**——一个"有礼貌的道歉"开篇。 +- **结论**:**重大场景最克制的开场 = 让读者"轻装进入"**。 +- **结果**:成为"克制美学"的金标准;展示了"轻说重"的力量。 + +### 案例 2:Clark 引用 Spielberg《Saving Private Ryan》对照() + +- **问题**:同样严肃场景(纳粹屠杀),不同修辞密度的对照。 +- **方法的使用**:Schindler's List = 黑白 + 长镜头 + 极少台词(克制);Saving Private Ryan = 慢镜头 + 抖动 + 大量音效(暴露)。 +- **结论**:**前者有效,后者审美疲劳**——重大场景的"轻处理"反而让读者情感到位。 +- **结果**:电影美学的对照;说明"克制"是处理重大场景的工具,不是"缺乏能力"。 + +## 操作步骤 + +1. **评估场景的"主题温度"** + - 列出当前场景:涉及什么主题?人物命运的重量?读者会期待什么情感强度? + - 完成标准:1-10 的温度评分(10 = 最严肃,如亲人死亡、战争屠杀 / 1 = 最轻,如日常打趣)。 + - 判停条件:若评分犹豫,默认保守(更克制)。 +2. **反比决定修辞密度** + - 温度 8-10:修辞密度 2-3(克制,简单句,人物自己动作,作者"不在场")。 + - 温度 5-7:修辞密度 5-6(中等,可有修辞但需谨慎)。 + - 温度 1-4:修辞密度 8-10(炫技,作者声音可大量展示)。 + - 完成标准:温度与密度成反比。 +3. **"广岛幸存者"检验** + - 写完重大场景后,问:"如果让一个广岛幸存者来读这个场景,他会觉得'用力过猛'吗?" + - 完成标准:若会,改写为更克制版本。 +4. **"Koch 市长"对照** + - 写完日常场景后,问:"如果把这段放在一个 Koch 式胡闹场景里,是否够炫技?" + - 完成标准:若否,加大修辞密度。 + +## 中文落地与规则并存【中文适配】 + +- **Clark 偏新闻克制美学**(Hersey 的《广岛》是新闻特稿),不一定适用于中文网文"虐文美学"——后者常以"重笔写重事"为美。**网文写作者应保留"克制"工具,但不必全盘照搬**。 +- **中国新文学的对照**:鲁迅的克制(《孔乙己》《示众》)+ 张爱玲的"轻说重"(《倾城之恋》"一座城的陷落成全了她的爱情")+ 莫言的"重说重"(《丰乳肥臀》)。三种笔法都成立,关键是**与主题匹配**。 + - **规则冲突标注**:莫言式"重笔写重事"与 Clark 的"主题重量与修辞密度成反比"并存冲突。Clark 的反比出自新闻克制美学,是默认值不是铁律;两条规则都保留,以"与主题匹配"为最终裁决。 +- **短视频 / 直播时代**:读者注意力更短,"修辞密度"与"严肃度"的反比关系被压缩——可能需要"快速切换"。 +- **"网络爽文"**:主题重量往往不"重",修辞密度可以"用力",Clark 的"反比"不适用——爽文有自己的"轻场景用力 / 重场景也用力"逻辑。 + +与《小说课》的呼应:毕飞宇的"抒情不抒发"(本包 `lyric-restraint.md`)在重大场景与本方法结论一致——作者退后,让动作说话。两者分工:本方法管"场景严肃度允许多少修辞",那个管"情感用什么出口传递"。 + +## 失败模式(作者在书中警告) + +1. **"严肃场景炫技"(ce09)**:失败模式是在广岛幸存者这种最严肃时刻用华丽修辞、独白、戏剧化。信号:悲剧场景里有"作者旁白独白"或"刻意感人"段落。机制:作者"不放心"读者,想用修辞"加力",但情感透支反而冷漠。预警:广岛幸存者检验失败。 +2. **"日常场景紧绷"**:失败模式是把日常场景写得像悲剧——每句都用力,每个细节都"沉重"。信号:日常对话也有"诗化"语言。机制:作者误以为"用力 = 文气",但日常场景需要炫技空间而不是紧绷。预警:整本书都是紧绷的,没有"轻下来"的时刻。 +3. **"误判严肃度"**:失败模式是误判场景温度(把轻场景当重场景)。信号:写打闹场景用庄重笔法,或写悲剧用轻佻笔法。机制:作者对"主题重量"敏感度不足。预警:Koch 市长对照失败。 + +## 边界(不适用场景) + +- **后现代反讽**——故意用"反比"作为反讽。 +- **喜剧 / 网络爆款**——喜剧本身需要"用力"或"用力装作不用力",Clark 的"严肃克制"模型不适用。 +- **实验文学**——故意打散"主题-修辞"对应关系。 +- **网络段子的快节奏**——短视频的"金句感"需要修辞密度直接拉满,不能"反比"。 + +## 容易混淆的邻近方法 + +- 与"语言节制"的区别:语言节制是"减少华丽词",back off 是"减少作者声音"。前者是词汇层,后者是叙述者层。 +- 与原型选择(character-design 域 archetype-toolkit)的区别:原型选择是"主题层"操作(说什么),back off / show off 是"修辞层"操作(怎么说)。两者可同时使用。那个管"在选定原型上如何说",这个管"给多大的声音音量"。 +- 与声音均衡器(本包 `voice-equalizer.md`)的区别:那是"整体声音的杠杆清单"(30+ 杠杆,默认设置),这个是"特定场景的修辞密度校准"(反比主题)。前者是基线,后者是局部操作;本方法是它的**一个子旋钮**。 +- 与句法节奏(本包 `sentence-rhythm.md`)的区别:那是"句法节奏"(主谓、句长、模式),这个是"修辞密度"(比喻、典故、声音的展示)。前者是微观句法,后者是宏观修辞。 + +## 激活场景与信号 + +场景: + +1. 写到"高潮场"(死亡、悲剧、告白)用了一堆华丽修辞,但读起来"用力过猛" / "俗"。 +2. 写日常向场景,反而没有"文气" / "笔力"。 +3. 写战争 / 灾难 / 重病等重大场景,担心读者疲劳。 +4. 写完一个场景后觉得"主题宏大但修辞没跟上"或"修辞宏大但主题很轻"。 +5. 网络虐文读者反应冷淡——想找原因。 + +信号:"用力过猛" / "过度修辞" / "back off" / "show off" / "如何写重大场景" / "严肃场景怎么写" / "克制" / "restraint" / "主题温度" / "日常场景怎么写" / "文气" / "修辞密度" / "读者反应冷淡" / "写得俗"。 diff --git a/framework/catalog/dsh/skills/prose-craft/references/sentence-rhythm.md b/framework/catalog/dsh/skills/prose-craft/references/sentence-rhythm.md new file mode 100644 index 0000000..431b561 --- /dev/null +++ b/framework/catalog/dsh/skills/prose-craft/references/sentence-rhythm.md @@ -0,0 +1,138 @@ +# 句法节奏三轴:主谓先行、句长控速、模式转折 + +> 来源:《写作工具》(Roy Peter Clark《Writing Tools: 55 Essential Strategies for Every Writer》)sentence-rhythm —— Tool 1(主谓先行)、Tool 18(句长控速)、Tool 8(模式转折)。源单元 frontmatter 的 source_chapter 另标注 Tool 7,但源正文无 Tool 7 的方法点,本条不含其内容。 +> 模式转折(轴 2)与《小说课》"克制中的破例"是同一方法点,两书合并的一条在 `pattern-and-break.md`,本文只留骨架与指针。 +> 本方法基于英语句法,中文落地处均标注【中文适配】。 + +## 原文摘录(全量) + +以下三处引文均出自。 + +> Rebels seized control of Cap Haitien, Haiti's second largest city, on Sunday, meeting little +> resistance as hundreds of residents cheered, burned the police station, plundered food from port +> warehouses and looted the airport, which was quickly closed. +> +> — Roy Peter Clark, *Writing Tools* (Tool 1) + +> A pure parallel construction would be "Boom, boom, boom." Parallelism with a twist gives us +> "Boom, boom, bang." ... By breaking the pattern, he lends more emphasis to the final element. +> +> — Roy Peter Clark, *Writing Tools* (Tool 8) + +> Long sentences — I sometimes call them journey sentences — create a flow that carries the reader +> down a stream of understanding, an effect that Don Fry calls "steady advance." A short sentence +> slams on the brakes. +> +> — Roy Peter Clark, *Writing Tools* (Tool 18) + +## 方法骨架:三轴系统 + +句法节奏不是玄乎的"文笔",而是三个可调度的旋钮,Clark 在这 3 个 tool 中分别处理(Tool 1 · Tool 8 · Tool 18)。 + +### 轴 1:主谓先行(Locomotive Sentence,Tool 1) + +英语的"火车头"模型:主语+动词放在句首作为**机车**,其他成分(从句、介词短语、分词)**向右拖挂**。Steinbeck 几乎每句都用此结构;Quindlen 故意把主谓拉开 31 词制造悬念。 + +- 决策规则:**默认把主谓放前**(locomotive 拉车厢)→ 清晰、动力、可读。 +- **偶尔把主谓放后**(用于悬念、发现、旅程)→ 特殊效果。 +- 关键判断:**18 个词分隔主谓 = 致命**;31 个词分隔 + 主题庄重 = 出色。 + +### 轴 2:模式转折(Pattern-Twist,Tool 8) + +平行结构(句式、节奏、词汇、意象)建立稳固模式后,在结尾或关键处故意"反一手"——换词、变奏、加异常。"Boom, boom, boom" 变成 "Boom, boom, bang"。先建稳模式,再凿一处反——是"出人意料"的高效版本,不是不可预测的奇袭。 + +此方法点在 里有情感层版本(克制中的破例),两书合并成一条,案例、判断标准与中文形式见 `pattern-and-break.md`。 + +### 轴 3:句长控速(Sentence Length,Tool 18) + +- 长句 = journey sentence = 流体力学(读者被载着走)。 +- 短句 = slam on the brakes(急刹车)。 +- **5 种句长的战略目的**: + 1. 简化复杂(simplify the complex) + 2. 制造悬念(create suspense) + 3. 聚焦情感(focus on emotional truth) + 4. 段落开头减速 / 段末加速 + 5. 一句超长 = 庄重 + +这是**句子级架构的复合框架**——把"句法"从模糊的"文笔"重新框架为可调度的三轴旋钮。 + +## 书中的案例 + +### 案例 1:Steinbeck《Cannery Row》"Doc 的潮汐作息"() + +- **问题**:写自然主义场景如何让读者"被场景裹挟"? +- **方法的使用**:Steinbeck 用连续的"主谓 + 向右分枝"句子描写海洋生物学家 Doc 的早晨——一段没有明显标点的流水句。 +- **结论**:**右分支句**在自然描写里的"流体力学"——读者像坐船一样被句子载着走。 +- **结果**:成为"句法节奏"在英文文学课中的标准范例之一;展示了"形式追随材料"。 + +### 案例 2:Polgreen《纽约时报》海地报道() + +- **问题**:战地报道开头 37 词,如何既信息密集又可读? +- **方法的使用**:"Rebels seized control ... on Sunday, meeting little resistance as hundreds of residents cheered, burned, plundered, and looted, which was quickly closed."——每个动词都是具体动作(seized, cheered, burned, plundered, looted)。"Rebels seized control"前三个词是"火车头"——抓住了全部意义。 +- **结论**:主谓先行 = 战地报道的认知优势——读者第一秒就知道"谁做了什么"。 +- **结果**:NYT 的标准战地报道起手式之一;说明了"主谓前置"的认知优势。 + +## 操作步骤 + +1. **诊断主谓位置** + - 用 X 光标出每句的主谓位置(X 光即 Clark 的 X 光阅读:戴上 X 光眼镜透视文本底下的隐形机器,这里是逐句标出主语和动词的落点),看是否"主谓先行"或"主谓远置"。 + - 完成标准:每段 70% 以上句子是"主谓先行",只有特殊效果处主谓远置(主题庄重)。 + - 判停条件:若某段主谓远置过多,改写为机车结构。 +2. **列出 5 种句长比例** + - 在要修改的段落中,标出每句的字数(中)/ 词数(英)。 + - 理想:长-短-短-长 / 短-长-短-短等"有模式"的分布,**不是**长-长-长 / 短-短-短。 + - 完成标准:5 个相邻句子里,至少 3 种不同长度。 + - 判停条件:每段必须有 1 个"短句刹车"。 +3. **模式转折检验** + - 检查关键场景(高潮、转折点、情感峰值)是否有"模式-转折"。 + - 完成标准:每个关键场景至少有 1 处"建立模式 + 打破"的结构。 + - 判停条件:不是每段都要"模式转折",只在关键处用。 + +## 中文落地【中文适配】 + +Clark 的句法理论是英语的。中文小说作者需要本地化,不能直接套用: + +1. **"主谓先行"的中文版是"先动作后修饰"** + - 英语右分支:"She opened the door slowly."(主谓先 + 副词后) + - 中文对应:"她把门慢慢打开。"(动作+对象+方式)——而非"她缓慢地打开了那扇沉重的木门"。 + - 中文流水句(类似 Quindlen 的远置):"她走去开门,看见他站在雨里,手里拿着一束已经湿透的玫瑰,花瓣被风吹得七零八落。"——一气呵成,但 Clark 的 18 词 / 31 词界限不直接适用,中文的"语义句"比"语法句"长。 +2. **"模式转折"在中文里有特殊形式** + - 四字格堆叠 + 突然短句("他走了 / 没有回头。") + - 对仗 + 打破("长亭外,古道边,芳草碧连天" + "他死了。") + - 详见 `pattern-and-break.md`。 +3. **"句长控速"在中文是"逗号节奏"**——中文逗号密度比英文高,长句需要"句号"而不是"逗号"来刹车。 +4. **"翻译腔"检测**——中文写作者常见的 3 个翻译腔信号:"是"字句、被动语态、长定语后置。 + +## 失败模式(作者在书中警告) + +1. **主谓远置造成"读者溺水"(ce01)**:失败模式是 30+ 词分隔主谓,但主题不庄重。信号:读完一段后读者需要回头重读。机制:人脑短时记忆容量有限(7±2 项),过长前置修饰"溢出"工作记忆。预警:翻译腔、未消化的长定语后置。 +2. **句长单轨(ce07)**:失败模式是每句话一样长(即使都很短)。信号:每段都是"短-短-短"或"长-长-长"。机制:人脑对模式敏感,模式建立就期待重复——一致句长 = 无意外 = 无效果。预警:用"短句"代替"句长变化"。 +3. **"翻译腔"**:失败模式是英文句法直接套中文——"这是一件重要的事情,涉及......"(This is an important thing that involves...)。信号:句子里"是"太多、被动语态多、长定语后置。机制:中文是"意合",英文是"形合"。预警:每个段落都从"是"开始,或每段都有"被"字。 + +## 边界(不适用场景) + +- **实验文学 / 后现代解构**——故意打破语法的项目。 +- **诗歌**——句法规则与诗不同(虽然有交集)。 +- **短抒情 / 极简文风**——短句刻意一致,反而是设计。 +- **翻译文本**——翻译要保留原语种节奏,不应强加 Clark 的英语规则。 + +## 容易混淆的邻近方法 + +- 与"短句好 / 长句坏"的简单规则的区别:Clark 不是主张"只用短句",而是主张"句长差异是修辞杠杆"。同样不是主张"主谓必须在前",而是主张"主谓位置是调度旋钮"。 +- 与"风格 = 用词"的区别:句法节奏是"句子结构层",不是"词汇层"。 +- 与声音均衡器(本包 `voice-equalizer.md`):那是"整体声音的杠杆清单"(30+ 杠杆),这个是"句法层三轴"(主谓位置、句长、模式转折)。前者是宏观,后者是微观;本方法是它的节奏子模块。 +- 与镜头距离(scene-craft 域 cinematic-distances):那是"摄影机距离"在叙事单元间的调度,这个是"句法节奏"在句子间的调度。前者是"镜头",后者是"句间"。 +- 与对话即行动(dialogue-craft 域 dialogue-as-action):那是"对话的功能化"(做事),这个是"对话的句法"(节奏)。前者管"对话做什么",后者管"对话怎么说"。 +- 与抽象梯子(本包 `abstraction-ladder.md`)的搭配:抽象句与具体句交替;上梯产出的格言句,配本方法的短句刹车最有力。 + +## 激活场景与信号 + +场景: + +1. 写完一段后觉得"读起来催眠"——句长单调,没有呼吸。 +2. 翻译腔太重,句子"主语+系动词+表语"太多,没有动作。 +3. 写长段描写,不知道何时该"刹车"放短句。 +4. 写对话后觉得"每个人的台词都一样长",没有节奏差异。 +5. 读到好句子想学,但不知道"为什么这个句子好"——Clark 的三轴可以诊断。 + +信号(用户的话里出现这些就应激活):"句法节奏" / "sentence rhythm" / "主谓先行" / "右分支句" / "locomotive sentence" / "句子太长" / "句长" / "模式转折" / "pattern-twist" / "boom boom bang" / "读者怎么读得下去" / "句子催眠" / "翻译腔" / "翻译体" / "句子读起来累" / "短句太多像在喊" / "主语和动词隔太远"。 diff --git a/framework/catalog/dsh/skills/prose-craft/references/voice-equalizer.md b/framework/catalog/dsh/skills/prose-craft/references/voice-equalizer.md new file mode 100644 index 0000000..e16b1d1 --- /dev/null +++ b/framework/catalog/dsh/skills/prose-craft/references/voice-equalizer.md @@ -0,0 +1,122 @@ +# 声音均衡器:把"风格"从神秘变工程 + +> 来源:《写作工具》(Roy Peter Clark《Writing Tools》)voice-equalizer —— Tool 23 "Tune your voice · Read stories aloud",借用写作教师 Don Fry 的"声音"定义。 +> 中文杠杆补充(对仗、四字格、节奏点、语气词、标点中文化、声调)为中文适配内容,单独成节。 + +## 原文摘录(全量) + +以下引文出自。 + +> Voice is the sum of all the strategies used by the author to create the illusion that the writer +> is speaking directly to the reader from the page. … Think of a piece of sound equipment called +> a graphic equalizer. This is the device that creates the range of sounds in an amplifier by +> providing about thirty dials or levers. +> +> — Roy Peter Clark, *Writing Tools* (Tool 23), quoting Don Fry + +## 方法骨架 + +Clark 在 Tool 23 中借用了写作教师 Don Fry 的"声音"定义,并配上一组工程比喻: + +- **声音不是人格**——它是作者**营造的"在纸上直接对读者说话"的幻觉**。三个关键词:create(创造)、illusion(幻觉)、speaking(在说话)。 +- **声音是合成效果**——由约 **30 个杠杆(dials/levers)** 同时调节而成:语言层级、口语 vs 书面语比例、句长分布、句型变化、词汇正式度、节奏、修辞密度、抽象-具体比、人物视角、对话密度、感官细节、情感强度、典故来源、距离感、立场温度、框架方式、隐喻密度、是否用方言/俚语、第一人称或第三人称、内心独白比例、引语密度、标点使用、段落长短、章节切分、甚至空格与空白…… +- **图形均衡器(Graphic Equalizer)比喻**:每个杠杆都是音响上的一个"频段旋钮",可调高调低。模仿海明威 = 看见他把"句长旋钮"压短、"形容词旋钮"调低、"感官细节旋钮"调高;模仿张爱玲 = 看见她把"对仗旋钮"调高、"感官旋钮"调中、"心理距离旋钮"近。 +- **核心操作**:列出 30 杠杆 → 选定基线作家(模仿对象或自己的稳定稿)→ 在每根杠杆上读出当前位置 → 想去的方向 → 调高/调低。 +- **关键判断**:"听起来像"不是玄学,是 30 个滑块的某种特定组合。 + +把"风格"从"做你自己 / 找到你的声音"这种**神秘口号**重新框架为**可拆解、可诊断、可调节**的工程问题——这是 Clark 整个 Tool 23 的贡献。 + +## 书中的案例() + +### 案例 1:E. B. White 11 岁在《St. Nicholas》杂志发表的故事 + +- **问题**:"作者声音"到底是后天养成,还是天生注定? +- **方法的使用**:Clark 引用同事 David McCord 的回忆:McCord 偶然读到一篇儿童故事,文中"他知道我十一岁生日那天的所有感受"——McCord 心里说"这听起来像 E. B. White",然后看署名:**Elwyn Brooks White, age 11**。 +- **结论**:White 11 岁就已经拥有"声音"——这证明声音**不是"后天学会"**而是**"被发现 + 被调谐"**。配合 graphic equalizer 模型:每个写作者生来就有这 30 个旋钮的**初始位置**(口音、家庭、阅读偏好早就塑好了),工作不是"创造声音",而是**识别初始位置 + 调试想去的方向**。 +- **结果**:Clark 用此例反对"声音是天赋"的本质主义,把"找到你的声音"从浪漫口号改成**可逆向工程的任务**——先测自己的旋钮在哪,再问想去哪。 + +### 案例 2:海明威 vs 菲茨杰拉德——同一时期不同"均衡器" + +- **问题**:模仿海明威,为什么只学到了"短句 + 不用形容词",还是不像? +- **方法的使用**:Clark 用 30 杠杆框架做对比诊断——海明威把"句长"压到 4-8 词、"感官细节(具体)"调高、"心理距离"远、"修辞密度"压低、"对话密度"中等。菲茨杰拉德则把"句长"调到 15-25 词、"修辞密度"调高、"心理距离"近、"感官细节"调中(更华丽抽象)。**表面看一个短一个长,本质是 30 个滑块的不同组合。** +- **结论**:模仿不是"抄一两个标志",而是**把目标作家的 30 个旋钮逐一读出位置**,再把自己的均衡器调到那个组合。 +- **结果**:提供了"模仿学习"的可操作路径——不再是"读 50 本找感觉",而是"读 3-5 个章节,用 X 光透视出 30 旋钮的设定"。 + +## 操作步骤 + +1. **列出 30 个杠杆(List the 30 dials)**——让用户对照下面 30 杠杆清单,逐一标注"当前我的设定(高/中/低)": + + - **句法层**:① 句长分布(短/中/长)② 句型变化(主谓前置/后置)③ 主谓位置 ④ 主动/被动比 ⑤ 修辞密度 ⑥ 段落长短 ⑦ 标点使用密度 + - **词汇层**:⑧ 词汇正式度(口语/书面)⑨ 抽象-具体比 ⑩ 方言/俚语比例 ⑪ 典故来源(古典/现代/无)⑫ 行业行话密度 + - **声音层**:⑬ 对话密度 ⑭ 引语 vs 对话比例 ⑮ 内心独白比例 ⑯ 第一/第三人称 ⑰ 人物视角距离 + - **感官层**:⑱ 视觉细节 ⑲ 听觉细节 ⑳ 嗅觉/触觉/味觉 ㉑ 修辞(明喻/暗喻)密度 + - **修辞层**:㉒ 距离(远/近)㉓ 立场温度(冷/热)㉔ 情感强度 ㉕ 节奏点(短句爆点)㉖ 框架方式(全知/限知) + - **结构层**:㉗ 章节切分 ㉘ 空白使用 ㉙ 章节标题风格 ㉚ 段首句惯例 + + - 完成标准:30 个杠杆中至少 25 个被标注。 + - 判停条件:标记为"无意识/不知道"也算一次标注(后续调试对象)。 + +2. **选定基线(Pick a baseline)** + - 问用户:**"你想模仿谁?或者你自己哪一章最满意?"**——选定一个基线文本(模仿对象的一篇,或自己最满意的一章)。 + - 用 **X 光阅读**:读 3-5 个章节,逐一标注基线在 30 杠杆上的位置。 + - 完成标准:拿到一份"基线 30 旋钮位置表"。 + - 判停条件:基线必须可读出 25+ 旋钮位置,否则换基线。 + +3. **调高调低(Tune up/down)** + - 拿当前稿的"30 杠杆位置表"和"基线 30 杠杆位置表"对比,标出差值最大的 5-8 个杠杆。 + - 选 1-3 个杠杆,做局部改写测试(改 500-1000 字),只动这一根杠杆,看是否更像基线。 + - 完成标准:完成至少 1 根杠杆的"调高/调低"测试,并通读自检"像不像基线"。 + - 判停条件:若调完 1 根杠杆后"反而更不像",**回退**,换另一根杠杆(说明那根杠杆不是主因)。 + +## 中文落地【中文适配】 + +Don Fry 的定义原属英语新闻业:Don Fry 是 Poynter 新闻研究所的写作教师,他的"30 杠杆"是为**英语非虚构**总结的。**迁移到中文小说需要补全中文特有的杠杆**: + +- **对仗 / 骈文密度**(中文独有,鲁迅/张爱玲都大量使用) +- **四字格 / 成语密度**(中文的"压缩信息"杠杆) +- **节奏点(七字句 / 五言节奏)**(中文的内在韵律感) +- **语气词密度**("呢 / 啊 / 吧 / 嗯"——决定"京味 / 沪语 / 港式") +- **标点中文化**(顿号、省略号、引号样式)——和英文杠杆系统不同 + +**时代局限(2006 年英文版)**——未涵盖**网文 / 弹幕体 / 微博体**的声音系统,这些是 2010 年后兴起的"新 30 杠杆"(括号表情、截图体、emoji 节奏点),需另行补充。 + +**盲点:无声调意识**——Don Fry 的英语杠杆不包括"声调 / 音韵",但中文有声调,中文的"对仗"+"节奏点"+"声调"构成的中文声律系统,需要在迁移时**额外补 3-5 根杠杆**。 + +## 失败模式(作者在书中警告) + +1. **把"工具"当"规则"硬套(ce17)**——以为 30 杠杆"必须**全部**调到中位",结果写出来四不像。**信号**:写完一段自检 5+ 个杠杆位置。**机制**:工具是"在多数情况下有效"的杠杆,不是"必须遵守"的规则;知道何时**不调**比知道何时**调**更难。 +2. **杠杆混乱 = 没有风格**——30 旋钮各调各的,每段声音都不一样。**信号**:同章内对话密度忽高忽低、句长分布无规律、距离感忽远忽近。**机制**:风格 = 杠杆组合的**一致性**,不是"每个杠杆都用上"。**解药**:选定基线 + 围绕基线微调,不要每根都创新。 +3. **模仿变抄袭**(未在书中明列,但属于此方法必警告)——把基线作家的"标志杠杆"(海明威短句)调到极端,自己的杠杆全部抹掉。**信号**:写出来一句,通读发现完全是海明威的句子、自己没贡献。**解药**:选基线时选 1-2 个杠杆学,其余保持自己的;**模仿是参考,不是替换**。 +4. **"教科书式"对话(ce24)**——每句对话完整、无语气词,杠杆 ⑬(对话密度)和 ⑭(口语比例)失调。详见 dialogue-craft 域 dialogue-as-action。 + +## 边界(不适用场景) + +- **单篇短文(< 2000 字)**——30 杠杆组合尚未沉淀,均衡器比喻失效,改用句法节奏(本包 `sentence-rhythm.md`)即可。 +- **学术论文 / 商业文案**——声音不是核心目标(目标是把事说清楚 / 卖出去),调音会牺牲清晰度。 +- **诗歌**——诗歌的"声音"在音步 / 韵律 / 跨行上有自己的 30 杠杆系统,与散文的杠杆不同。 +- **跨语言翻译文学**——模仿某作家的"声音",原语种的杠杆系统(如英文的句法节奏、中文的四字格对仗)无法直接迁移,会失真。 + +## 容易混淆的邻近方法 + +- **与"风格 = 用词"(误解)**——很多人以为"风格"就是"用词"——用大词 vs 小词、书面 vs 口语、典雅 vs 俚俗。但 voice-equalizer 明确:**风格 = 30 杠杆的组合**,用词只是 30 杠杆中的 3-4 根(⑧ 词汇正式度 ⑩ 方言比例 ⑪ 典故来源 ⑫ 行话密度)。只看用词是**以偏概全**。 +- **与"作者声音 = 角色声音"(混淆)**——很多中文写作教学把"声音"等同于"角色对话的口音",但 voice-equalizer 管的是**作者自己的叙述声音**(作者在纸上对读者说话的口吻),人物对话只是 30 杠杆中"对话密度 + 人物视角"两个旋钮。**作者声音 ≠ 人物声音**。 +- **与"找到自己的声音"(神秘主义)**——把"声音"当成"做你自己"的口号,反对可拆解;voice-equalizer 明确:声音**不是"找到"**而是**"调试"**,从已有的初始位置出发,调到想去的地方。 +- **与"风格 = 流派"(genre)**——流派(武侠 / 悬疑 / 科幻)是**题材 + 情节范式**,声音是**语言风格**;同一个流派可以有 30 种声音。voice-equalizer 不管流派,管语言。 +- **与退一步/进一步(本包 `rhetoric-density.md`)的区别**:那个是**单一杠杆的反比关系**——"修辞密度反比主题重要性"(轻主题用重修辞,重主题用轻修辞)。这个是**整体声音的 30 杠杆清单**——视野更大,管所有杠杆的组合,而非单杠杆的反比。back-off-show-off 是 voice-equalizer 的**一个子旋钮**。 +- **与句法节奏(本包 `sentence-rhythm.md`)的区别**:那个管**句法节奏**(短-中-长交替、句首动词、主动语态),只覆盖 30 杠杆中的"句长 / 句型 / 主谓位置"等 3-5 个旋钮。这个是**整个声音系统**——包括节奏、视角、距离、词汇、对话密度、感官、修辞等所有杠杆。sentence-rhythm 是 voice-equalizer 的**节奏子模块**。 +- **与对话即行动(dialogue-craft 域 dialogue-as-action)的区别**:那个管"对话的功能化"(推进 / 暴露 / 改变权力),是 30 杠杆中"对话密度 + 人物声音"两个旋钮的**功能论**。这个管"作者声音"的合成,人物声音是其中一环。 +- **与抽象梯子(本包 `abstraction-ladder.md`)的区别**:那个管"抽象-具体"一个**纵轴**,是 30 杠杆之一(且只占一维)。这个管 30 个杠杆的**整体并联**。 +- **与基础体温(本包 `base-temperature.md`)的呼应**:毕飞宇用一个"默认温度"抓住风格辨识度,温度大致落在 ㉓ 立场温度与 ㉔ 情感强度两根杠杆上;体温模型对中文写作者直观,杠杆模型便于精细诊断,两套互证。 +- 跨域一句话指针:与细节马赛克(character-presentation 域 mosaic-of-detail)——人物声音需要细节支撑;与镜头距离(scene-craft 域 cinematic-distances)——看声音系统在哪些镜头距离上表现;与叙事模式混合(narration-pov 域 mix-narrative-modes)——看不同叙事模式下声音如何变;与煽动事件(story-structure 域 inciting-incident)——开篇声音为全书定调。 + +## 激活场景与信号 + +场景: + +1. **风格自我诊断**——写了几万字,读起来"不像我"或"像三个人写的",但说不出哪里不对。 +2. **模仿学习**——读海明威/张爱玲/鲁迅/汪曾祺很喜欢,想在自己写作里复现那种味道,但只学了皮毛(短句 / 不用形容词 / 句号多)。 +3. **长篇声音漂移**——三十万字长篇,写到中段发现"前 10 章"和"后 10 章"语气不一样,自己没察觉,读者已经察觉。 +4. **风格定位**——新作者问"我到底是什么风格?",无工具,只能凭感觉。 +5. **跨体裁混乱**——同一人写小说和写散文,声音系统不统一,被读者评论"你写小说时像另一个人"。 + +信号:"作者声音" / "voice" / "个人风格" / "如何形成风格" / "怎么像某个作家" / "模仿海明威" / "学张爱玲" / "学鲁迅" / "声音均衡器" / "graphic equalizer" / "30 个杠杆" / "风格统一" / "声音漂移" / "写着写着不像我了" / "风格分析" / "我的风格是什么" / "找到自己的声音" / "声音不统一" / "听起来像三个人写的" / "Don Fry" / "Clark 写作工具" / "Tool 23"。 diff --git a/framework/catalog/dsh/skills/scene-craft/SKILL.md b/framework/catalog/dsh/skills/scene-craft/SKILL.md new file mode 100644 index 0000000..564186d --- /dev/null +++ b/framework/catalog/dsh/skills/scene-craft/SKILL.md @@ -0,0 +1,95 @@ +--- +name: scene-craft +description: | + 小说场景执行方法:给每个场景定使命、定详略、定进出点、定镜头距离,把相邻场景排成节奏, + 再把拼装痕迹蒙蔽掉。用户建场景、改场景、诊断场景时激活:"这个场景有什么用、场景散、 + 小说拖、场景太慢、不知道该详写还是略写、字数安排不合理、过渡生硬、场景扁平、没画面感、 + 全程中景、场景切换不自然、读者出戏、高潮没力"。 + 关键 trigger:"场景使命 / 场景任务 / scene mission / 晚进入 / 早退出 / enter late leave early / + 场景进入退出 / 场景节奏 / 场景紧凑 / 详写略写 / 字数安排 / 过渡 / 镜头距离 / 摄影机距离 / + 拉远推近 / 远景中景特写 / 鸟瞰 / 建立镜头 / cinematic distances / 没画面感 / 场景扁平 / + 全程中景 / 对质戏 / 对峙戏 / 群像戏 / 回忆与现实切换 / 突兀 / 不自然 / 拼装痕迹 / 蒙蔽 / + 读者出戏"。 + 不适用于:整体篇章结构与里程碑(用 story-structure)、对话写法(用 dialogue-craft)、 + 展示与留白的一般原则(用 show-and-omission)、视角选择与叙述模式(用 narration-pov)、 + 没有场景概念的非虚构与诗歌散文、剧本台词部分、纯抒情独白与全程单一距离的意识流章节、 + 三千字以下切不开档的极短篇。 + 与 foreshadow-payoff 交接:有「埋了没收 / 契诃夫之枪 / 铺垫债」语境 → foreshadow-payoff; + 仅「这个场景高潮没力 / 进出点弱」→ 本 Skill。 + 与 narrative-momentum 交接:跨场景章末钩子、弃读、势链归后者;单场景使命与排节奏归本 Skill。 +--- + +# 场景执行 + +场景执行解决六件事:这个场景干什么、给它多少篇幅、从哪里进从哪里出、用多远的镜头拍、相邻场景怎么排、拼装痕迹怎么藏。前三件决定场景成不成立,第四五件决定它好不好读,最后一件决定读者会不会出戏。 + +## 方法索引 + +### 定使命:这个场景干什么 + +- 一个场景只交付一个戏剧使命:一条关键事实、一个不可逆决定,或一次改变主角状态的推进;写前写后各用一句话验证,说不清就该删或并 → references/scene-mission.md +- 使命分三种(信息型 / 决策型 / 动作型),共同点是改变故事的下一步走向,不要造第四种;使命必须达到"改变故事走向"的量级 → references/scene-mission.md +- 一场塞两个以上使命就拆;整篇统计:全部有使命算通过,两个以上没使命就删或并 → references/scene-mission.md + +### 定详略:给多少篇幅 + +- 这一刻故事的核心是冲突、转变、启示就详写,核心是推进、过渡、背景就略写;详写给读者必须知道感受的,略写给读者不必知道但你自己要懂的 → references/scene-detail.md +- 不重要的过渡三个字打发,略写场景用动作词扛,字数拿"数他几字"来校准而不是照抄 → references/scene-detail.md + +### 定进出:从哪里进,从哪里出 + +- 晚进入早退出:跳过寒暄铺垫直接落在戏剧爆发那一刻,张力释放完立刻切下一场 → references/scene-entry-exit.md +- 进入问"读者现在还不知道什么",退出问"读者需要知道的都知道了吗",答案就是剪切点 → references/scene-entry-exit.md + +### 定镜头:用多远的距离拍 + +- 五档焦距各管一件事:鸟瞰交代格局、建立镜头带出场所氛围、中景处理动作对话、特写推到情绪、极端特写钉住关键细节;每写完一段问自己"我现在是哪一档" → references/scene-camera.md +- 给死亡、告白、揭露这类关键瞬间指派距离;一个场景内切换三档以上;全程中景是场景扁平的头号原因 → references/scene-camera.md + +### 排节奏:相邻场景怎么排,哪里换气 + +- 三种节奏模式(紧-紧-紧 / 详-略-详 / 略-略-详),不知道选哪个就默认详-略-详;过渡要短,是节奏的屏息 → references/scene-rhythm.md +- 全书要有快有慢:慢场景留着建氛围,长篇中段放一个鸟瞰或建立镜头给读者换气 → references/scene-rhythm.md + +### 藏拼装:别让读者看见接缝 + +- 没有"自然"的小说,都是拼装出来的;唯一值得诟病的是拼装被当场看穿 → references/scene-mystification.md +- 用桥梁叙述和细节延续掩盖接缝,禁止作者亲自跳出来替读者解读人物;收尾做一次盲测 → references/scene-mystification.md + +### 边界与误区 + +- 什么时候不要用这套方法、十一个常见误区、各书盲点与中文适配 → references/boundaries-and-pitfalls.md + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|----------| +| references/scene-mission.md | 场景使命原文引文;一场一使命与三种使命类型;写前写后一句话验证法;詹姆斯·帕特森百章一场一使命案例;一场塞三件事与零使命咖啡馆反例;场景改稿五步与统计标准 | +| references/scene-detail.md | 详略判断核心标准(冲突/转变/启示详写);四个技术(数他几字、三个字过渡、惯性场景去留、动作词概括);五个常见错误;布兰德原文引文;福特"知道一切"案例;场景诊断五问与六步执行流程 | +| references/scene-entry-exit.md | 晚进入早退出原文引文;进入跳什么、退出跳什么;读者知道/不知道两问判定剪切点;去前妻家平铺版与晚入版对照示范;进入太早三页变半页、退出太晚两页变半页反例;单场景五步执行 | +| references/scene-camera.md | 五档镜头距离原文引文与各档功能;Turn your notebook into a camera;克拉克一段四距离金标准;《哈姆雷特》独白换档案例;距离分布诊断阈值(八成可标、中景六成警告);关键瞬间指派距离;场景内切三档;长文中段换气段 | +| references/scene-rhythm.md | 三种节奏模式及选择法;好坏过渡的标准与例句;过渡是节奏的屏息;全书有快有慢(三书视角合并:慢场景的价值、统一节奏是错误、长篇中段鸟瞰换气) | +| references/scene-mystification.md | 蒙蔽三段原文引文;所有作品都是拼装;蒙蔽成功/失败征兆;作者亲临的危险与"站着喝酒";蒙蔽与欺骗的区分;间歇性认知;《荒凉山庄》成功案例;《伪币制造者》反例;菲尔丁/萨克雷小酒馆旁白极端失败;五步执行与盲测 | +| references/boundaries-and-pitfalls.md | 五个源单元的不适用场景汇总;常见误区(多使命、零使命、过渡详写、高潮写快、全程中景、为换而换、极端特写堆砌、技法展览、作者亲临等);各书盲点与时代局限;中文适配(中文段落单位、网文与对话体、留白传统、说书人说书人亲临);易混方法区分;规则冲突标注 | + +## 脚本 + +| 脚本 | 用途 | 来源 | +|------|------|------| +| references/scene-revision-checklist.md | 场景改稿五关检查清单:使命关、详略关、进出关、距离关、蒙蔽关,含全部量化阈值与判停条件 | 五个源单元的执行步骤合并 | +| references/scene-ledger-template.md | 场景台账模板:场景清单逐场登记使命、详略、字数、节奏模式、进出点、镜头距离 | /scene-mission-driven;/fiction-scene-craft;/scene-enter-late-exit-early;/cinematic-distances | + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/dsh/skills/scene-craft/references/_coverage.md b/framework/catalog/dsh/skills/scene-craft/references/_coverage.md new file mode 100644 index 0000000..8235dbc --- /dev/null +++ b/framework/catalog/dsh/skills/scene-craft/references/_coverage.md @@ -0,0 +1,19 @@ +# scene-craft 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| aspects-of-the-novel/mystification | references/scene-mystification.md | +| aspects-of-the-novel/mystification | references/boundaries-and-pitfalls.md | +| becoming-a-writer/fiction-scene-craft | references/scene-detail.md | +| becoming-a-writer/fiction-scene-craft | references/scene-rhythm.md | +| becoming-a-writer/fiction-scene-craft | references/boundaries-and-pitfalls.md | +| story-engineering/scene-enter-late-exit-early | references/scene-entry-exit.md | +| story-engineering/scene-enter-late-exit-early | references/scene-rhythm.md | +| story-engineering/scene-enter-late-exit-early | references/boundaries-and-pitfalls.md | +| story-engineering/scene-mission-driven | references/scene-mission.md | +| story-engineering/scene-mission-driven | references/boundaries-and-pitfalls.md | +| writing-tools-clark/cinematic-distances | references/scene-camera.md | +| writing-tools-clark/cinematic-distances | references/scene-rhythm.md | +| writing-tools-clark/cinematic-distances | references/boundaries-and-pitfalls.md | diff --git a/framework/catalog/dsh/skills/scene-craft/references/boundaries-and-pitfalls.md b/framework/catalog/dsh/skills/scene-craft/references/boundaries-and-pitfalls.md new file mode 100644 index 0000000..e01ad7b --- /dev/null +++ b/framework/catalog/dsh/skills/scene-craft/references/boundaries-and-pitfalls.md @@ -0,0 +1,160 @@ +# 边界与误区:什么时候不用,哪里容易摔 + +> 本文件汇总五个源单元的不适用场景、失败模式、盲点与时代局限、易混方法,并标注规则冲突。方法本体见各主题文件:[scene-mission.md](scene-mission.md)、[scene-detail.md](scene-detail.md)、[scene-entry-exit.md](scene-entry-exit.md)、[scene-camera.md](scene-camera.md)、[scene-rhythm.md](scene-rhythm.md)、[scene-mystification.md](scene-mystification.md)。 + +## 不适用场景汇总 + +**scene-mission-driven(/scene-mission-driven)** + +- 场景的进入退出技巧(用 scene-enter-late-exit-early,即本包 [scene-entry-exit.md](scene-entry-exit.md)) +- 整体结构(用 structure-* 系列,现归 story-structure) +- 中短篇/单场景——不适用,整个故事 1 个 mission + +**scene-enter-late-exit-early(/scene-enter-late-exit-early)** + +- 场景的功能诊断(用 scene-mission-driven,即本包 [scene-mission.md](scene-mission.md)) +- 文学/意识流(这些场景故意慢,节奏不是快就好) +- 中短篇单场景(没"进入/退出"问题) + +**fiction-scene-craft(/fiction-scene-craft)** + +- 用户不知道怎么写故事——那是整体写作流程问题(原书路由 story-draft-flow,现归 story-planning) +- 写非虚构/技术文档——没有"场景"概念 +- 写诗/散文——节奏逻辑不同 +- 写剧本——剧本是按场景写,每一个都是"详写",不需要"详略" +- 写长篇(> 30000 字)——短篇的"详略"在长篇里要重新设计(每章有自己的"详略") + +**cinematic-distances(/cinematic-distances)** + +- 纯抒情独白 / 内心独白为主体的章节——这种章节本身就是"全程极端特写",不需要再切距离,切了反而稀释情绪 +- 极短篇(3000 字以下)——篇幅不够切 5 档,强切会显得凌乱;用句子节奏(sentence-rhythm,现归 prose-craft)即可 +- 学术论文 / 说明文 / 新闻消息——cinematic-distances 是叙事场景的杠杆,非虚构的应用面窄(只在叙事特写、报告文学中适用) +- 剧本(用舞台指示)而非小说——剧本已经有"舞台提示"的距离感,文字部分聚焦对话;cinematic-distances 适用于剧本的"场景说明"而非对话本身 + +**mystification(/mystification)** + +- 透明性优先的场景——如科学报告、新闻报道、合同;蒙蔽在这里是反价值 +- 刻意展示"思考过程"的场景——如辩论、咨询、教育;让学生/用户看到你的思考是合法目标 +- 元小说/元艺术——故意让作者出现的作品(如《项狄传》某些段落),不适用 +- 极简风格——一条推文、一个标签,没有"拼装",蒙蔽不适用 + +## 常见误区(按来源单元) + +### 来自 scene-mission-driven(《Story Engineering》) + +1. **1 场景塞多个 mission**:决定、见反派、拿信息塞进同一场,戏剧张力稀释,读者消化不了。修:拆成多场,各背一个 mission。 +2. **0 mission 场景**:角色在咖啡馆描述环境、想了想、离开,什么都没发生。修:删,或并入相邻场景。 +3. **把 Patterson 风格当唯一正确**:一场一使命一章一场是极致做法,不是教条。 +4. **Mission 太小**:如"角色出门"——mission 必须"改变故事走向"。 +5. **Mission 太多变体**:集中于"信息/决策/动作"3 种,不要造新类。 + +### 来自 scene-enter-late-exit-early(《Story Engineering》) + +1. **进入太早**:路上、停车、电梯、打招呼全写,浪费读者时间。修:跳到读者还不知道的那一点。 +2. **退出太晚**:戏剧已结束还写思考、讨论、打电话。修:决定已做就切下一场。 +3. **所有场景都晚入早出**:失去氛围/共情建立的时间;有时 1 句寒暄是共情建立。 +4. **删过渡后场景"割裂"**:需要用"白空间/换行"维持连贯。 + +### 来自 fiction-scene-craft(《成为作家》) + +1. **过渡场景写太多**:失重,读者疲倦。修:减到 3 个字,或动作词概括。 +2. **高潮场景写太快**:离婚谈判一段对话就完了,读者没感受到张力。修:高潮详写,短句+对话+动作密集。 +3. **所有场景一个节奏**:详写详写详写 = 读者累;略写略写略写 = 读者没感觉。修:模式 2 或模式 3。 +4. **不知道详写哪些**:什么都想完整描述。修:每次只详写当前冲突的核心。 +5. **模仿字数不知判断**:数了海明威 150 字,不知道为什么是 150 不是 50 或 500。修:字数是校准,不是摹本。 +6. **"X 说 Y 说"标签**:节奏断(对话标签问题归 dialogue-craft,原书见 fiction-dialogue)。 +7. **模仿风格 / 模仿题材**:模仿别人的"详略风格"永远不像;跟着用别人的场景结构也不行(原书失败模式 ce02、f10 条)。 + +### 来自 cinematic-distances(《写作工具》) + +1. **"全程中景"**(与 ce06 / ce07 同族):写作者一辈子只用"中景"——场景扁平、读者视觉疲劳、远无交代近无情绪。**信号**:一章里 80% 段落都是"人物 + 动作 + 对话",无任何"鸟瞰 / 建立 / 特写"。**机制**:中景是"安全区",作者躲在"叙述者默认距离"里不用冒险;但读者需要空间感(远)、情绪感(近)、物件感(极近)——这些中景都给不了。 +2. **"为换而换"**:反向失败——每段都换距离,读者头晕、失去空间锚点。**信号**:段落开头变化太快,读者每次都要"重新定位我在哪";"像剪辑师抽风"。 +3. **"极端特写堆砌"**:把极端特写当"形容词 / 意象",放 20 个细节而没有鸟瞰/建立来"清空"视觉。**信号**:一段里堆 5+ 个"小物件",失去"远-近"的对比张力,读者视觉过载。 + +### 来自 mystification(《小说面面观》) + +1. **作者亲临(作者亲自解说人物)**——菲尔丁/萨克雷的"小酒馆式东拉西扯"(ce05);把读者领进幕后("A 看着不错吧——我一直都特别喜欢她")。在过去的小说中,再没有比这一点更致命的了。 +2. **视角转换太刻意**——纪德式"技法展览吞掉人物"(ce12):转换之间的解说累赘,读者太在意作者创作技法,失去对人物的兴趣,热情骤降。 +3. **"站着喝酒"姿态**——让人没工夫批评你的想法,实际上贬低了读者。这不是蒙蔽,是引诱。 + +## 盲点与时代局限(按来源单元) + +### scene-mission-driven(《Story Engineering》) + +- Mission 假设"线性故事"——闪回/非线性可能 mission 重新定义 +- Mission 假设"主角 POV"——群像/POV 切换每个场景都需 1 mission +- Mission 默认"看得见"——内心独白场景 mission 是"信息"(角色领悟) + +### scene-enter-late-exit-early(《Story Engineering》) + +- 假设读者都急——实际部分读者喜欢慢/氛围 +- 假设"快" = "好"——部分场景需要慢(回忆/情感) +- 假设只用 1 种时间感——整本书应该有时快有时慢 + +### fiction-scene-craft(《成为作家》) + +- 1934 年没有"章节"概念——短篇通常没有章节,详略靠段落 +- 不区分"文学" / "类型"——类型小说(悬疑/科幻)对详略有不同要求(类型需要"节奏卡点") +- 没考虑"网文节奏"——网络连载要求"每章必有钩子",是另一套节奏(中文适配:这一条恰好与"一场一使命"的连载排法对接,见 [scene-mission.md](scene-mission.md) 中文落地条) +- "数他几字"假设你能"感觉"——这是经验,不是技术,初学者很难 +- 不区分"叙述视角"对场景的影响——第一人称场景限制更多 + +### cinematic-distances(《写作工具》) + +- **中文段落单位不同(中文适配)**:Clark 2006 年(英文版)写的是英语文学场景;在中文小说里,"段落"长度与英文不同——5 句话的中文段落可能对应 1 段英文。所以"5 距离切换"在中文里要看**整章 / 整场景**为单位,**不是段段必切**;否则会变成"段落碎片化"。 +- **新兴形式未覆盖(中文适配)**:Clark 时代没有网文 / 微信对话体 / 弹幕小说——他不讨论这些新兴形式的距离感。但这些形式本质是"全程极端特写 + 心理活动",与传统小说的"中景叙事"形成对比,值得中文写作者对照。 +- **中文留白传统(中文适配)**:中文写作者常用"留白"代替"建立镜头"(不写场景,直接对话,让读者脑补)。两者可互补:在留白处插入一个极端特写(一个物件),比纯留白更有"锚点"。 + +### mystification(《小说面面观》) + +- 现代主义巅峰期的视角——1927 年;当时还没有"打破第四面墙"作为合法艺术手法(如品钦、巴斯) +- **西方文学中心的视角(中文适配)**:中国评书/相声中"说书人亲临"是合法传统,西方小说中不一定(详见 [scene-mystification.md](scene-mystification.md) 中文落地条) +- 对"作者亲临"的全盘否定过激——某些伟大作品(《项狄传》《一个青年艺术家的画像》)故意让作者出现,福斯特未充分讨论这种情况 + +## 规则冲突标注(都保留) + +1. **"跳过寒暄" vs "1 句寒暄是共情建立"**——同出/scene-enter-late-exit-early:主规则要求晚进入时跳过寒暄铺陈,失败模式条又警告完全删寒暄会丢掉共情建立。取舍看场景使命:推进事件就跳,推进关系就留一句。 +2. **"作者亲临是致命的" vs "说书人亲临是合法传统 / 元小说故意让作者出现"**——/mystification 的主规则与其自身盲点条(1927 年后打破第四面墙成为合法手法、中国评书传统)之间的冲突。取舍看文体约定:文体承诺了叙述者在场,亲临就不是罪。 +3. **"场景内切 3+ 距离、一段四距离是金标准" vs "中文不是段段必切"**——/cinematic-distances 的英文示范与其中文落地盲点条。取舍按语言单位:英文按段数距离,中文按整场整章数距离。 +4. **"写长篇不适用(详略要重新设计)" vs "长篇中段放鸟瞰换气段"**——/fiction-scene-craft 说的是短篇详略体系不直接套长篇;/cinematic-distances 说的是长篇距离调度。两者不是真冲突:前者管详略体系按章重建,后者管距离换气,长篇里同时成立。 + +## 易混方法与相邻区分(按来源单元) + +### scene-mission-driven + +- "Single Beat per Scene"(Snyder)——接近,但 Snyder 强调"节拍" +- "Scene-Sequel"(Dwight Swain)——是另一种结构(场景-反应),不是 mission +- "MRU"(Motivation-Reaction Unit)——是"角色心理单元",不是"场景使命" + +### scene-enter-late-exit-early + +- "Show, Don't Tell"——接近,但 Show 主要是"演示" vs "陈述"(现归 show-and-omission) +- "Scene-Sequel"(Swain)——是"场景+反应"2 段结构,不是节奏 +- "Cinematic Writing"(影视)——接近,但影视可视觉化,文字更需紧凑 + +### fiction-scene-craft + +- "三幕剧"结构——是**结构**,不是详略(现归 story-structure) +- "故事弧"(Story Arc)——是**张力曲线**,不是详略 +- "节奏卡"(Pacing Beats)——是**电影/网文术语**,类似但不同 +- 与 fiction-dialogue(现归 dialogue-craft):对话是工具,场景是框架 +- 与 fiction-opening(现归 story-structure):第一句是局部,场景是贯穿 +- 与 imitate-technique-not-style(已按合并计划裁剪):那是"学别人的字数安排",本方法是"自己判断字数";前者是模仿,后者是原创 +- 与 story-draft-flow(现归 story-planning):那是整个流程,本方法是其中场景阶段的内部技术 + +### cinematic-distances + +- 与 show, don't tell(《写作工具》Tool 27,现归 show-and-omission):show 管"用什么"(用证据代替断言),cinematic-distances 管"在哪看"(在 5 档里切换视距);一个特写段如果只 show 证据而不在正确的距离,效果有限 +- 与 mosaic-of-detail(Tool 54,现归 character-presentation):前者用"9 类细节拼人物",本方法用"5 个距离拼场景";一个专注人物,一个专注空间;两者可叠加——人物登场段可以先"建立(看见房间)+ 中景(看见人)+ 极端特写(看见他手上的戒指)" +- 与 active verbs(Tool 3,同书工具,未入本库):active verbs 是"动词力度"(句子内部),cinematic-distances 是"距离切换"(段落/场景级别);一个微观,一个中观 +- 与 pattern-twist(Tool 8,同书工具,未入本库):pattern-twist 是"先建模式再打破"(句式层),cinematic-distances 是"在 5 档里切换"(空间层);两者都可制造"裂缝"让读者注意力回弹——一个在词法层,一个在空间层 +- 与 back-off / show-off(Tool 21,现归 prose-craft):back-off/show-off 是"严肃时克制、轻松时炫技"(作者声音的音量),cinematic-distances 是"切换视距"(摄影机的距离);一个是作者的存在度,一个是读者的视距 +- 与 mix-narrative-modes(Tool 36,现归 narration-pov):那个管"**何时**跳出动作做解释/反思/独白"——是叙事模式的开关(主线 / 折线);本方法管"在 5 档距离里**现在停在哪一档**"——是空间视距的开关(远 / 中 / 近);一个是"动作里 vs 动作外",一个是"远 vs 近" +- 与 sentence-rhythm(Tool 18,现归 prose-craft):那个管句长搭配,是**时间**节奏(快/慢);本方法管视距远近,是**空间**节奏(远/近);一个是油门,一个是方向盘,可同时调但作用不同 +- 与 dialogue-as-action(Tool 26,现归 dialogue-craft):那个管对话的功能化;本方法决定"对话放在哪个距离"——对话通常在中景,情感高潮在特写;两者正交,中景对话推进情节是好的,特写对话放大情绪也是好的 + +### mystification + +- vs 沉浸式设计(Immersive Design):沉浸式追求"用户感觉不到界面",与蒙蔽相似但目标不同(蒙蔽是叙事/技术,沉浸式是产品/界面) +- vs 透明性(Transparency):透明性是反蒙蔽,故意让过程可见 +- vs 4th wall breaking(打破第四面墙):故意让作者/演员出现,是反蒙蔽 diff --git a/framework/catalog/dsh/skills/scene-craft/references/scene-camera.md b/framework/catalog/dsh/skills/scene-craft/references/scene-camera.md new file mode 100644 index 0000000..d0b14fb --- /dev/null +++ b/framework/catalog/dsh/skills/scene-craft/references/scene-camera.md @@ -0,0 +1,95 @@ +# 定镜头:五档焦距随时切换 + +> 来源单元:《写作工具》(Roy Peter Clark, *Writing Tools*)writing-tools-clark/cinematic-distances,Tool 34 · Write from different cinematic angles。 +> 本文件管"这个场景用多远的距离拍"。详略见 [scene-detail.md](scene-detail.md),长篇中段的镜头换气也收录在 [scene-rhythm.md](scene-rhythm.md),边界与误区见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> Aerial view. Establishing shot. Middle distance. Close-up. Extreme close-up. ... Simple descriptions +> of standard camera angles should help you imagine how to use your "word cameras" for a variety of +> effects. In that single paragraph, I measure at least four different distances from the author's +> camera to the subject matter. +> +> — Roy Peter Clark, *Writing Tools* (Tool 34) + +(/cinematic-distances) + +## 方法核心:五种标准距离 + +Clark 把"笔"当摄影机,把"叙事段落"当"镜头"。他给出 **5 种标准距离**,每种对应一种叙事功能:(/cinematic-distances) + +- **鸟瞰(Aerial view)**——"as if standing atop a skyscraper"——交代**位置、整体格局、世界的尺度**。读者需要"知道我们在哪里、事情多大规模"。 +- **建立镜头(Establishing shot)**——退后一步,带出**场所、氛围、时间感**。读者需要"看见这个房间 / 这条街 / 这一刻"。 +- **中景(Middle distance)**——"the common distance for most stories"——处理**人物动作、对话、互动**。是大多数叙事者的默认档位。 +- **特写(Close-up)**——"close enough to detect anger, fear, dread, sorrow, irony"——推到**情绪/心理层**。读者需要"看见人物此刻的状态"。 +- **极端特写(Extreme close-up)**——"focuses on an important detail that would be invisible from a distance"——聚焦**一个若不从极近看就看不见的细节**(流氓小指上的戒指、杯沿的唇印、鞋底的泥土)。读者需要"抓住这个物件/这个符号"。 + +Clark 的核心命令:**"Turn your notebook into a camera."**——把笔记本变成摄影机,5 档焦距随时切换。(/cinematic-distances) + +**判定方法**:每写完一段,问"**我现在用的是哪一档**"。Clark 自己的标准示范是:**一段之内出现 4 种距离**——这是高水平叙事的常规,不是炫技。(/cinematic-distances) + +**为什么大多数人只敢写中景?** 因为中景是"安全的叙述者距离",作者躲在这里不用冒险;但场景扁平、读者视觉疲劳、远无交代近无情绪。(/cinematic-distances) + +**与叙事模式开关的关系**:Tool 36 的"折线 / 不断线"是这一工具的延伸——什么时候"拉远做解释/反思"(折线),什么时候"推回场景中"(不断线),本质也是"距离切换",只是从"远-近"扩展到"内-外"。(叙述模式本身归 narration-pov 域,见/cinematic-distances) + +## 案例 + +### 案例 1:Clark 自己示范的"4+ 距离段落" + +- **问题**:写作者一辈子停在"中景安全区",写出来的场景像监控录像——读者看得见发生了什么,但**没画面感**。 +- **方法论的使用**:Clark 在 Tool 34 中给出 5 种距离,然后在**自己写的一个段落**里数出 4 种不同的距离——他把这个段落作为"金标准"示范,证明"高密度距离切换"在顶级写作中**很常见**,不是炫技。 +- **结论**:一个场景的"画面感"不靠形容词,靠**焦距调度**——读者在不同尺度上**重新看见**同一场景,获得空间感、情绪感、象征感。 +- **结果**:成为了"5 距离切换"的金标准示范;说明场景的"调度感"是**可数、可练**的工艺,不是天赋。 + +(/cinematic-distances) + +### 案例 2:莎士比亚《哈姆雷特》"生存还是毁灭"独白 + +- **问题**:主角在动作进行中需要"内心独白"——但独白会**打断动作链**;若直接插入独白,叙事节奏断裂。 +- **方法论的使用**:Shakespeare 用 cinematic-distances 解决——把镜头**从"中景"(动作)切到"极端特写"(人物心理)再切回**。独白是"特写停格",不是"另起一段"。读者在极近距离上**与哈姆雷特共呼吸**。 +- **结论**:极端特写是混合叙事模式(折线 / 不断线)的**视觉表现**——什么时候拉远(交代)、什么时候推近(情绪),由"读者此刻需要什么"决定。 +- **结果**:成为了 cinematic-distances 与 mix-narrative-modes 的**共同金标准**;说明两种工具(空间距离 / 叙事模式)在高手笔下是**同一种调度的两个面**。 + +(/cinematic-distances) + +## 可执行步骤 + +1. **诊断当前距离分布** + - 把一章/一个场景的每个段落标上"鸟瞰/建立/中景/特写/极端特写"5 档之一。 + - 完成标准:80%+ 段落被明确标上距离;无"中景含糊"(分不清是中景还是特写的)段落。 + - 判停条件:出现 ≥ 60% 中景 = **警告**,说明作者"只敢写中景",需要拉远和推近的练习。 +2. **指派关键瞬间的距离** + - 列出场中 3-5 个"情绪 / 信息 / 动作"的关键瞬间(死亡、告白、揭露、冲突顶点、回忆闪回),问"这个瞬间应该在哪一档"——**大多数作者把死亡/告白写在"中景" = 没换档**。 + - 完成标准:每个关键瞬间被指派一个明确距离(死亡=特写,战场=中景+鸟瞰,告白=特写+极端特写)。 + - 判停条件:关键瞬间仍在中景 = 重新设计段落,否则场景不会有情绪峰值。 +3. **在一个场景内切换 3+ 距离** + - 改写一个关键场景,保证一个段落或两个相邻段落内出现 **≥ 3 种距离**(常见:建立→中景→特写)。 + - 完成标准:改写后场景中可识别 3+ 距离切换;读者读后能"看见"空间(知道在哪里、人物多大距离、聚焦在哪)。 + - 判停条件:切换"为换而换" / 每段都换 5 词特写 = 矫枉过正,回头减;每个距离段至少 2-3 句再切。 +4. **可选:加一个"鸟瞰 / 建立"作节奏换气** + - 在长篇中段(读者开始疲劳处)插入 1 个**鸟瞰 / 建立镜头**段落,不带情节,只交代空间与时间——让读者"换气"。 + - 完成标准:鸟瞰/建立段不承载情节功能,只服务"读者呼吸";位置在中段 40-60% 处。 + - 判停条件:把鸟瞰当"省力"——一段不写的"空"段不叫鸟瞰,鸟瞰仍要**有具体内容**(晨光、街景、季节变化)。 + - 这一条同时是全书节奏手段,见 [scene-rhythm.md](scene-rhythm.md)。 + +(/cinematic-distances) + +## 激活场景与语言信号 + +适用范围(源单元 frontmatter「适用于」清单原样承接):小说场景戏、动作戏、对质戏、人物登场段、群像、回忆与现实切换、长篇中段的节奏"换气"段。(/cinematic-distances) + +用户会在这些情境下需要这条方法: + +1. 写一个场景戏,但读者说"读着读着走神了"——大概率**全程中景**,没在关键时刻推近或拉远。 +2. 写一段本应震撼的死亡 / 告白 / 揭露,读者只感到"信息"——情绪没推到特写,细节没收到极端特写。 +3. 写人物登场段,作者想"显示"但只会用"形容词 / 心理活动"——应该用"建立镜头 + 极端特写"代替抽象。 +4. 长篇中段读者弃读,作者想"换气"——一个"鸟瞰 / 建立镜头"段落能制造**节奏的窗口**,让读者重新定位。 +5. 写动作戏 / 战斗 / 追逐,作者发现"画面乱"——可能是 5 档切得太快,失去空间锚点,需要**先建立中景再换档**。 + +语言信号:"场景扁平 / 没画面感 / 像监控录像"、"全程中景 / 不会换距离 / 焦距不会切"、"镜头距离 / 摄影机距离 / cinematic angles / cinematic distances"、"拉远推近 / 远景中景特写 / 鸟瞰 / 建立镜头"、"读者看不到空间 / 读者走神"、"写场景像流水账 / 调度感不够"、"Turn your notebook into a camera / 把笔记本变成摄影机"、"show, don't tell 但 show 不出来"。(/cinematic-distances) + +## 中文落地(中文适配) + +- **段落单位不同**:Clark 2006 年(英文版)写的是英语文学场景;在中文小说里,"段落"长度与英文不同——5 句话的中文段落可能对应 1 段英文。所以"5 距离切换"在中文里要看**整章 / 整场景**为单位,**不是段段必切**;否则会变成"段落碎片化"。(中文适配;/cinematic-distances) +- **新兴形式对照**:Clark 时代没有网文 / 微信对话体 / 弹幕小说——这些形式本质是"全程极端特写 + 心理活动",与传统小说的"中景叙事"形成对比,中文写作者可对照理解各档位的取舍。(中文适配;/cinematic-distances) +- **留白传统互补**:中文写作者常用"留白"代替"建立镜头"(不写场景,直接对话,让读者脑补)。两者可互补:在留白处插入一个极端特写(一个物件),比纯留白更有"锚点"。(中文适配;/cinematic-distances) diff --git a/framework/catalog/dsh/skills/scene-craft/references/scene-detail.md b/framework/catalog/dsh/skills/scene-craft/references/scene-detail.md new file mode 100644 index 0000000..53aeb95 --- /dev/null +++ b/framework/catalog/dsh/skills/scene-craft/references/scene-detail.md @@ -0,0 +1,168 @@ +# 定详略:该详写还是略写,给多少字 + +> 来源单元:《成为作家》(多萝西娅·布兰德)becoming-a-writer/fiction-scene-craft,第十章 + 第八章 + 第十一章。 +> 本文件管单个场景的篇幅判断。相邻场景怎么排见 [scene-rhythm.md](scene-rhythm.md),场景该干什么见 [scene-mission.md](scene-mission.md),边界与误区见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> "我们举例说吧, 在一个五千字的短入小说中你所模仿的作者用了一百五十个字描写他的主人公生活中的不怎么重要的一天一夜。 +> 那么你呢? 或许会用三个字, 或者用一句话这样写, ' 第二天康拉德如此这般'。 +> 总的来说, 这字数有点太少了。或者尽管康拉德的夜晚和早晨就故事本身而言并不重要, +> 尽管你已经在刻画主人公方面用完了所有的空间, 一旦你开始了, 你也许需要六百字。 +> 只是因为你没法停下来不写他。 +> 你学习的那位作者如何运用那些你数过的字来进行间接描写呢? +> 他是否选择使用了一些表达动作的词, 显示他的主人公虽然当时并没有做什么事去推进故事情节发展, +> 却仍然内心丰富呢? 他为故事的结局埋下了什么线索, 让他能够回归到真正的行动上去? +> 当你能够用这种方式尽可能多地有所发现时, 你就掌握了模仿的技巧。 +> 段话, 逐句模仿你的术科。" +> +> — 多萝西娅·布兰德,《成为作家》第十章 + +(/fiction-scene-craft) + +这段原文同时给出了本文件的四个技术:数他几字(一百五十字)、不重要的过渡("第二天康拉德如此这般")、惯性场景("你也许需要六百字, 只是因为你没法停下来不写他")、动作词间接描写("表达动作的词")。 + +## 核心判断:这个场景,该详写还是略写? + +这是场景写作的中心问题。(/fiction-scene-craft) + +- **详写**:给"读者**必须**知道/感受"的内容 +- **略写**:给"读者**不需要**知道/感受"的内容(但你**自己**要懂) +- **判断标准**:这一刻,故事的核心是**什么**? + - 核心 = 冲突 / 转变 / 启示 — 详写 + - 核心 = 推进 / 过渡 / 背景 — 略写 + - 核心 = 节奏 / 呼吸 / 对比 — 看情况 + +(/fiction-scene-craft) + +注意:这把"读者必须知道/不需要知道"的尺子,和晚进入早退出的进出判断是同一把尺子——进入问"读者还不知道什么",退出问"读者已经知道什么",见 [scene-entry-exit.md](scene-entry-exit.md)。 + +## 四个具体技术(怎么决定详写/略写) + +### 技术 1:"数他几字"(模仿字数) + +- 选一个要模仿的作者,**数**他在一个场景上用了多少字 +- 比如:5000 字短篇,主人公"不重要的"一天一夜,他用了 150 字 +- 你的判断:这个字数是"够"还是"不够"? +- **关键**:不是"模仿他的字数",是"用他的字数来校准自己的判断" +- 布兰德的洞察:**好的作家能"感觉到"一个场景需要多少字**——你在练习中校准 + +(/fiction-scene-craft) + +### 技术 2:"不重要的场景用 3 个字" + +- 不重要的过渡,**3 个字**就够:"第二天。" +- 不要:"第二天早晨, 阳光透过窗帘, 照在床头的书本上, 她翻了个身, 看到手机上有三条未读消息……" +- 为什么:**读者的注意力是有限的**,不重要的场景详写 = 失重 +- 例外:如果"不重要场景"本身有**隐喻功能**(如"三天三夜的雨"),详写 + +(/fiction-scene-craft) + +### 技术 3:"必须停下来写"(惯性) + +- 有时,**一旦开始写一个场景,就停不下来** +- 即使这个场景"不重要",但你**已经**在脑子里想了很久 +- 布兰德的洞察:"你也许需要六百字, 只是因为你没法停下来不写他" +- 怎么判断:写完一个场景,看——这 600 字**删掉**会影响故事吗? + - 影响 → 留下(即使看起来不重要) + - 不影响 → 删到 3 个字 + +(/fiction-scene-craft) + +### 技术 4:"动作词代替叙述" + +- 略写的场景,不是"略去",是"用动作/感官词概括" +- 坏:"那天晚上她想了很久。" +- 好:"她把信烧了。" +- 动作词 = 1-3 个字,暗示了"想了很久 + 决定 + 行动" +- **怎么练**:每个略写场景,找 1-2 个**动作/感官**词概括 + +(/fiction-scene-craft) + +## 五个常见错误(场景写作的陷阱) + +1. **"过渡场景写太多"**——"不重要"的过渡场景详写,浪费字数,失重,读者疲倦。**修**:减到 3 个字,或"动作词概括"。 +2. **"高潮场景写太快"**——关键场景**略写**,失去力量。例子:离婚谈判,一段对话就完了——读者没感受到张力。**修**:高潮场景应该详写,短句 + 对话 + 动作密集。 +3. **"所有场景一个节奏"**——详写详写详写 = 读者累;略写略写略写 = 读者没感觉。**修**:用"模式 2"(详-略-详)或"模式 3"(略-略-详),见 [scene-rhythm.md](scene-rhythm.md)。 +4. **"不知道详写哪些"**——写什么都想"完整描述",没有取舍。**修**:每次只详写**当前冲突的核心**,其他略过。 +5. **"模仿别人的字数但不知道判断"**——数了海明威 150 字,但不知道**为什么**是 150,不是 50 或 500。**修**:把"数"当作**校准**,不是"模仿";问自己"这个场景,150 字够吗?" + +(/fiction-scene-craft) + +## 案例 + +### 案例 1:布兰德的"数他几字"——校准判断 + +- **问题**:不知道一个场景该用多少字 +- **方法论的使用**:选一个作者,数他每个场景的字数 +- **结论**:用**他的字数**作为校准,不是模仿 +- **结果**:学会"感觉"一个场景该用多少字 + +(/fiction-scene-craft) + +### 案例 2:布兰德的"不重要 = 3 个字"——简略过渡 + +- **问题**:过渡场景写太多,失重 +- **方法论的使用**:"不重要的过渡 = 3 个字" +- **结论**:过渡是节奏的"屏息",不是另一个场景 +- **结果**:故事节奏紧凑,详略得当 + +(/fiction-scene-craft) + +### 案例 3:福特的方法——知道一切 + +- **问题**:不知道详写哪些细节 +- **方法论的使用**:前期准备"知道"一切(即使不写到) +- **结论**:你**知道**得越多,你的**判断**越准——该详写哪些,你知道 +- **结果**:写出来的人物动作**可信**,因为作者知道每个细节 + +(/fiction-scene-craft) + +## 可执行步骤(单篇详略安排) + +1. **诊断:用户的场景问题在哪** + - 完成标准:用户能指出"我的场景是 X 问题" + - 提问:"你的场景问题是——(a) 不知道详写哪些?(b) 详写太多?(c) 过渡拖沓?(d) 高潮没力?(e) 整体一个节奏?" + - 判停条件:若用户说"我都不知道场景是什么" → 先解决整体写作流程问题(原书路由到 story-draft-flow 阶段 1,现归 story-planning) +2. **第一步:列出场景清单** + - 完成标准:用户能列出故事的所有场景(5-15 个) + - 关键:每个场景一个名字(例:"第一次见面" / "三个月后" / "重逢") +3. **第二步:给每个场景标"详/略"** + - 完成标准:每个场景标 详 或 略 + - 关键:详写场景 = 5%-15% 故事字数,略写 = 1-3 个字或一段 +4. **第三步:选节奏模式** + - 完成标准:用户能说出"我用模式 X" + - 默认:模式 2(详-略-详) + - 关键:不要全详或全略(三种模式见 [scene-rhythm.md](scene-rhythm.md)) +5. **第四步:用"动作词"略写过渡** + - 完成标准:略写场景都有 1-3 个动作/感官词 + - 例:"她把信烧了。" / "那夜雨下到天明。" +6. **第五步:用"数他几字"校准** + - 完成标准:选一个作者,数他类似场景的字数,校准自己 + - 关键:这是**校准**,不是"模仿" +7. **第六步:写完不立即重读** + - 完成标准:写完后立刻放一边,至少隔一夜再看 + - 这条纪律原挂 set-aside-the-manuscript(作者状态管理,已按合并计划裁剪,不入 skill 库),纪律本身保留 + +(/fiction-scene-craft) + +配表使用:场景逐场登记见 [../references/scene-ledger-template.md](scene-ledger-template.md)。 + +## 激活场景与语言信号 + +用户会在这些情境下需要这条方法: + +1. "我场景之间切换不好"——过渡问题 +2. "我场景写得太平"——节奏问题 +3. "我不知道该详写还是略写"——决策问题 +4. "我场景字数安排不合理"——数字问题 +5. "我故事节奏拖沓"——整体节奏问题 +6. "我场景写太多/太少"——密度问题 +7. "我描写太多/对话太多"——比例问题 +8. "我过渡生硬"——衔接问题 + +语言信号:"场景切换"、"节奏拖沓"、"详写略写"、"字数安排"、"描写太多"、"过渡生硬"、"我故事太平"、"我场景写太多"。(/fiction-scene-craft) + +## 中文落地(中文适配) + +本单元源文即中文译本,举例已落在中文语境("第二天。"、"三个月后。"、"她搬到北京那年。"、"她把信烧了。"、"那夜雨下到天明。"、"三天三夜的雨"),可直接照用。中文小说里"三个字过渡"常由单句独段或空行承担,效果等同。(中文适配;依据 becoming-a-writer/fiction-scene-craft) diff --git a/framework/catalog/dsh/skills/scene-craft/references/scene-entry-exit.md b/framework/catalog/dsh/skills/scene-craft/references/scene-entry-exit.md new file mode 100644 index 0000000..5560d37 --- /dev/null +++ b/framework/catalog/dsh/skills/scene-craft/references/scene-entry-exit.md @@ -0,0 +1,126 @@ +# 定进出:晚进入,早退出 + +> 来源单元:《Story Engineering》(Larry Brooks)story-engineering/scene-enter-late-exit-early,Part 6 · The Function of Scenes。 +> 本文件管单场景从哪里开始、在哪里结束。场景该干什么见 [scene-mission.md](scene-mission.md),详略判断见 [scene-detail.md](scene-detail.md),边界与误区见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> "Enter the scene late, leave it early. Don't make your reader sit through the pleasantries before getting to the drama. Don't make them sit through the conversation once the dramatic moment is over and resolved. This is simple, almost too simple, yet adherence to it is one of the most powerful tools in a writer's tool chest." +> +> — Larry Brooks, *Story Engineering* (2011), Part 6 + +(/scene-enter-late-exit-early) + +## 方法核心 + +进入场景时跳过所有铺垫到戏剧爆发的瞬间;退出场景时在戏剧张力释放完的瞬间立刻离开。看似太简单,却是"你放不下这本书"的最强工具之一。(/scene-enter-late-exit-early) + +**晚进入(Enter Late)**: + +- 跳过:寒暄、问候、铺陈、问候"最近如何" +- 跳到:戏剧爆发的瞬间 / 关键信息揭示 / 关键决策点 +- 例:不用写"主角走进咖啡馆, 看到朋友, 两人点单";跳到"主角说: '我查过了, 你丈夫是凶手'" + +**早退出(Leave Early)**: + +- 跳过:戏剧张力释放后的"收尾"(客套、告别、反思) +- 跳到:戏剧张力释放完的瞬间(角色做出决定 / 真相浮出) +- 例:不用写"主角说: '我决定这么做', 朋友说: '好的', 两人离开";跳到主角做出决定, 立刻切下一场景 + +(/scene-enter-late-exit-early) + +**为什么有效**: + +- 读者时间宝贵,不能浪费 +- 戏剧张力 = 读者"想知道下一步",早退场 = 把这个想知道带到下一场景 +- 进入晚 = 不浪费"读者已经知道的事" + +(/scene-enter-late-exit-early) + +**判断标准**: + +- 进入:"读者还不知道什么?" = 跳到那 +- 退出:"读者已经知道什么?" = 立刻退出 + +(/scene-enter-late-exit-early) + +这把"读者知道/不知道"的尺子和详略判断是同一把,见 [scene-detail.md](scene-detail.md)。 + +**风险**: + +- 太晚进入 = 读者"不知道发生什么" = 困惑 +- 太早退出 = 戏剧没爆发 = 场景没 mission +- 需要配合 scene-mission-driven 使用:先确认场景有东西可爆(使命),再谈从哪里剪(见 [scene-mission.md](scene-mission.md)) + +(/scene-enter-late-exit-early) + +## 案例 + +### 案例 1:书中直接对比——去前妻家 + +- **作者原书示范**:同一段(主角去前妻家),用两种方式写 +- **方式 A(平铺)**:"主角出门, 开车 10 分钟, 到了前妻家, 敲门, 前妻开门, 进屋, 坐下, 寒暄……" +- **方式 B(晚入早出)**:跳到"前妻的车在车道, 主角心沉, 决定不停下" +- **结论**:方式 B 更紧凑,戏剧更强 + +(/scene-enter-late-exit-early) + +### 案例 2:反例——进入太早 + +- **问题**:写作者 3 页写主角"开车去公司, 停车, 电梯, 跟同事打招呼, 坐下" +- **诊断**:进入过早,浪费读者时间 +- **方法**:跳到"主角到公司, 接到关键电话" +- **结果**:3 页变 0.5 页,节奏紧凑 + +(/scene-enter-late-exit-early) + +### 案例 3:反例——退出太晚 + +- **问题**:戏剧决策已做,但写作者继续写 2 页"角色思考决定, 跟助手讨论, 跟家人打电话" +- **诊断**:退出过晚,戏剧已结束 +- **方法**:跳到"决定已做, 切下一场景" +- **结果**:2 页变 0.5 页,节奏紧凑 + +(/scene-enter-late-exit-early) + +## 可执行步骤(单场景剪切) + +1. **选 1 个场景** + - 完成标准:用户指定 1 个场景 +2. **标记场景当前的开头/结尾** + - 完成标准:1 句话标"场景从这里开始"和"场景在这里结束" +3. **判断进入** + - 问"读者现在还不知道什么?" + - 答案点 = 应该是真正的进入点 + - 在那之前 = 应该删 / 并 +4. **判断退出** + - 问"读者现在需要知道的都知道了?" + - 是 = 应该是退出点 + - 在那之后 = 应该删 / 并 +5. **改稿** + - 完成标准:列出"删多少字/段" + - 注意:删不是粗暴,是用"白空间/换行"暗示场景切换 + +(/scene-enter-late-exit-early) + +## 激活场景与语言信号 + +用户会在这些情境下需要这条方法: + +1. **场景节奏优化**:"场景太慢,怎么改?" +2. **改稿**:"我场景开头/结尾太多废话" +3. **新场景建**:"场景怎么进入/退出?" +4. **教学**:"教学生写紧凑场景" + +语言信号:"晚进入 / 早退出 / enter late leave early"、"场景紧凑 / 场景节奏 / 场景不拖"、"场景开头 / 场景结尾"、"怎么进入场景 / 怎么退出场景"。(/scene-enter-late-exit-early) + +## 与相邻方法的分工 + +- **scene-mission-driven**(同包 [scene-mission.md](scene-mission.md)):管"场景功能"(做什么);本方法管"场景节奏"(快慢、剪切点)。 +- **structure-\***(现归 story-structure):管"整体结构",不管单场景剪切。 + +(/scene-enter-late-exit-early) + +## 中文落地(中文适配) + +原文说的"白空间/换行"暗示场景切换,在中文小说里对应空一行、分节符、或直接一句独立成段的时空跳转(如"三个月后。",见 [scene-rhythm.md](scene-rhythm.md) 的过渡条)。中文传统里的留白与分节天然承接晚入早出:删掉的路上工夫不写,读者自会补上。(中文适配;依据 story-engineering/scene-enter-late-exit-early 与 becoming-a-writer/fiction-scene-craft) diff --git a/framework/catalog/dsh/skills/scene-craft/references/scene-ledger-template.md b/framework/catalog/dsh/skills/scene-craft/references/scene-ledger-template.md new file mode 100644 index 0000000..c8216cc --- /dev/null +++ b/framework/catalog/dsh/skills/scene-craft/references/scene-ledger-template.md @@ -0,0 +1,23 @@ +# 场景台账模板 + +> 用途:改稿前把全部场景列成一张表,逐场登记使命、详略、进出点与镜头距离,再拿这张表去对 [scene-revision-checklist.md](scene-revision-checklist.md) 的五关。 +> 来源:/scene-mission-driven 执行步骤 1-2(列出所有场景、逐场景一句话回答使命);/fiction-scene-craft 执行步骤 2-3(列场景清单 5-15 个、每个场景一个名字、标详/略、详写占 5%-15% 字数);/scene-enter-late-exit-early 执行步骤 3-4(判断进入问"读者还不知道什么"、判断退出问"读者需要知道的都知道了吗",答案即进入点/退出点);/cinematic-distances 执行步骤 1-2(逐段标距离、关键瞬间指派距离)。 + +## 台账 + +| # | 场景名 | 使命(一句话:让故事前进了什么) | 使命类型 | 详/略 | 约字数 | 节奏模式位置 | 进入点(读者从哪一刻开始知道) | 退出点(读者知道够了就切) | 主要镜头距离 | 关键瞬间及距离 | 处置(留/删/拆/并) | +|---|--------|------------------------------|----------|-------|--------|--------------|------------------------------|--------------------------|--------------|----------------|---------------------| +| 1 | 例:第一次见面 | 例:让两人结下梁子 | 动作型 | 详 | 1200 | 详-略-详 的"详" | 例:对方开口挑衅 | 例:主角决定报复 | 建立→中景→特写 | 告白=特写+极端特写 | 留 | +| 2 | 例:三个月后 | 例:时间过渡 | ——(略写过渡) | 略 | 3-30 | 详-略-详 的"略" | —— | —— | —— | —— | 留(压到一句话) | +| 3 | | | | | | | | | | | | + +## 填表规则 + +1. **场景名**:每场一个名字("第一次见面" / "三个月后" / "重逢"),列不出名字的场景先怀疑它没有存在的理由。(/fiction-scene-craft) +2. **使命**:一句话回答"这个场景让故事前进了什么",说不清 = 无使命,处置列写"删/并";一场写出两件事 = 处置列写"拆"。(/scene-mission-driven) +3. **使命类型**:信息型 / 决策型 / 动作型 三选一,不要造第四种;内心独白场景归信息型(角色领悟)。(/scene-mission-driven) +4. **详/略与字数**:核心是冲突/转变/启示就详写,推进/过渡/背景就略写;全篇详写场景合计约占 5%-15% 字数,略写 1-3 个字或一段。(/fiction-scene-craft) +5. **节奏模式位置**:先看全篇落在紧-紧-紧 / 详-略-详 / 略-略-详 哪一种,再标每场在模式里的位置;相邻三场全详或全略 = 节奏警报。(/fiction-scene-craft) +6. **进入点/退出点**:进入 = 读者还不知道什么就跳到哪;退出 = 读者需要知道的都知道了就切。只填时刻,不填过程。(/scene-enter-late-exit-early) +7. **主要镜头距离与关键瞬间**:逐段标五档后写主档;死亡/告白/揭露这类关键瞬间单独登记指派距离,关键瞬间停在中景 = 重新设计。(/cinematic-distances) +8. **统计口径**(填完整张表后核对):无使命场景 ≥ 2 = 删或并;中景占比 ≥ 60% = 练拉远推近;高潮场被标"略" = 先改详略。(三个源单元的判停条件) diff --git a/framework/catalog/dsh/skills/scene-craft/references/scene-mission.md b/framework/catalog/dsh/skills/scene-craft/references/scene-mission.md new file mode 100644 index 0000000..99176ef --- /dev/null +++ b/framework/catalog/dsh/skills/scene-craft/references/scene-mission.md @@ -0,0 +1,125 @@ +# 定使命:一个场景只交付一件事 + +> 来源单元:《Story Engineering》(Larry Brooks)story-engineering/scene-mission-driven,Part 6 · The Function of Scenes。 +> 本文件管"这个场景干什么"。场景给多少篇幅见 [scene-detail.md](scene-detail.md),从哪里进从哪里出见 [scene-entry-exit.md](scene-entry-exit.md),边界与误区见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> "Every scene has a mission to accomplish. The mission of each scene is to deliver a single, salient, important piece of story to the reader. Less is more here. More than one bomb going off, or even a little mouse trap clicking shut, is often too much for one scene." +> +> — Larry Brooks, *Story Engineering* (2011), Part 6 + +(/scene-mission-driven) + +## 方法核心 + +每个场景必须有一个**戏剧使命(mission)**——交付一条关键信息,或做出一个关键决策,或推动一个关键情节节点。一个场景 1 个 mission;多个 mission = 戏剧张力稀释。(/scene-mission-driven) + +**Mission 的 3 种类型**: + +1. **信息型**:告诉读者一个关键事实(背景 / 真相 / 即将发生的事) +2. **决策型**:角色在场景内做出一个不可逆决定 +3. **动作型**:场景推进情节 / 改变主角状态 + +**3 类的共同点**:改变故事的下一步走向。(/scene-mission-driven) + +**为什么 1 个 mission**: + +- 多个 mission = 读者注意力分散 +- 每个 mission 都削弱其他 mission 的冲击力 +- 1 个 mission = 读者每次被打动 1 次,印象深 + +(/scene-mission-driven) + +**操作法**: + +- 写场景前,用 1 句话回答"这个场景让故事前进了什么" +- 写场景后,再用 1 句话验证 +- 说不清 = 这个场景删 / 并 + +(/scene-mission-driven) + +**使命的量级标准**:mission 必须达到"改变故事走向"的量级,"角色出门"这种不算 mission。(/scene-mission-driven) + +**反例**:"这个场景让角色思考了,之后她做决定"——思考 + 决定 = 2 mission,拆。(/scene-mission-driven) + +**内心独白场景怎么算**:mission 默认是"看得见"的,但内心独白场景也有 mission,归入信息型——角色领悟了某件事。(/scene-mission-driven) + +## 案例 + +### 案例 1:James Patterson——极致的任务驱动 + +- **方法**:每场景 1 mission,每章 1 场景,100+ 章/书 +- **Mission 例子**: + - Chapter 1:介绍主角 + - Chapter 2:介绍反派 + - Chapter 3:第一场追逐 + - Chapter 4:反派接近主角 + - …… 一直到高潮,1 mission/章 +- **结果**:验证了"每场景 1 mission"的可读性优势 + +(/scene-mission-driven) + +注意:帕特森式"一场一使命、一章一场"是极致做法,不是唯一正确的写法,见下文误区。(/scene-mission-driven) + +### 案例 2:反例——写作者 1 场景塞 3 件事 + +- **问题**:1 个场景里:(1) 角色做决定 (2) 角色见到反派 (3) 角色得到关键信息 +- **诊断**:3 mission = 戏剧张力稀释,读者消化不了 +- **方法**:拆成 3 场景,每个 1 mission +- **结果**:故事节奏加快,戏剧强度提升 + +(/scene-mission-driven) + +### 案例 3:反例——1 场景无 mission + +- **问题**:1 场景里角色在咖啡馆,描述环境,角色想,角色离开,什么都没发生 +- **诊断**:0 mission = 删 +- **方法**:删场景,或并入相邻场景 +- **结果**:小说变紧凑 + +(/scene-mission-driven) + +## 可执行步骤(整篇/整段场景改稿) + +1. **列出所有场景** + - 完成标准:用户列出当前所有场景(或一段内的所有场景) +2. **逐场景回答 mission** + - 完成标准:每个场景 1 句话:"这个场景让故事前进了什么?" + - 说不清 = 这个场景无 mission +3. **统计** + - 全有 mission = 通过 + - ≤ 1 个无 mission = 还行 + - ≥ 2 个无 mission = 改稿,删 / 并 +4. **检查 mission 数量** + - 完成标准:每个场景只 1 mission + - 有 2+ mission = 拆场景 +5. **改稿** + - 完成标准:列出"删哪些 / 拆哪些 / 并哪些" + +(/scene-mission-driven) + +配表使用:场景逐场登记可用 [../references/scene-ledger-template.md](scene-ledger-template.md),改稿逐关过用 [../references/scene-revision-checklist.md](scene-revision-checklist.md)。 + +## 激活场景与语言信号 + +用户会在这些情境下需要这条方法: + +1. **新场景建**:"我要写 1 个场景,它应该做什么?" +2. **场景诊断**:"这个场景有用吗?" +3. **节奏优化**:"我的小说拖,怎么改?" +4. **改稿**:"我写完一稿,怎么诊断场景?" + +语言信号:"场景任务 / 场景使命 / scene mission"、"这个场景有什么用 / 场景为什么"、"场景太多 / 场景散 / 小说拖"、"场景诊断 / 1 个场景 1 件事"。(/scene-mission-driven) + +## 本单元的误区提醒 + +1. **把"1 场景 1 mission"当教条**:Patterson 风格是极致做法,不是唯一正确,不要拿它苛责一切写法。(/scene-mission-driven) +2. **Mission 太小**:如"角色出门"——mission 必须"改变故事走向"才算数。(/scene-mission-driven) +3. **乱造 mission 变体**:集中于"信息 / 决策 / 动作"3 种,不要造新类。(/scene-mission-driven) + +更多边界(不适用场景、盲点、易混方法)见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 中文落地(中文适配) + +网文连载"每章必有钩子"的节奏要求(见《成为作家》单元盲点条)与"一场一使命"天然合拍:一章一场、一场一使命、章末落在使命刚完成或刚被打破的位置,就是帕特森式排法的中文连载版。(中文适配;依据 story-engineering/scene-mission-driven 与 becoming-a-writer/fiction-scene-craft) diff --git a/framework/catalog/dsh/skills/scene-craft/references/scene-mystification.md b/framework/catalog/dsh/skills/scene-craft/references/scene-mystification.md new file mode 100644 index 0000000..a629eab --- /dev/null +++ b/framework/catalog/dsh/skills/scene-craft/references/scene-mystification.md @@ -0,0 +1,121 @@ +# 藏拼装:蒙蔽读者,唯一的罪是被看穿 + +> 来源单元:《小说面面观》(E. M. 福斯特)aspects-of-the-novel/mystification,第四讲 人物(续) / 第五讲 情节。 +> 本文件管场景与视角的拼装痕迹如何不被读者察觉。边界与误区见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> "总领小说技巧的最复杂问题 (珀西·卢伯克先生如是说), 我认为是视角问题, 也就是叙事者与所叙故事之间的关系问题。在我看, 总领小说技巧的最复杂问题不在于总结几个套路公式, 而在于作者有多少能力'蒙蔽'读者, 使之信服自己所讲述的一切。" + +> "《荒凉山庄》的第一章是全知视角 …… 到了第二章, 他的视角收窄了 …… 第三章, 他更是离谱, 索性直接用上戏剧手法 …… 从逻辑上说, 《荒凉山庄》完全是碎片化的, 可狄更斯蒙蔽了我们的感知, 让我们完全不在意视角的转换。" + +> "唯一值得诟病的, 就是被我们当场察觉出转换的生硬。" +> +> — E. M. 福斯特, 《小说面面观》第四讲 人物(续) / 第五讲 情节 + +(/mystification) + +## 方法核心 + +福斯特在评论技巧中提出的**核心方法**:视角转换/扁平/圆形人物/碎片化逻辑/模式等等技术手段,真正重要的不是"我用了哪几种",而是"我有没有**蒙蔽**读者的感知,让一切显得自然"。(/mystification) + +**核心操作**: + +1. **承认"所有作品都是拼装"**——没有"自然"的作品,都有视角转换、类型切换、模式裁剪。**唯一值得诟病的不是"拼装",是"被当场察觉出拼装"**。 +2. **判断"蒙蔽"成功的征兆**: + - 读者/听众/用户感到"自然",不问"这里为什么突然换视角了" + - 即使被告知"这里有转换",也觉得"啊,确实自然,我没注意到" + - 读者/听众/用户主动跟随,不掉线 +3. **判断"蒙蔽"失败的征兆**: + - 读者/听众/用户感到"突兀" / "硬" / "不对劲" + - 主动指出"这里好像换了风格 / 这里人物怎么突然变样了" + - 注意力从内容转移到形式 +4. **危险的"作者亲临"**——福斯特明示:把读者领进幕后("A 看着不错吧——我一直都特别喜欢她","让我们来猜猜 B 为什么要这么做")破坏想象空间和尊严。"就像是只许人站着喝酒, 这样他们就没工夫批评你的想法了。" +5. **"蒙蔽"和"欺骗"的区别**——蒙蔽是"让拼装不刺眼",欺骗是"让内容失真"。前者是技术,后者是道德。 + +(/mystification) + +**关键认识**:福斯特把"蒙蔽读者"作为小说这一艺术形式的**最大优势之一**。这与现实生活的"间歇性认知"一致——我们有时候比其他人傻,我们偶尔可以理解别人的心思但并不总能如此。这种间歇性确保了我们有能力迎接更多彩多样的各色体验。**小说家对人物也是时松时紧,有冷有热**,这是合法且必要的。(/mystification) + +**具体蒙蔽手段**(给修改建议时用): + +- 在视角转换前加入一段"桥梁"叙述 +- 用细节的延续掩盖视角的切换 +- 不要空话(如"让叙述更自然")——给可操作修改 + +(/mystification,执行步骤第 3 步) + +## 案例 + +### 案例 1:狄更斯《荒凉山庄》——视角转换的蒙蔽(成功) + +- **问题**:《荒凉山庄》从全知视角(第一章)→ 收窄视角(第二章累斯特·戴洛克男爵)→ 戏剧手法(第三章埃丝特·萨默森),这种"碎片化"为什么没让读者察觉? +- **方法论的使用**:福斯特诊断——"狄更斯蒙蔽了我们的感知, 让我们完全不在意视角的转换"。从逻辑上说,这本书完全是碎片化的,但狄更斯的"蒙蔽"能力让它看起来自然 +- **结论**:蒙蔽是狄更斯的核心能力 +- **结果**:借此福斯特说明"蒙蔽"是评论小说技巧的**真正核心**,不是"我用了哪几种视角" + +(/mystification) + +### 案例 2:纪德《伪币制造者》——蒙蔽的反例 + +- **问题**:纪德也做视角转换,为什么不成功? +- **方法论的使用**:福斯特诊断——纪德的视角转换"在转换之间的解说显得累赘了",读者"太在意作者创作技法",失去对人物的兴趣 +- **结论**:纪德"放弃了对人物的创造, 只召唤我们来帮忙分析他自己的心思, 结果自然只能是叫人热情骤降" +- **结果**:借此福斯特说明,蒙蔽失败的征兆是"读者开始琢磨作者的心思" + +(/mystification) + +### 案例 3:菲尔丁/萨克雷的小酒馆式旁白——蒙蔽的极端失败 + +- **问题**:菲尔丁/萨克雷在小说中直接"东拉西扯"评论人物,这种"作者亲临"为什么是"致命的"? +- **方法论的使用**:福斯特诊断——这种"作者亲临""破坏想象空间和尊严"。"就好像是只许人站着喝酒, 这样他们就没工夫批评你的想法了。"——这不是蒙蔽,是"引诱" +- **结论**:在过去的小说中,再没有比这一点更致命的了 +- **结果**:借此福斯特划出"蒙蔽"和"诱惑/打破第四面墙"的明确边界 + +(/mystification) + +## 可执行步骤 + +1. **承认"所有作品都是拼装"** + - 完成标准:明确说出"没有'自然'的作品,都有视角转换、类型切换、模式裁剪,关键是蒙蔽质量" +2. **检测"蒙蔽失败"的具体征兆** + - 完成标准:至少标出 1 处"读者/听众/用户可能察觉的拼装痕迹" + - 提示:关注"转换的瞬间"——视角、语气、节奏、密度突然改变的地方 +3. **设计"蒙蔽"的具体手段** + - 完成标准:至少 1 条具体修改(如"在视角转换前加入一段'桥梁'叙述"或"用细节的延续掩盖视角的切换") + - 不要空话(如"让叙述更自然")——给可操作修改 +4. **避免"作者亲临"陷阱** + - 完成标准:检查"我是否亲自出现在叙述中,替读者解读人物",如有,删去 + - 福斯特明示:"A 看着不错吧——我一直都特别喜欢她"这种旁白是致命的 +5. **做"读者/听众盲测"** + - 完成标准:至少 1 个人(或 1 个独立评审)在不知道"作者意图"的情况下阅读,报告"哪里觉得突兀" + - 判停条件:如果盲测报告 0 处突兀,蒙蔽成功 + +(/mystification) + +## 激活场景与语言信号 + +用户会在这些情境下需要这条方法(原单元覆盖写作之外的演示、教学、产品场景,此处全数保留,小说场景之外用法同理): + +1. **写小说/剧本/课程/演讲**——写完前自检:"我的视角转换自然吗?" +2. **设计演示/汇报/会议**——评估"听众是否觉得突兀" +3. **教学**——评估"学生是否察觉到了我的拼装" +4. **产品 UX/界面设计**——评估"用户是否察觉到我的表面功夫" +5. **设计一个多模块/多角色/多视角的产品**——评估"切换是否自然" +6. **做品牌/营销/广告**——评估"观众是否觉得生硬" +7. **编辑/审校/反馈他人作品**——诊断"这里是不是有未蒙蔽的拼装" + +语言信号:"不自然 / 突兀 / 生硬"、"拼装 / 痕迹 / 不流畅"、"听众/读者没察觉"、"X 看起来很硬"、"X 的转折太硬了"、"读者开始关注形式而不是内容"、"X 让我跳戏"、"X 让人出戏"、"X 太匠气 / 太刻意"、"X 太炫技 / 太技巧"。(/mystification) + +## 与相邻方法的分工 + +- 与 flat-vs-round-character(现归 character-design)的区别:蒙蔽是**整体感知层**,扁/圆是**单人物形式层**;前者管"自然不自然",后者管"深不深"。圆形人物的"出人意料"必须被蒙蔽,才能既意外又可信。 +- 与 plot-character-tug(现归 novel-diagnosis)的区别:蒙蔽是**作者姿态**,情节-人物拉锯是**结构张力**;前者管"我让你信服",后者管"两种要素的张力"。 +- 与"打破第四面墙"的区别:后者故意让作者/角色跳出来,是**反蒙蔽**;蒙蔽是让作品自然,打破是让作品"不自然"。 +- 与 expansion-vs-completion(现归 story-ending)的配合:扩展/完成两种结尾姿态都需要蒙蔽支撑——收尾处的速度变化、视角收束同样不能被读者看出接缝。 + +(/mystification) + +## 中文落地(中文适配) + +中国评书/相声中"说书人亲临"是合法传统——说书人当众点评人物、与听众搭话,并不构成失败。这与福斯特"作者亲临是致命的"的判断不同:福斯特的论断基于西方现代小说传统,移到说书体、章回体口吻时要看文体约定——文体本就承诺了说书人在场,读者的期待不同,蒙蔽的对象也不同(蒙蔽的是情节接缝,不是说书人的存在)。(中文适配;依据 aspects-of-the-novel/mystification 盲点条) diff --git a/framework/catalog/dsh/skills/scene-craft/references/scene-revision-checklist.md b/framework/catalog/dsh/skills/scene-craft/references/scene-revision-checklist.md new file mode 100644 index 0000000..92cbcd1 --- /dev/null +++ b/framework/catalog/dsh/skills/scene-craft/references/scene-revision-checklist.md @@ -0,0 +1,91 @@ +# 场景改稿检查清单(五关) + +> 用途:一稿写完后,逐场景、逐关过一遍。五关按"先定命,再定篇幅,再剪进出,再调镜头,最后藏缝"的顺序走;单场景快速诊断可只过相关的关。 +> 来源:五个源单元的可执行步骤合并——/scene-mission-driven 与 scene-enter-late-exit-early;/fiction-scene-craft;/cinematic-distances;/mystification。 +> 逐场登记用 [scene-ledger-template.md](scene-ledger-template.md)。 + +## 第一关:使命关(这个场景干什么) + +来源:scene-mission-driven + +- [ ] 列出当前所有场景(或一段内的所有场景) +- [ ] 逐场景用一句话回答:"这个场景让故事前进了什么?" + - 说不清 = 这个场景无使命 +- [ ] 统计: + - 全有使命 = 通过 + - ≤ 1 个无使命 = 还行 + - ≥ 2 个无使命 = 改稿,删 / 并 +- [ ] 检查每场使命数量:每个场景只 1 个使命 + - 有 2+ 使命 = 拆场景(典型反例:"角色思考了,之后她做决定" = 思考 + 决定两个使命) +- [ ] 检查使命量级:使命必须"改变故事走向","角色出门"不算 +- [ ] 输出改稿清单:"删哪些 / 拆哪些 / 并哪些" + +## 第二关:详略关(给多少篇幅) + +来源:fiction-scene-craft + +- [ ] 诊断问题类型:(a) 不知道详写哪些?(b) 详写太多?(c) 过渡拖沓?(d) 高潮没力?(e) 整体一个节奏? +- [ ] 给每个场景标详 / 略: + - 核心 = 冲突 / 转变 / 启示 → 详写 + - 核心 = 推进 / 过渡 / 背景 → 略写 + - 详写场景合计约占故事字数 5%-15%,略写 = 1-3 个字或一段 +- [ ] 高潮场景没有被略写(略写高潮 = 失去力量:短句 + 对话 + 动作密集才是高潮写法) +- [ ] 不重要的过渡是否减到 3 个字左右(例外:自带隐喻功能的场景详写,如"三天三夜的雨") +- [ ] 每个略写场景有 1-3 个动作/感官词扛住("她把信烧了。",不是"那天晚上她想了很久。") +- [ ] 惯性场景去留判断:一开写就停不下来的场景,写完试删——删掉影响故事就留,不影响就减到 3 个字 +- [ ] 字数校准:数一个参考作者同等场景的字数,问"这个字数够吗"(是校准,不是模仿) +- [ ] 全篇节奏落在三种模式之一:紧-紧-紧 / 详-略-详(默认)/ 略-略-详;不全详不全略 +- [ ] 过渡短(3-30 字),没有几百字的过渡段 +- [ ] 写完不立即重读,放一边至少隔一夜 + +## 第三关:进出关(从哪里进,从哪里出) + +来源:scene-enter-late-exit-early + +- [ ] 标出场景当前的开头和结尾(各一句话) +- [ ] 进入判断:问"读者现在还不知道什么?" + - 答案点 = 真正的进入点;在那之前的内容 = 删 / 并 +- [ ] 退出判断:问"读者需要知道的都知道了吗?" + - 是 = 退出点;在那之后的内容 = 删 / 并 +- [ ] 输出"删多少字/段" +- [ ] 边界检查: + - 进入太晚 = 读者不知道发生什么(困惑)→ 回退到能给读者定位的点 + - 退出太早 = 戏剧没爆发 = 场景没使命 → 回第一关确认使命 +- [ ] 删掉的过渡用"白空间/换行"暗示场景切换,不剪出断裂 + +## 第四关:距离关(用多远的镜头拍) + +来源:cinematic-distances + +- [ ] 把一章/一个场景的每个段落标上五档之一:鸟瞰 / 建立 / 中景 / 特写 / 极端特写 + - 完成标准:80%+ 段落标得明确;没有"分不清中景还是特写"的含糊段 + - 判停:中景占比 ≥ 60% = 警告,作者只敢写中景,练拉远和推近 +- [ ] 列出场景中 3-5 个关键瞬间(死亡、告白、揭露、冲突顶点、回忆闪回),逐个指派距离: + - 死亡 = 特写;战场 = 中景 + 鸟瞰;告白 = 特写 + 极端特写 + - 判停:关键瞬间仍在中景 = 重新设计段落,否则场景没有情绪峰值 +- [ ] 一个场景内切换 3+ 距离(常见:建立→中景→特写) + - 判停:为换而换 / 每段都换 = 矫枉过正,回头减;每个距离段至少 2-3 句再切 +- [ ] 长篇中段(约 40-60% 处)可加 1 个鸟瞰/建立镜头段作换气: + - 不承载情节,只服务读者呼吸 + - 必须有具体内容(晨光、街景、季节变化),"空段"不叫鸟瞰 +- [ ] 中文单位检查:距离切换按整场/整章看,不段段必切,避免段落碎片化 + +## 第五关:蒙蔽关(藏拼装痕迹) + +来源:mystification + +- [ ] 找接缝:视角、语气、节奏、密度突然改变的地方,至少标出 1 处可能被读者察觉的拼装痕迹 +- [ ] 每处接缝给至少 1 条具体修改:视角转换前加一段"桥梁"叙述,或用细节的延续掩盖切换;不说"让叙述更自然"这类空话 +- [ ] 检查作者亲临:有没有亲自出现在叙述中替读者解读人物的句子("她看着不错吧——我一直都特别喜欢她"),有就删 +- [ ] 分清蒙蔽与欺骗:只让拼装不刺眼(技术),不让内容失真(道德) +- [ ] 盲测:至少 1 个不知道作者意图的人(或独立评审)通读,报告哪里突兀 + - 判停:盲测报告 0 处突兀 = 蒙蔽成功 + +## 整体适用性预检(开工前先过) + +- 中短篇/单场景:整个故事一个使命,进出与距离切换可不强求 +- 文学/意识流:场景故意慢,节奏不是快就好;全程单一距离的章节切了反而稀释情绪 +- 极短篇(3000 字以下):篇幅不够切五档,强切凌乱 +- 长篇(> 30000 字):详略按章重新设计,每章有自己的详略 +- 剧本:台词部分不适用,场景说明可用距离法 +- 非虚构、诗歌散文、纯抒情独白:不适用本清单 diff --git a/framework/catalog/dsh/skills/scene-craft/references/scene-rhythm.md b/framework/catalog/dsh/skills/scene-craft/references/scene-rhythm.md new file mode 100644 index 0000000..fea98f0 --- /dev/null +++ b/framework/catalog/dsh/skills/scene-craft/references/scene-rhythm.md @@ -0,0 +1,99 @@ +# 排节奏:详略相间,有快有慢 + +> 本文件是三本书的合并落点:《成为作家》(多萝西娅·布兰德)becoming-a-writer/fiction-scene-craft 的三种节奏模式与过渡规则;《Story Engineering》(Larry Brooks)story-engineering/scene-enter-late-exit-early 的"慢场景有价值、全书不能只有一种速度";《写作工具》(Roy Peter Clark)writing-tools-clark/cinematic-distances 的长篇中段换气段。 +> 单个场景的详略判断见 [scene-detail.md](scene-detail.md),单场景的剪切点见 [scene-entry-exit.md](scene-entry-exit.md),镜头距离见 [scene-camera.md](scene-camera.md)。 + +排节奏回答的问题是:相邻场景怎么排列,整本书在哪里屏息、在哪里换气。详略是单个场景的篇幅判断,节奏是这些篇幅的排布。 + +## 三种节奏模式(场景的不同节奏) + +(/fiction-scene-craft) + +**模式 1:"紧 → 紧 → 紧"(高潮场景)** + +- 全部详写,节奏快 +- 大量短句,大量对话,动作密集 +- 适用:冲突 / 高潮 / 转折 +- 例子:离婚谈判的高潮,一次告白,一次摊牌 + +**模式 2:"详 → 略 → 详"(呼吸)** + +- 一个详写场景 + 一个略写过渡 + 一个详写场景 +- 像呼吸:吸 → 屏 → 呼 +- 适用:故事主体 +- 例子:详写"第一次见面" + 略写"几个月后" + 详写"重逢" + +**模式 3:"略 → 略 → 详"(蓄势)** + +- 开头都是略写,蓄势到一个详写场景 +- 像慢镜头推到特写 +- 适用:故事铺垫,关键场景前 +- 例子:略写"5 个人物的日常" + 详写"关键事件" + +**怎么选**: + +- 不知道选哪个?**默认模式 2**(详-略-详),最平衡 +- 写高潮?**模式 1** +- 写铺垫?**模式 3** + +(/fiction-scene-craft) + +## 场景之间过渡(节奏的关键) + +**好的过渡**: + +- 短(3-30 字) +- 暗示时间/空间的变化 +- 不需要完整描述 +- 例:"三个月后。" / "她搬到北京那年。" + +**坏的过渡**: + +- 长(几百字) +- 像另一个场景一样详写 +- 例:"三个月后, 她搬到了北京, 找了一份新工作, 认识了新的朋友……" + +**过渡的作用**: + +- 节奏的"屏息" +- 让详写场景之间有**呼吸** +- 让读者**主动**填补空白(这正是想象的入口) + +(/fiction-scene-craft) + +## 全书要有快有慢(三书视角合并) + +同一个方法点——"整本书不能只有一种速度,慢的部分有它的位置"——三本书从不同角度说过,合并如下,各自视角与出处保留。 + +### 《Story Engineering》视角:别把所有场景都剪成快戏 + +- 所有场景都晚入早出——失去氛围/共情建立的时间。 +- 完全删寒暄——有时 1 句寒暄是共情建立。 +- 假设读者都急——实际部分读者喜欢慢/氛围。 +- 假设"快" = "好"——部分场景需要慢(回忆/情感)。 +- 假设只用 1 种时间感——整本书应该有时快有时慢。 + +(/scene-enter-late-exit-early,失败模式与盲点条) + +注意这里与"跳过所有寒暄"的原文命令存在张力:原文主规则要求进入场景时跳过寒暄铺陈,作者自己又警告"有时 1 句寒暄是共情建立"。两条都保留,取舍看场景使命是推进关系还是推进事件。(冲突标注:同出/scene-enter-late-exit-early) + +### 《成为作家》视角:统一节奏就是错误 + +- 所有场景一个节奏:详写详写详写 = 读者累;略写略写略写 = 读者没感觉。 +- 修法:用模式 2(详-略-详)或模式 3(略-略-详)换着排。 + +(/fiction-scene-craft,常见错误第 3 条) + +### 《写作工具》视角:长篇中段放一个换气窗口 + +- 在长篇中段(读者开始疲劳处)插入 1 个**鸟瞰 / 建立镜头**段落,不带情节,只交代空间与时间——让读者"换气"。 +- 完成标准:鸟瞰/建立段不承载情节功能,只服务"读者呼吸";位置在中段 40-60% 处。 +- 判停条件:把鸟瞰当"省力"——一段不写的"空"段不叫鸟瞰,鸟瞰仍要**有具体内容**(晨光、街景、季节变化)。 + +(/cinematic-distances,执行步骤第 4 步) + +## 节奏与详略、进出的关系 + +- 节奏模式是详略的排布:先按 [scene-detail.md](scene-detail.md) 给每场定详略,再看全篇落在三种模式的哪一种。 +- 剪切点影响单场内部的快慢,但"全书快慢"不由剪切点单独决定:晚入早出是单场景层面的紧,慢场景与换气段是全书层面的松,两者配合使用。 +- 高潮场景被略写时,先改详略再调距离:详略错了,焦距救不回来(见 [scene-detail.md](scene-detail.md) 常见错误第 2 条)。 diff --git a/framework/catalog/dsh/skills/show-and-omission/SKILL.md b/framework/catalog/dsh/skills/show-and-omission/SKILL.md new file mode 100644 index 0000000..f924ee9 --- /dev/null +++ b/framework/catalog/dsh/skills/show-and-omission/SKILL.md @@ -0,0 +1,84 @@ +--- +name: show-and-omission +description: | + 激活场景:小说文本里情绪、氛围、性格被抽象标签堆出来("她很悲伤""气氛阴森""他是个好人"),读者没有画面; + 写到极端情绪场景(崩溃、杀人后、噩耗、求爱)不知道心理怎么下笔;奇幻、梦境、超现实情节写得假、读者出戏; + 对话和动作看着平淡,扛不出第二层意思;想藏住两个人之间的秘密或暗流,不想明说; + 视角人物说出了自己不可能知道的信息;或者总怕读者看不懂,解释越写越多,读者仍说读不懂。 + 关键 trigger:"show don't tell" / "展示不说教" / "没有画面感" / "太抽象" / "形容词太多" / + "心理描写怎么写" / "不写他感到,写他做什么" / "留白" / "飞白" / "冰山" / "写得假" / "出戏" / + "imagination" / "magical realism" / + "读者不信" / "藏着不写明" / "说得太满" / "视角穿帮" / "人物知道了不该知道的" / "信息差" / + "读者读不懂" / "明明很显然" / "跳步" / "术语太多" / "why is this jargon"。 + 不适用于:意识流作品里刻意的直接心理呈现(乔伊斯、伍尔夫式的美学追求); + 第一人称主观独白和全知叙述者的合法评述;纪实写作和须符合科学逻辑的硬科幻; + 需要逻辑严密的悬疑推理与动作戏(反逻辑法不能用); + 说明书、新闻导语、学术论文、儿童启蒙等只需明确传递信息的段落;写给同行的专业文献(术语是该有的)。 + 与 prose-craft 交接:句长单调、修辞密度、风格杠杆诊断归 prose-craft。 + 与 theme-and-stance 交接:抽象标签、极端情绪缺画面、视角穿帮归本 Skill;主题演示、作家立场、手软/心慈手狠归 theme-and-stance(含 show don't tell 主题层)。 +--- + +# 展示与留白 + +一句话定位:不把结论递给读者,给读者能自己得出结论的材料——写出来的部分是抓手,没写出来的部分是分量。 + +## 方法索引 + +### 写情绪、氛围、性格:把标签换成场景 + +- 抽象标签(愤怒 / 阴森 / 勇敢 / 有效 / 重要)全部换成动作、数字、场景、对话,以"读者脑中能出现什么画面"为验收 → references/show-vs-tell.md +- 极端情绪场景关掉"他感到 / 她心想"的心理分析通道,改写手在做什么、眼睛看到什么、耳朵听到什么、身体什么姿态 → references/extreme-emotion-body.md +- 用一个具体的动作、对话或物件扛住心理、氛围、关系、主题等多层信息,让读者自己读出第二层 → references/iceberg.md + +### 写超现实:让想象可信 + +- 想象与虚幻的差别在有无现实依据:为每个超现实元素找一个读者经验里有的现实锚点,周围用写实笔法、人物反应写得日常,不解释成因 → references/imagination-anchor.md + +### 写留白:用不写来写 + +- 反逻辑三形态:缺席(该出现的人不出现)、反常(该有的反应没有 / 不该有的反应出现)、飞白(该写的不写,让读者从空白读) → references/anti-logic.md +- 写周围人的反应,不写主角的心思,让读者从周围推导主角 → references/anti-logic.md +- 空白处必须留可反推的暗示,并控反逻辑密度:短篇一两处、中篇三到五处、长篇每章约一处 → references/anti-logic.md + +### 写视角:锁住知识边界 + +- 每个视角人物只说、只想他视角内的信息;信息差是叙事张力的引擎,戏剧反讽(读者知道角色不知道)是它的正面用法 → references/pov-knowledge-boundary.md + +### 修订与验证:防读者读不懂 + +- 知识诅咒诊断:写下"显然 / 不用说 / 众所周知"基本是诅咒发作;靠"想得更努力换位"破不了,要靠读者复述、隔夜重读、反向拆解组块 → references/reader-gap-diagnosis.md +- 逐段自问"读者在这里应该看到什么",答不上来就还在告知;只传信息(时间、地点、数字)的地方直接告知即可 → references/show-vs-tell.md +- 全部检查项按写作进程汇总(写作中 / 修订 / 完稿验收) → references/show-omission-checklist.md + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|----------| +| references/show-vs-tell.md | 展示而非告知的原则与认知基础(镜像神经元);四步法(识别标签→问具体→替换具象→画面自检);tell/show 对照例;zombie noun 过度抽象模式;Pinker 三个 show 范本(Dawkins、Greene、兔错觉重写);兔错觉 / 暗能量 / Goldstein 三个案例;六步执行流程;五条不适用边界;四个失败模式;三个盲点(含 AI 腔、中文四字套话);三个易混方法;小说落地五项(情绪 / 氛围 / 节奏 / 对话 / 性格)与小说专属边界;中文适配 | +| references/extreme-emotion-body.md | 无心理描写法:极端情绪关闭心理分析通道、打开身体感官通道;福克纳《沃许》杀人后的视觉动作、陀思妥耶夫斯基《罪与罚》杀人后二十页动作、司汤达《红与黑》桌下握手三个案例全文;五步执行流程(含判停条件与三分之一标准);四条边界(平静场景 / 意识流 / 纪实 / 儿童视角);失败模式(绕开、动作当点缀);盲点(福克纳长篇反例、普遍法则化表述);与冰山理论的"省略 vs 转移"区分 | +| references/imagination-anchor.md | 想象-事实转化法:想象与虚幻的区分(口技木偶 vs 真人);现实锚点;文学的真实含想象、梦境、欲望;毕加索"虚伪中的真实";马尔克斯床单飞天、卡夫卡《变形记》、马尔克斯《虚度年华的海洋》三个案例全文;五步执行流程;三条边界(严格现实主义 / 历史纪实 / 硬科幻);失败模式(把虚幻当想象、过度解释);盲点(网文世界观、无量化标准);与世界观构建、写实主义的区分 | +| references/iceberg.md | 冰山写作法:不是少写,是写有含量的少;《杀手》"哪一份是你的"水面 / 水下拆解;奈保尔《布莱克·沃滋沃斯》"取"vs"讨"一字之差;蒲松龄《促织》"小虫";四步执行流程(水下清单、承载原则、冰山比 1/8-1/3、删字测试);五条触发场景;适用边界与新手慎用;三个常见错误表项 | +| references/anti-logic.md | 反逻辑写作:用不写来写;三种形态(缺席 / 反常 / 飞白);《红楼梦》秦可卿之死原文拆解;王熙凤三次"走"、秦可卿死后消失、林冲向东走、责编轶事四个案例;五步执行流程(该写没写清单、三问归因、反常反应设计、飞白方法与检验、密度控制);适用边界(推理 / 动作戏禁用);四个常见错误表项;与冰山、视角、关系、必然逻辑的跨域链接 | +| references/pov-knowledge-boundary.md | 知识诅咒在小说叙事层的直接应用:POV 角色只知道自己知道的;多视角 / 第一人称 / 第三人称限制 / 多角色对话逐条检查;侦探 .38 口径反例;信息差是叙事张力引擎;戏剧反讽(《罗密欧与朱丽叶》);小说专属边界(全知叙述者 / 童话寓言 / 元小说) | +| references/reader-gap-diagnosis.md | 知识诅咒本体:认知机制定义与英文原段;五个变体(自我中心 / 后见之明 / 错误共识 / 虚幻透明 / 心盲);功能固着与组块化;"显然"自我诊断信号;三破解(close the loop / 隔夜重读 / 反向拆解组块);兔错觉摘要、鸟食器说明书、术语邮件三个案例;七步执行流程;五条边界;三个失败模式;两个盲点(含 AI 腔);三个易混方法(Dunning-Kruger / 读者中心 / 认知负荷) | + +## 脚本 + +| 脚本 | 用途 | +|------|------| +| references/show-omission-checklist.md | 展示与留白检查清单:按写作进程排列(写作中六张子清单:抽象标签 / 极端情绪 / 想象锚点 / 冰山 / 反逻辑 / 视角边界;修订阶段:画面自检、隔夜重读、读者复述;完稿验收:密度与暗示核对;快速排错表) | + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/dsh/skills/show-and-omission/references/_coverage.md b/framework/catalog/dsh/skills/show-and-omission/references/_coverage.md new file mode 100644 index 0000000..c0b12e3 --- /dev/null +++ b/framework/catalog/dsh/skills/show-and-omission/references/_coverage.md @@ -0,0 +1,17 @@ +# show-and-omission 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| bifeiyu-novel-skill/bifeiyu-anti-logic | references/anti-logic.md | +| bifeiyu-novel-skill/bifeiyu-anti-logic | references/iceberg.md | +| bifeiyu-novel-skill/bifeiyu-iceberg | references/iceberg.md | +| bifeiyu-novel-skill/bifeiyu-iceberg | references/anti-logic.md | +| sense-of-style/curse-of-knowledge | references/reader-gap-diagnosis.md | +| sense-of-style/curse-of-knowledge | references/pov-knowledge-boundary.md | +| sense-of-style/show-dont-tell | references/show-vs-tell.md | +| sense-of-style/show-dont-tell | references/extreme-emotion-body.md | +| wo-neng-fou-xiang-xin-zi-ji/imagination-to-fact | references/imagination-anchor.md | +| wo-neng-fou-xiang-xin-zi-ji/no-psychological-description | references/extreme-emotion-body.md | +| wo-neng-fou-xiang-xin-zi-ji/no-psychological-description | references/iceberg.md | diff --git a/framework/catalog/dsh/skills/show-and-omission/references/anti-logic.md b/framework/catalog/dsh/skills/show-and-omission/references/anti-logic.md new file mode 100644 index 0000000..2f15497 --- /dev/null +++ b/framework/catalog/dsh/skills/show-and-omission/references/anti-logic.md @@ -0,0 +1,191 @@ +# 反逻辑与飞白:用不写来写 + +> 来源单元:《小说课》(毕飞宇)bifeiyu-novel-skill/bifeiyu-anti-logic,读《红楼梦》王熙凤/秦可卿 + 曹雪芹的"真事隐去"(第 6 章)。 +> 本文件管"留白"的极端形式:该写的偏偏不写,空白本身就是信息。冰山的一般形式见 [iceberg.md](iceberg.md)。 + +## 原文引文 + +> 「有时候,你从具体的描写对象上反而看不到作者想表达的真实内容,你要从'飞白'——也就是没有写到的地方去看。所谓'真事隐去、假语存焉'就是这个道理。」 + +(/bifeiyu-anti-logic) + +## 书中原文:《红楼梦》第十三回,秦可卿死了 + +**按常理最该悲痛的人**:贾蓉(丈夫)、王熙凤(闺蜜)。 + +**曹雪芹的写法**: + +- 贾蓉、王熙凤在小说里**突然失踪**——没有写他们的反应。 +- 真正反应激烈的是:贾宝玉(喷血)、贾珍(哭成泪人)。 +- 秦可卿的婆婆**尤氏**——祭奠时胃疼、葬礼时胃又疼。 + +**毕飞宇解读**:王熙凤和贾蓉"暧昧"——他们的"消失"是反逻辑的,但**正是这种反逻辑泄露了真相**。 + +(/bifeiyu-anti-logic) + +## 方法核心 + +**反逻辑 = 用"不写"来写。** 当所有人按逻辑应该如此,你偏偏如此——**这本身就是信息**。(/bifeiyu-anti-logic) + +**反逻辑的三种形态**: + +1. **缺席**:该出现的人不出现。 +2. **反常**:该有的反应没有 / 不该有的反应出现。 +3. **飞白**:该写的不写,让读者从"空白"读。 + +## 书中案例 + +### 案例 1:曹雪芹 王熙凤的"走"——三次走,三种心态 + +``` +第一次:一步步行来赞赏(离开秦可卿的病房) + → 字面:心情不错 + → 飞白:心里没别人,包括秦可卿 + +第二次:方移步前来(离开贾瑞的色诱) + → 字面:轻松潇洒 + → 飞白:她根本没把贾瑞放在眼里 + +第三次:款步提衣上了楼 + → 字面:妖娆美不胜收 + → 飞白:王熙凤心里只有"爷们"——欲望 +``` + +**关键**:三次"走"的字面都"正常"——**但放在一起看,反逻辑**。 + +(/bifeiyu-anti-logic) + +### 案例 2:曹雪芹 秦可卿死后的"消失" + +- 贾蓉、熙凤不该消失。 +- 他们的消失泄露了秘密。 +- 尤氏的"胃疼"是反逻辑的"借口"。 + +(/bifeiyu-anti-logic) + +### 案例 3:施耐庵 林冲的"向东走" + +- 林冲被逼到山神庙,杀了人。 +- 接下来他"向东走"。 +- **向东**是反逻辑——林冲没方向,只是流亡。 +- **这个"没方向"本身说明他没想造反**。 + +(/bifeiyu-anti-logic) + +### 案例 4:反逻辑的"话"在叙述者身上的应用 + +> 「一句话原封不动地送给贾责编:遇上你这样的责编,我容易吗我。」 + +——这是反逻辑的"话"在叙述者身上的应用(毕飞宇叙述自己与编辑的关系)。 + +注:源单元此条标题文字有串讹(混入"莫泊桑《项链》"与"王熙凤的'见面'"字样),内容与《项链》、王熙凤无关,按内容保留如上。(/bifeiyu-anti-logic) + +## 触发场景 + +1. 你想写"两个人有秘密"但不能明说 → 用反逻辑。 +2. 你的人物"应该"有反应但你没有写 → 检查是不是用了反逻辑。 +3. 你发现"不该出现的反应"出现了 → 这是金矿。 +4. 你想让读者读出"字面之外" → 用飞白。 +5. 你的小说太"顺"了 → 考虑加一个反逻辑点。 + +(/bifeiyu-anti-logic) + +## 可执行步骤 + +### 步骤 1:识别"应该写但没写" + +列出场景里**按逻辑应该有反应/动作**的所有元素: + +```yaml +场景:秦可卿之死 +应该反应的人: + - 贾蓉(丈夫)—— ❌ 失踪 + - 王熙凤(闺蜜)—— ❌ 失踪 + - 尤氏(婆婆)—— ✅ 胃疼(反常) +实际反应的人: + - 贾宝玉 —— 喷血 + - 贾珍 —— 哭成泪人 +``` + +**失踪就是反逻辑**。 + +### 步骤 2:问"为什么没写" + +为每一个"应该写但没写"找原因: + +- 是作家没想到?→ 补上。 +- 是作家刻意?→ 这是反逻辑——深挖原因。 +- 是作家"藏"了?→ 这是飞白——设计空白让读者填空。 + +### 步骤 3:设计"反常反应" + +让一个**不该有反应的人有反应**,或者**该有反应的人反应异常**: + +``` +不该反应的人反应 → 揭示隐藏关系 +该反应的人无反应 → 揭示心理距离 +该反应的人反常反应 → 揭示深藏的性格 +``` + +### 步骤 4:用"飞白"留白 + +**最难的技巧**:让读者读"没说出口的话"。 + +方法: + +1. 写出"周围的人的反应"。 +2. 不写"主角的反应"。 +3. 让读者从"周围"推导"主角"。 + +**检验**: + +> "我从没写到主角的心思,但读者读出来了吗?" + +### 步骤 5:检验"反逻辑密度" + +一部小说里**反逻辑点不能太多**——多了读者读不懂。 + +- 短篇:**1-2 个**反逻辑点足够。 +- 中篇:**3-5 个**。 +- 长篇:每章节 1 个,累积密度可控。 + +(以上五步均出自/bifeiyu-anti-logic) + +## 适用边界 + +- **适合**:长篇、复杂人物关系、有秘密的情节。 +- **慎用**:短篇(密度太高会失焦)。 +- **不适合**:动作戏、悬疑推理(它们要逻辑严密)。 + +(/bifeiyu-anti-logic) + +## 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 反逻辑当逻辑用 | 人物不真实 | 反逻辑要有"暗示"——读者事后能反推 | +| 反逻辑太多 | 读者困惑 | 短篇不超过 2 处 | +| 飞白留白变成"偷懒" | 读者读不懂 | 飞白也要"暗示" | +| 滥用巧合 | 假 | 反逻辑是结构选择,巧合是偷懒 | + +(/bifeiyu-anti-logic) + +## 一句话总结 + +> **真正的高手从不写主角的心思,只写周围人的反应——让读者自己读出主角在想什么。** + +(/bifeiyu-anti-logic) + +## 与相邻方法的区分与跨域链接 + +- 与 bifeiyu-shakespeare 互补:逻辑是"必然",反逻辑是"反必然"——两者配对才立体。(注:bifeiyu-shakespeare 归 theme-and-stance 综合 skill。) +- 与 bifeiyu-iceberg 同源:反逻辑是冰山的极端形式——"水下"是**没发生的事**(见 [iceberg.md](iceberg.md))。 +- 与 bifeiyu-perspective 配合:反逻辑往往通过"看的人"实现。(注:bifeiyu-perspective 归 narration-pov 综合 skill。) +- 与 bifeiyu-relationship 同源:关系即人物——反逻辑经常用于揭示隐藏关系。(注:bifeiyu-relationship 归 character-presentation 综合 skill。) + +(/bifeiyu-anti-logic) + +## 同一方法的多书视角 + +- Pinker 从读者认知一端给出同样的要求:读者处理具体动作时镜像神经元激活、处理抽象标签时没有感官激活——飞白正是把"主角的心思"这个抽象留给读者用自己的感官经验去补全(见 [show-vs-tell.md](show-vs-tell.md))。 +- 余华的无心理描写法是飞白的近亲:不写主角的心理,写他的身体和周围(见 [extreme-emotion-body.md](extreme-emotion-body.md))。区别在于:无心理描写法写主角的身体动作,飞白连主角的身体也不写,只写周围人。 diff --git a/framework/catalog/dsh/skills/show-and-omission/references/extreme-emotion-body.md b/framework/catalog/dsh/skills/show-and-omission/references/extreme-emotion-body.md new file mode 100644 index 0000000..b7e5f47 --- /dev/null +++ b/framework/catalog/dsh/skills/show-and-omission/references/extreme-emotion-body.md @@ -0,0 +1,138 @@ +# 极端情绪不写心理,写身体:无心理描写法 + +> 来源单元:《我能否相信自己》(余华)wo-neng-fou-xiang-xin-zi-ji/no-psychological-description,《内心之死》(1998) / 《我能否相信自己》演讲。 +> 本文件管极端情绪场景(狂喜、崩溃、杀人后、噩耗、求爱)的内心呈现。这是 show-don't-tell 在情绪层的具体应用(总原则见 [show-vs-tell.md](show-vs-tell.md));它与冰山理论的区别("转移"vs"省略")见本文件末节。 + +## 原文引文 + +> "心理描写是知识分子虚构出来的,来吓唬我们这些写小说的,害得我走了很长一段弯路。" +> +> "当人物最需要内心表达的时候,我学会了如何让人物的心脏停止跳动,同时让他们的眼睛睁开,让他们的耳朵矗起,让他们的身体活跃起来,我知道了这时候人物的状态比什么都重要,因为只有它才真正具有了表达丰富内心的能力。" +> +> — 余华,《内心之死》 + +(/no-psychological-description) + +## 方法核心 + +当人物面临极端情境时,内心是"兵荒马乱"的——百感交集,用再多语言也无法直接表达。此时任何心理分析("他感到极度痛苦""她心中充满矛盾")都会局限人物真实的内心,因为内心在最丰富的时候恰恰是无法言说的。(/no-psychological-description) + +正确的做法是**关闭心理分析的通道,打开身体和感官的通道**:让人物的心脏停止跳动(不写内心),让眼睛睁开(写他看到了什么),让耳朵矗起(写他听到了什么),让身体活跃起来(写他的动作和姿态)。人物的身体状态比任何心理分析都更能表达丰富的内心。(/no-psychological-description) + +这不是"不写内心",而是**通过外在的身体和动作让内心自己浮现**。读者通过人物的动作、视觉、身体状态,自行感受到人物的内心——这种感受比直接告知更强烈、更持久。(/no-psychological-description) + +## 书中案例 + +### 案例 1:福克纳《沃许》——杀人后的视觉描写 + +- **问题**:穷白人沃许砍死了侮辱他外孙女的富白人塞德潘,杀人后的内心如何描写? +- **方法论的使用**:福克纳没有写沃许的心理活动,而是写他出奇的平静——帮助外孙女喝水,安慰她的眼泪,动作"笨拙",姿态"硬挺挺"而且阴沉。他坐在窗口等了一上午,时不时踮脚走到草垫那边。一个白人男孩碰上死尸,抽了口冷气喊了一声,抬头看见窗口的沃许,被催眠似的转身逃开。 +- **结论**:全部是视觉和动作,没有一句心理描写,但杀人者内心的麻木和压力扑面而来。 +- **结果**:余华读到这一段后"明白了"心理描写的真正方式,跨越了写作最大的障碍。 + +(/no-psychological-description) + +### 案例 2:陀思妥耶夫斯基《罪与罚》——杀人后二十页动作 + +- **问题**:拉斯柯尔尼科夫用斧头砍死放高利贷老太婆后,内心的惊恐如何描写? +- **方法论的使用**:陀思妥耶夫斯基写了近二十页,没有一句心理描写。拉斯柯尔尼科夫刚躺下立刻跳起来,感觉袖管上可能有血迹,一看没有,再躺下,接着又跳起来;钥匙插不进锁孔,手上的鲜血擦在红锦缎上;发烧、打寒颤、发现没扣门钩、睡觉没脱衣服还戴着帽子——一连串热锅上的蚂蚁似的动作。 +- **结论**:通过身体的不停动作和对细节的强迫性检查,杀人后的恐惧被表达得淋漓尽致。 +- **结果**:成为文学史上最经典的杀人后心理描写之一,但全程没有"心理描写"。 + +(/no-psychological-description) + +### 案例 3:司汤达《红与黑》——于连抓德·瑞那夫人的手 + +- **问题**:于连在德薇夫人在场的情况下,桌下抓住德·瑞那夫人的手,这个极度紧张的时刻如何写内心? +- **方法论的使用**:司汤达写于连"强迫自己说话,为了不让德薇夫人觉察,于连强迫自己声音洪亮有力";德·瑞那夫人的声音"泄露出来情感的激动,忸怩不安";于连"把这只手握得更紧了";他"高谈阔论,忘记了装假做作"。 +- **结论**:通过声音的变化、手的力度、说话的状态,两个人的内心紧张被精确呈现。 +- **结果**:"他的心浸润在幸福里。并不是他爱着德·瑞那夫人,而是一个可怕的苦难结束了。"——唯一一句心理陈述,但前面的动作已经让读者感受到了。 + +(/no-psychological-description) + +## 触发场景与语言信号 + +用户会在什么情境下需要这个方法(/no-psychological-description): + +1. 写到人物极端情绪(杀人后、得知亲人去世、被背叛、求爱时刻)时,停下笔不知道怎么继续。 +2. 写出的心理描写读起来苍白、像心理学教科书,自己都不满意。 +3. 被编辑/读者反馈"人物情绪不够真实""心理描写太表面"。 +4. 想学习 "show, don't tell" 但不知道具体怎么操作。 +5. 写关键场景时总是"绕过去",用叙述概括代替具体描写。 + +语言信号: + +- "心理描写怎么写" +- "他感到/她心想 这样写是不是太直白" +- "这个情绪场景写不下去了" +- "人物内心活动怎么写才有力量" +- "写杀人/死亡/崩溃场景" +- "show don't tell 具体怎么做" + +## 可执行步骤 + +当这个方法被激活后,按以下步骤执行(/no-psychological-description): + +1. **识别极端情绪场景** + - 完成标准:确认人物正处于狂喜/极度悲伤/恐惧/愤怒/杀人后/求爱等内心"兵荒马乱"的时刻。 + - 判停条件:如果人物内心平静(日常思考、回忆),跳到步骤 5,可直接写心理。 +2. **关闭心理分析通道** + - 删除或避免所有"他感到…""她心想…""心中充满…"式的直接心理陈述。 + - 完成标准:段落中没有任何直接描述内心状态的句子。 +3. **打开身体和感官通道** + - 写人物的**动作**:手在做什么(颤抖/紧握/反复检查/无意识的动作)。 + - 写人物的**视觉**:他的眼睛看到了什么(注意他注视的细节,往往是无关紧要的东西)。 + - 写人物的**听觉**:他听到了什么(环境声音、自己的呼吸/心跳)。 + - 写人物的**身体状态**:姿势、呼吸、体温、肌肉紧张。 + - 完成标准:至少包含 3 种身体/感官维度的描写。 +4. **让动作暴露内心** + - 人物的动作应该是"不由自主"的——反复检查、走来走去、突然停下、机械性重复。 + - 这些动作本身就是内心状态的外化,不需要解释。 + - 完成标准:读者通过动作就能感受到人物情绪,不需要额外说明。 +5. **(非极端场景)适度心理描写** + - 人物内心平静时,可以直接写心理活动,但要简洁。 + - 完成标准:心理描写不超过段落的 1/3,其余用动作和对话。 + +## 不要在以下情况使用 + +- **人物内心平静的日常场景**:此时内心可以直接描写,强行用动作反而做作。 +- **意识流文学的特定追求**:乔伊斯《尤利西斯》、伍尔夫《达洛维夫人》等作品正是以直接心理描写见长,本方法的法则不适用于这种美学追求。 +- **非虚构写作/纪实文学**:纪实作品中人物心理需要基于事实,不能用虚构的动作替代。 +- **儿童视角的内心**:儿童的心理活动本身就是简单直接的,不需要"绕弯子"。 + +(/no-psychological-description) + +## 失败模式(作者在书中警告) + +- **90% 的作家遇到心理描写就绕开**:"很多作家的作品让我们觉得叙述没有问题,语言也很美,可是总在绕来绕去,一到应该冲过去的地方就绕开。"——不要绕开,要用身体动作冲过去。 +- **把动作当装饰**:动作不是心理描写的"点缀",而是替代——必须完全放弃直接心理分析,让动作独立承担表达内心的功能。 + +(/no-psychological-description) + +## 盲点与时代局限 + +- 余华用福克纳的短篇《沃许》论证心理描写不可靠,但福克纳自己的长篇(如《喧哗与骚动》)大量使用意识流式的心理描写——余华选择性地忽略了这个反例。 +- 本方法适用于极端情绪场景,但余华的表述有时像是普遍法则,实际上在平静内心场景中心理描写是有效的。 + +(/no-psychological-description) + +## 容易混淆的邻近方法 + +- **"show, don't tell" 通用原则**:本方法是 show-don't-tell 在极端情绪场景下的具体应用,但更精确——不是泛泛地"展示",而是特指"用身体和感官替代心理分析"。 +- **冰山理论(海明威)**:海明威的冰山理论是"省略",本方法是"转移"——从心理转移到身体,不完全相同。 + +(/no-psychological-description) + +## 与相邻单元的区分与配合 + +- 与 obstacle-crossing(写作障碍应对)的区分与配合:区分面——本方法是具体的写作技法(如何写极端情绪),obstacle-crossing 是写作过程的宏观策略(如何面对和制造障碍)。配合面——两者经常配合使用:心理描写本身就是三大障碍之一,跨越障碍需要无心理描写法。(注:obstacle-crossing 属作者培养类,未入综合 skill 库,仅存于 craft/books/。) +- 与 character-voice-discovery(人物声音发现)的区分与配合:区分面——本方法关注极端情绪下的身体呈现,character-voice-discovery 关注人物日常语言和行为的自发产生。配合面——人物有了自己的声音后,极端情绪下的身体反应会更自然。(注:character-voice-discovery 归 character-presentation 综合 skill。) +- 与 skeptical-narration(怀疑主义叙述)的区分:怀疑主义叙述关注叙述立场,本方法关注叙述技法。(注:skeptical-narration 归 narration-pov 综合 skill。) + +(/no-psychological-description) + +## 同一方法的多书视角 + +- Pinker 从认知科学给同一原则打底:一串具体动作激活镜像神经元,读者"运行"那个场景;体感细节(湿冷 / 沙哑 / 钻痛)比情绪标签(悲伤 / 恐惧)强 10 倍。他还给了中文语境的提醒:四字成语很多是套话,"具体"不等于成语(见 [show-vs-tell.md](show-vs-tell.md) 的中文适配节)。(/show-dont-tell) +- 毕飞宇的冰山法则在操作端给出验收:把"我觉得气氛很紧张""他很害怕"这种形容词式心理描写全部删掉,用一个具体动作替代;别告诉读者"紧张",用一个错误动作让读者自己紧张(见 [iceberg.md](iceberg.md))。(/bifeiyu-iceberg) +- **边界分工的说明**:余华的方法管极端情绪场景(内心"兵荒马乱"时),并明确平静场景可以直接写心理;Pinker 也指出全篇 show 会冗长,第一人称主观体验和全知叙述者的评述是合法手段。两者一致:无心理描写法是极端场景的替代方案,不是全书禁令。(/no-psychological-description;/show-dont-tell) diff --git a/framework/catalog/dsh/skills/show-and-omission/references/iceberg.md b/framework/catalog/dsh/skills/show-and-omission/references/iceberg.md new file mode 100644 index 0000000..638bab9 --- /dev/null +++ b/framework/catalog/dsh/skills/show-and-omission/references/iceberg.md @@ -0,0 +1,142 @@ +# 冰山写作法:用一个动作扛多层信息 + +> 来源单元:《小说课》(毕飞宇)bifeiyu-novel-skill/bifeiyu-iceberg,《杀手》解析 + 海明威冰山理论(第 2 章)。 +> 本文件管"留白"的信息密度端:写出来的每个句子都要让读者读出第二层。用"不写"来写的反逻辑 / 飞白是它的极端形式,见 [anti-logic.md](anti-logic.md);极端情绪的身体呈现见 [extreme-emotion-body.md](extreme-emotion-body.md)。 + +## 原文引文 + +> 「他只写了'八分之一',其余的'八分之七'呢,都在'水下'。」 + +(/bifeiyu-iceberg) + +## 书中原文:《杀手》亨利快餐店那一段 + +《杀手》海明威在亨利快餐店那一段里,"一个字的氛围描写都没有"——但读完让人魂飞魄散。**为什么?**因为冰山在水下。(/bifeiyu-iceberg) + +服务员乔治一上来就问杀手阿尔:"**哪一份是你的?**"——这是一句废话。两个客人,记忆力再差也不会记不住。但海明威偏偏写了这一句废话。**这正是冰山**: + +``` +水面上的 1/8:乔治问"哪一份是你的" +水面下的 7/8: + - 乔治没有做笔录(紧张到忘记) + - 乔治没把握(再谨慎也不过) + - 整个餐厅气氛令人窒息 + - 两个杀手的压迫感被一个问句承载 +``` + +(/bifeiyu-iceberg) + +## 方法核心 + +**冰山理论不是"少写"——是"写有含量的少"**。你写出来的每个句子,必须承担它表面看不出来的重量。(/bifeiyu-iceberg) + +- 错误理解:写得越少越好。 +- 正确理解:写出来的每个细节都要让读者"读到第二层"。 + +## 书中案例 + +### 案例 1:海明威《杀手》"哪一份是你的" + +- **水面**:一个服务员问一句。 +- **水下**:整个故事的张力、人物心理、环境氛围全在这一句里。 + +(/bifeiyu-iceberg) + +### 案例 2:奈保尔《布莱克·沃滋沃斯》"来取走他的那一分钱" + +- **水面**:一个盲人乞丐"取"钱。 +- **水下**:他已经忘记自己是乞丐了,他当自己是公务员——性格、尊严、悲剧全在"取"vs"讨"的一字之差。 + +(/bifeiyu-iceberg) + +### 案例 3:蒲松龄《促织》"小虫" + +- **水面**:成名的儿子变成了一只小促织。 +- **水下**:全篇始终用"虫",唯独这里用"小虫"——父亲不认识儿子,儿子却认得父亲。 + +(/bifeiyu-iceberg) + +## 触发场景 + +当以下情况出现时,调用这个方法(/bifeiyu-iceberg): + +1. 你的对话/动作描写"看起来"平淡 → 检查水下。 +2. 你写了氛围但读者感受不到 → 把氛围藏进动作里。 +3. 你想说"气氛恐怖 X 已经吓傻" → ❌ 删掉,改用一个具体动作。 +4. 你的人物对话"自报家门"("我很紧张")→ ❌ 让动作说话。 +5. 短篇接近结尾、信息密度大 → 检验每句是否承担双重含义。 + +## 可执行步骤 + +### 步骤 1:定位你想写的信息 + +先想清楚:这一段想表达什么?列一个**水下清单**: + +``` +[ ] 人物心理状态 +[ ] 环境氛围 +[ ] 关系张力 +[ ] 主题暗示 +[ ] 情感重量 +``` + +### 步骤 2:选一个表面动作承载 + +找一个**具体动作 / 对话 / 物件**,让上面 5 个元素中的多个附着在上面。 + +> **原则**:能用一个动作承载 3 个元素 = 优秀;承载 1 个 = 浪费。 + +### 步骤 3:检验冰山比 + +写完一段,回头看: + +``` +水面字数 / 总字数 = 1/8 到 1/3 之间最理想 +``` + +太多 = 没给读者留白;太少 = 读者读不懂。 + +### 步骤 4:做"删字"测试 + +把"我觉得气氛很紧张"或"他很害怕"这种**形容词式心理描写**全部删掉,用一个**具体动作**替代。 + +**检验问题**: + +- [ ] 这段删掉后,水下的内容读者能自己"读出来"吗? +- [ ] 读者读完之后会想"原来如此",而不是"他告诉我"? + +(以上四步均出自/bifeiyu-iceberg) + +## 适用边界 + +- **适合**:短篇小说、对话、动作戏、意识流。 +- **不适合**:学术论文、说明书、儿童启蒙(需要明确表意的场景)。 +- **新手慎用**:冰山需要"水面"和"水下"高度匹配,水平不够时强行留白 = 读者读不懂。 + +(/bifeiyu-iceberg) + +## 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 把"留白"做成"省略" | 读者困惑 | 留白是有内容的省略,省略是偷懒 | +| 水下完全无迹可循 | 读者感受不到氛围 | 至少要有一个暗示 | +| 满篇都是冰山 | 读者累 | 关键场次用冰山,叙述段用正常密度 | + +(/bifeiyu-iceberg) + +## 一句话总结 + +> **别告诉读者"紧张",用一个错误动作让读者自己紧张。** + +(/bifeiyu-iceberg) + +## 与相邻方法的区分与跨域链接 + +- 与 bifeiyu-paiban(白描)形成对比:白描是"少即是多"在人物刻画上的应用,冰山是"少即是多"在信息密度上的应用。(注:bifeiyu-paiban 归 prose-craft 综合 skill。) +- 与 bifeiyu-anti-norm(反常)互补:反常是发现冰山的好工具——一个反常动作必有 7/8 在水下。(注:bifeiyu-anti-norm 归 character-presentation 综合 skill。) +- 与 bifeiyu-lyric-pass(抒情不抒发)同源:都是"克制"的不同表现。(注:bifeiyu-lyric-pass 归 prose-craft 综合 skill。) +- 与反逻辑同源:**反逻辑是冰山的极端形式——"水下"是没发生的事**(该出现的人缺席、该有的反应没有),见 [anti-logic.md](anti-logic.md)。 +- 与余华无心理描写法的关系:余华的方法是"转移"(从心理转移到身体),冰山是"省略"(把内容压到水下);两者在"删掉形容词式心理描写、用具体动作替代"这一步上汇合。(/no-psychological-description;/bifeiyu-iceberg) + +(/bifeiyu-iceberg) diff --git a/framework/catalog/dsh/skills/show-and-omission/references/imagination-anchor.md b/framework/catalog/dsh/skills/show-and-omission/references/imagination-anchor.md new file mode 100644 index 0000000..609ba91 --- /dev/null +++ b/framework/catalog/dsh/skills/show-and-omission/references/imagination-anchor.md @@ -0,0 +1,144 @@ +# 给超现实的东西一个现实锚点:想象-事实转化法 + +> 来源单元:《我能否相信自己》(余华)wo-neng-fou-xiang-xin-zi-ji/imagination-to-fact,《强劲的想象产生事实》(1995)。 +> 本文件管奇幻、梦境、超现实情节的可信度。超现实场景中人物的反应同样适用无心理描写法(见 [extreme-emotion-body.md](extreme-emotion-body.md))。 + +## 原文引文 + +> "强劲的想象产生事实。" +> +> "想象应该有着现实的依据,或者说想象应该产生事实,否则就只是臆造和谎言。" +> +> "虚幻和想象之间的区别,就跟口技演员手里操纵的木偶和真人一样。" +> +> — 余华,《强劲的想象产生事实》 + +(/imagination-to-fact) + +## 方法核心 + +文学中的想象不是凭空捏造,而是**"强劲的想象产生事实"**——想象必须有现实依据,才能让读者信服。关键区分(/imagination-to-fact): + +- **想象**:有现实依据,能落地为读者可感的真实。读者不质疑其真实性,甚至觉得"这就是真的"。 +- **虚幻**:没有现实依据,不知所云。读者觉得"假""出戏"。 + +**马尔克斯的例子**:写俏姑娘雷梅苔丝飞上天,苦思冥想后看到院子里黑女人晾床单被风刮跑,茅塞顿开——用床单作为飞翔的载体。床单是现实的,风是现实的,"抓着床单飞上天"就从虚幻变成了想象,读者信服。(/imagination-to-fact) + +**文学的真实不等于现实的真实**。"文学的真实是不能用现实生活的尺度去衡量的,它的真实里还包括了想象、梦境和欲望。"毕加索说"艺术家应该让人们懂得虚伪中的真实"——文学的真实是"虚伪中的真实"。(/imagination-to-fact) + +## 书中案例 + +### 案例 1:马尔克斯用床单让俏姑娘飞上天 + +- **问题**:《百年孤独》中俏姑娘雷梅苔丝要飞上天,怎么写才可信? +- **方法论的使用**:马尔克斯苦思冥想,"她怎么也上不了天"。直到看到院子里一个洗衣服的黑女人晾床单,床单被风刮跑。他茅塞顿开:让雷梅苔丝抓着床单飞上天。床单是现实物品,风是现实力量,飞翔就有了现实锚点。 +- **结论**:"当我坐到打字机前的时候,俏姑娘雷梅苔丝就一个劲儿地飞呀,飞呀,连上帝也拦她不住了。" +- **结果**:成为文学史上最经典的魔幻现实主义场景之一。 + +(/imagination-to-fact) + +### 案例 2:卡夫卡《变形记》——人变甲虫 + +- **问题**:人变成一只巨大的甲虫,读者怎么会相信? +- **方法论的使用**:卡夫卡没有解释"为什么变甲虫",而是用极其写实的细节描写甲虫的身体(坚硬的背、许多细腿)、格里高尔的反应(看闹钟、想工作、担心赶不上火车)、家人的反应(秘书主任来访)。现实细节越扎实,甲虫这个超现实设定就越可信。 +- **结论**:经过八十年阅读检验,"是否真实的问题已经不存在了",《变形记》成为经典。 +- **结果**:成为现代文学的奠基之作。 + +(/imagination-to-fact) + +### 案例 3:马尔克斯区分想象与虚幻 + +- **问题**:马尔克斯曾写了一本童话《虚度年华的海洋》,朋友坦率告诉他不喜欢,认为"虚幻至少对你来说,真是不知所云"。 +- **方法论的使用**:马尔克斯幡然醒悟——"孩子们也不喜欢虚幻,他们喜欢想象的东西。"虚幻是口技演员的木偶,想象是真人。此后他的作品都坚持"强劲的想象产生事实"。 +- **结论**:区分想象和虚幻是写奇幻内容的关键。 +- **结果**:马尔克斯成为魔幻现实主义的代表作家。 + +(/imagination-to-fact) + +## 触发场景与语言信号 + +用户会在什么情境下需要这个方法(/imagination-to-fact): + +1. 写奇幻/超现实情节,读者反馈"太假了""出戏"。 +2. 想写魔幻现实主义但不知道怎么让虚构内容可信。 +3. 写梦境/幻觉/回忆场景时缺乏真实感。 +4. 脑洞很大但写出来像胡说八道。 +5. 想学习马尔克斯/卡夫卡的写作方法。 +6. 被反馈"设定不错但没有说服力"。 + +语言信号: + +- "写得假" "不可信" "出戏" +- "魔幻现实主义怎么写" "奇幻情节" "magical realism" "imagination" +- "脑洞写出来像胡说" +- "虚构真实感" "verisimilitude" +- "读者不相信我的设定" +- "梦境怎么写" "幻觉场景" + +## 可执行步骤 + +当这个方法被激活后,按以下步骤执行(/imagination-to-fact): + +1. **识别需要转化的想象内容** + - 哪些情节/设定是超现实的?(人变甲虫、人飞上天、死人说话等) + - 完成标准:明确需要"想象-事实转化"的具体内容。 +2. **寻找现实锚点** + - 为超现实内容找一个现实的载体/物品/动作/细节: + - 飞上天 → 抓着床单(被风刮跑的现实经验) + - 人变甲虫 → 描写甲虫身体的具体细节 + 人物的日常反应(看闹钟、想工作) + - 死人说话 → 描写死人的具体状态 + 活人的日常反应 + - 锚点必须是读者有现实经验的东西。 + - 完成标准:为每个超现实内容找到至少一个现实锚点。 +3. **用写实手法写超现实内容** + - 不解释"为什么会这样"(越解释越假)。 + - 用极其写实的细节描写超现实事件中的人物反应和环境。 + - 人物的反应应该是日常的(惊讶、困惑、继续生活),不是戏剧化的。 + - 完成标准:超现实内容周围的叙述是写实的、具体的、有细节的。 +4. **检查想象 vs 虚幻** + - 问自己:读者能在现实经验中找到这个想象的锚点吗? + - 如果完全没有现实依据,就是虚幻,需要添加锚点。 + - 如果有现实依据但处理得太抽象,需要增加具体细节。 + - 完成标准:想象内容有明确的现实支撑,读者不觉得"假"。 +5. **利用"虚伪中的真实"** + - 记住文学的真实不等于现实的真实。 + - 想象、梦境、欲望都是文学真实的一部分。 + - 不需要让一切符合现实逻辑,但需要让一切符合"文学的逻辑"(内在一致)。 + - 完成标准:作品有内在一致性,读者沉浸其中不质疑。 + +## 不要在以下情况使用 + +- **严格现实主义写作**:如果作品设定就是"完全符合现实",不需要超现实元素,也不需要转化。 +- **历史/纪实写作**:必须基于事实,不能用"想象"替代事实。 +- **硬科幻**:需要符合科学逻辑,不能用"文学真实"替代科学真实。 + +(/imagination-to-fact) + +## 失败模式(作者在书中警告) + +- **把虚幻当想象**:马尔克斯的教训——写了一本童话《虚度年华的海洋》,朋友说"虚幻至少对你来说,真是不知所云"。没有现实依据的离奇就是虚幻,不是想象。 +- **过度解释超现实**:越解释"为什么人会变甲虫",读者越觉得假。卡夫卡不解释,直接用写实细节呈现,反而可信。 + +(/imagination-to-fact) + +## 盲点与时代局限 + +- 余华主要讨论魔幻现实主义和现代主义文学,没有讨论网络文学/类型文学中如何建立设定可信度(需要更系统化的世界观构建)。 +- "强劲的想象产生事实"是经验性描述,没有给出判断"现实依据是否足够"的量化标准。 + +(/imagination-to-fact) + +## 容易混淆的邻近方法 + +- **"世界观构建"(worldbuilding)**:世界观构建是系统化地设定虚构世界的规则,本方法是为单个超现实元素找现实锚点。前者是宏观,后者是微观。 +- **"写实主义"**:写实主义追求完全符合现实,本方法是让超现实内容有现实感——不是写实,是"让虚构可信"。 + +(/imagination-to-fact) + +## 与相邻单元的区分与配合 + +- 与 detail-driven-climax(细节驱动高潮)的区别:本方法关注如何让虚构内容可信(现实锚点),detail-driven-climax 关注如何用细节驱动情节高潮。两者都用细节,但目的不同——一个是建立可信度,一个是驱动情节。(注:detail-driven-climax 归 foreshadow-payoff 综合 skill。) +- 与 certainty-uncertainty-tension(确定与不确定的张力)的区分与配合:区分面——本方法让超现实内容变得确定(可信),certainty-uncertainty-tension 保留不确定性。一个是"让读者相信",一个是"让读者回味"。配合面——想象的内容可以同时保留确定性(可信)和不确定性(多义):现实锚点让读者相信,保留的多义让读者回味,同一段想象内容可以两者兼得。(注:certainty-uncertainty-tension 归 narration-pov 综合 skill。) +- 与 no-psychological-description 的配合:超现实场景中的人物反应也需要用动作/视觉代替心理分析(见 [extreme-emotion-body.md](extreme-emotion-body.md))。 +- 现实锚点往往就是驱动高潮的细节:想象锚点与伏笔细节可以共用同一个物件。 + +(/imagination-to-fact) diff --git a/framework/catalog/dsh/skills/show-and-omission/references/pov-knowledge-boundary.md b/framework/catalog/dsh/skills/show-and-omission/references/pov-knowledge-boundary.md new file mode 100644 index 0000000..49ea7c4 --- /dev/null +++ b/framework/catalog/dsh/skills/show-and-omission/references/pov-knowledge-boundary.md @@ -0,0 +1,49 @@ +# 视角人物的知识边界与信息差 + +> 来源单元:《The Sense of Style / 风格感觉》(Steven Pinker)sense-of-style/curse-of-knowledge,第 3 章,小说写作应用部分。 +> 本文件管叙事层的知识诅咒:视角人物只知道自己知道的。知识诅咒的认知机制、诊断与三破解(修订端)见 [reader-gap-diagnosis.md](reader-gap-diagnosis.md)。 + +## 方法核心:知识诅咒在叙事层的直接应用 = POV 角色只知道自己知道的 + +知识诅咒是小说写作的关键方法,尤其在多视角小说里几乎是核心工具。判断标准:**角色在 POV 段里说/想了只在他自己视角里可能的信息吗?**(/curse-of-knowledge) + +## 在小说里怎么用 + +(/curse-of-knowledge) + +- **多视角小说**:检查每个 POV 段里,角色说/想的信息是否只在他视角内。 + - 反例:写一个侦探在凶手 POV 段里说"凶手用的是 .38 口径"——侦探不知道这个,错。 +- **第一人称 POV**:"我"不能写"我"视角外的事(不能写别的房间发生了什么,除非"我"后来被告知)。 +- **第三人称限制 POV**:严格限制在角色视角内,内心独白只能来自该角色。 +- **多角色对话**:每个人的话只能基于"他此刻知道的信息"。 +- **"信息差"是叙事张力的引擎**:知识诅咒诊断 = 哪里有信息差;修复 = 让 POV 角色没看到/想到那个信息。 + +## 戏剧反讽:诅咒的反用 + +读者知道角色不知道,正是诅咒的精彩反用(《罗密欧与朱丽叶》里我们都知道朱丽叶没死,罗密欧不知道)。(/curse-of-knowledge) + +## 小说专属边界 + +- **全知叙述者**:不受知识诅咒,不该机械应用(但用太多读者会觉得"在作弊")。 +- **童话/寓言**(无明确 POV)——不适用。 +- **元小说**(故意打破视角)——是合法实验,不该当成 bug 修。 + +(/curse-of-knowledge) + +## 执行要点 + +1. 每个视角段落动笔前先写下:这个人物此刻**不该知道**什么。 +2. 逐句检查该段的对话与内心独白有没有越界(说出/想到视角外的信息)。 +3. 必须交代给读者的信息改由合法渠道进入:他人转述、事后得知、亲眼看见。 +4. 有意制造信息差时,先想清楚它服务哪种张力:读者知道角色不知道(戏剧反讽),还是角色知道读者不知道(悬念)。 + +判断标准:信息差是设计出来服务张力的,不是无意漏出去的。(执行要点据源单元小说应用部分整理;/curse-of-knowledge) + +## 中文落地说明 + +这条方法不涉及语言差异:中文小说的多视角、第一人称、第三人称限制视角同样适用,检查标准一致——每个视角人物只能说、只想他视角内的信息。中文古典小说里全知叙述者("话说""且说")是常态,用本方法时要先确认作品选择的是全知还是限制视角:选了限制视角就严格执行,选了全知就不必机械套用,但要知道全知用多了读者会觉得"在作弊"。(中文落地说明;方法本体来自/curse-of-knowledge) + +## 与相邻方法的区分 + +- 与知识诅咒本体(reader-gap-diagnosis)的关系:诅咒本体管"作者以为读者懂"(术语、跳步),是修订端的诊断;本文件管"角色知道了不该知道的",是写作端的视角纪律。同一个认知机制,两个应用面。 +- 与反逻辑(飞白)的配合:飞白是"该写的不写",视角边界是"不该写的不能写"——一个主动藏,一个被动守,见 [anti-logic.md](anti-logic.md)。 diff --git a/framework/catalog/dsh/skills/show-and-omission/references/reader-gap-diagnosis.md b/framework/catalog/dsh/skills/show-and-omission/references/reader-gap-diagnosis.md new file mode 100644 index 0000000..bb2c9d1 --- /dev/null +++ b/framework/catalog/dsh/skills/show-and-omission/references/reader-gap-diagnosis.md @@ -0,0 +1,158 @@ +# 读者为什么读不懂:知识诅咒的诊断与三破解 + +> 来源单元:《The Sense of Style / 风格感觉》(Steven Pinker)sense-of-style/curse-of-knowledge,第 3 章 — The Curse of Knowledge。 +> 本文件管修订端的诊断:写出来的东西读者跟不上,作者却查不出问题在哪。知识诅咒在小说叙事层的应用(视角边界与信息差)见 [pov-knowledge-boundary.md](pov-knowledge-boundary.md);"用具象绕过诅咒"的具体方法见 [show-vs-tell.md](show-vs-tell.md)。 + +## 原文引文 + +> The curse of knowledge is the single best explanation I know of why good people write bad prose. It simply doesn't occur to the writer that her readers don't know what she knows — that they haven't mastered the patois of her guild, can't divine the missing steps that seem too obvious to mention, have no way to visualize a scene that to her is as clear as day. And so she doesn't bother to explain the jargon, or spell out the logic, or supply the necessary detail. +> +> — Steven Pinker, *The Sense of Style*, Chapter 3 + +(/curse-of-knowledge) + +## 方法核心:这是认知机制,不是态度问题 + +知识诅咒(curse of knowledge)是一个**认知机制**,不是态度问题:一旦你掌握了一个概念(一个术语 / 一个推导 / 一个场景),你就再也无法想象"不知道它"是什么感觉。(/curse-of-knowledge) + +具体有 5 个变体(Pinker 引用心理学研究): + +1. **自我中心(egocentrism)**:小孩子无法想象另一个孩子会从不同角度看三座山模型。成年人残留版本:写作者想象不出"读者没看到的步骤"。 +2. **后见之明偏误(hindsight bias)**:知道结果的人觉得结果"显然"。 +3. **错误共识(false consensus)**:我做这个决定很自然,所以别人也会这样决定。 +4. **虚幻透明(illusory transparency)**:我知道对话的幕后,所以以为对方也能听出讽刺。 +5. **心盲(mindblindness)**:不知道"不在场"的人没看到我所看到的事。 + +诅咒还会和**功能固着(functional fixity)**与**组块化(chunking)**叠加: + +- **功能固着**:熟悉一个概念后,你只想它的"功能"(用来做什么),忘了它的"形貌"(看起来像什么、怎么构成)。 +- **组块化**:专家把 5 个具体信息压成一个词(把 5 句话变成"决策"),写出来一句对新手是 5 句的容量。 + +**自我诊断信号**:写一句时感到"显然" / "不用说" / "显然" / "obviously"——几乎一定是诅咒发作。(/curse-of-knowledge) + +## 破解三招(Pinker 推荐) + +1. **关闭回路(close the loop)**:找目标读者的代表,把草稿给他们读,标记他们卡住的地方。靠"想得更努力换位思考"没用的,必须借外力。 +2. **隔夜重读**:写完放一夜,第二天的你和昨天的你已经不同,你会更接近"目标读者"的认知状态。 +3. **反向拆解组块化**:把抽象词(决策 / 杠杆 / 赋能)拆回具体动作(谁,做了什么动作,在什么场景)。 + +(/curse-of-knowledge) + +## 书中案例 + +### 案例 1:兔错觉的学术摘要(Pinker 自己的领域) + +- **问题**:一段认知科学期刊上的摘要,说的是一个简单的知觉实验("兔错觉"),但写成 "stimulus" / "poststimulus event" / "rabbit illusion and its variants" 这种术语,同行专家(Pinker 自己,在知觉研究领域 30+ 年)都读不懂。 +- **方法论的使用**:Pinker 重写这段:"受试者闭眼伸出手臂,实验者依次轻敲手腕、手肘、肩,受试者感觉像一连串轻敲沿手臂跑上去,像兔子跳一样。"把抽象还原成具体动作。 +- **结论**:同行读不懂同行写的摘要——知识诅咒连专家都不能免疫。 +- **结果**:Pinker 用此例论证"必须 close the loop"。一个专业领域的摘要,必须让该领域的另一个专家能读懂,都要靠外部反馈,不能靠"自己再努力"。 + +(/curse-of-knowledge) + +### 案例 2:给鸟器说明书(教学场景) + +- **问题**:一位教授给班上学生发了一份组装鸟食器的说明书,20 多分钟过去,没人能装上,大家都觉得是自己的问题。 +- **方法论的使用**:重新设计说明书,关键改动:把抽象描述("合适高度")改成具体数字("4½ inches from the bottom of the perch")。 +- **结论**:写说明书的人知道"什么是什么",但忘了"看上去是什么",功能固着让步骤看起来"显然"。 +- **结果**:找学生反馈(close the loop)之后,步骤改成"显然"不再显然,都能装上了。 + +(/curse-of-knowledge) + +### 案例 3:日常邮件里的术语 + +- **问题**:同事发邮件说 "Please effectuate a leverage of the existing core competency",看不懂,但又不能回邮件承认(显得不专业)。 +- **方法论的使用**:读这封邮件的人会归因为"对方故弄玄虚"或"我水平不够",几乎不会想到是知识诅咒。 +- **结论**:诅咒的隐匿性是它最危险的地方——写作者和读者都看不到。 +- **结果**:Pinker 引 Hanlon's Razor:"用愚蠢(理解不了)足以解释,就不要用恶意(故意刁难)揣测"——但他反转:把这个原则用在自己身上,当读者读不懂,第一时间是"我没写清楚"。 + +(/curse-of-knowledge) + +## 触发场景与语言信号 + +用户会在什么情境下需要这个方法(/curse-of-knowledge): + +1. 用户写完一篇文章,收到反馈"读不懂"但自己检查不出哪里有问题——需要诅咒诊断。 +2. 用户即将开始一个非虚构写作项目(论文 / 报告 / 教程 / 公文),想要从一开始就设计"读者友好"而不是事后改。 +3. 用户给非专业读者解释一个自己擅长的概念(写科普 / 给客户讲方案 / 教新人),反复被问"简单点说"。 +4. 用户用同一种方式(术语满篇 / 跳过步骤)写了好多年,怀疑"是不是我写作方式有问题"。 +5. 用户是老师 / 培训师,反复被学生说"听不懂",想知道为什么。 + +语言信号(用户的话里出现这些就应激活): + +- "为什么我写的东西别人读不懂" / "明明很显然" / "我以为大家都懂" +- "专家也说我写得不清晰" / "同行读不下去" / "被批术语太多" +- "我讲得这么清楚,怎么还有人问" / "我是不是太专业了" +- "curse of knowledge" / "why do smart readers not get this" / "they don't know what I know" / "why is this jargon" +- "我每次都被问'这是什么'" / "解释再多,同事还是不懂" + +## 可执行步骤 + +当这个方法被激活后,按以下步骤执行(各步完成标准来自源单元)(/curse-of-knowledge): + +1. **自我诊断:这段在写给谁?这段依赖了读者已经知道的什么?** + - 完成标准:写作者能列出"读者读这段前,必须已经知道的 3 个前置信息"。如果一个都列不出,这段抽象层级太高;如果列出但没有显式给出,这段在跳步。 +2. **逐句扫描"显然" / "obviously" / "众所周知" / "不用说"这种话** + - 完成标准:全文每处"显然"标记出来,思考"对哪个读者层级是显然?"如果是"对我是显然",几乎一定是诅咒,改写。 +3. **逐句扫描"术语 / 缩写 / 行业黑话"** + - 完成标准:把所有术语列出,问"对一个该领域的入门读者,这词能解释吗?"。如果不能,第一次出现时要附简短解释;如果该术语可以用更简单的同义词替代,替代。 +4. **三破解之一:找读者反馈(close the loop)** + - 完成标准:把草稿发给至少 1 个目标读者的代表,让他标记他卡住的地方。不要"问写得清不清楚"(这种问题对方会说清楚),要"让他读完后讲一遍"(这样能看出他真懂还是假懂)。 +5. **三破解之二:隔夜重读(read after a gap)** + - 完成标准:写完一稿,至少隔一夜再读。第二天读时,"显然"不再显然的地方会自动暴露。 +6. **三破解之三:反向拆解组块化(de-chunking)** + - 完成标准:把抽象词("决策" / "杠杆" / "赋能" / "做这个分析")拆回具体动作(谁 / 做了什么 / 在什么场景)。如果拆不开,那个抽象词可能是"作者自己都没想清楚"的标签。 +7. **用"我从未"双重否定自检**:"如果我从未听过这个概念,我读这段,哪个词是第一个我需要查的?"找到那个词,看是否需要解释或换掉。 + - 完成标准:至少识别 1 个"自己写的、自己却要查"的词,解释或换掉。 + +## 不要在以下情况使用 + +- **内容本来就不该被一般人懂**:前沿学术论文 / 行业内部备忘 / 暗号——这类文本的目标就不是让外行读懂,诅咒诊断不适用。 +- **写给同行的专业文献**:知识诅咒的反应用在这里,期刊论文就该用术语。但即便如此,摘要应给非专业读者,全文可保持术语。 +- **写作目的就是筛选读者**:营销 / 招聘 JD / 投行 pitch——写作者本就想让"不专业的人"退出,知识诅咒成了"过滤器",反而有效。 +- **用户没写,只是在"想要表达"阶段**:curse-of-knowledge 假设已经有草稿,还没写之前该用 classic-style(确定姿态)。(注:classic-style 未入综合 skill 库。) +- **教学讲义里"该用术语"的部分**:大一物理课讲 F=ma 之前必须用专业术语,不能用"力" + "质量" + "加速度"反复说(虽然诅咒理论本身提醒教师检查"显然")。 + +(/curse-of-knowledge) + +## 失败模式(作者在书中警告) + +- **把"换位思考"当破解**:Pinker 明确说光靠"想得更努力"没用,必须 close the loop(外部反馈)。写作时默念"读者可能不懂"不解决问题,因为诅咒让你看不到自己看不到的东西。 +- **把诅咒归因于态度**:知识诅咒是认知机制,不是傲慢。把读者的不理解归因于"他们没文化"只会强化诅咒。 +- **反馈只问"清不清楚"**:这是元层面的问题,读者会客气地说"清楚"。要让他复述,不要让他评分。 + +(/curse-of-knowledge) + +## 盲点与时代局限 + +- 写于 2014,当时还没有 LLM 写作工具。今天的诅咒还包括"AI 生成的默认空泛"(e.g.,"在当今快速变化的时代,我们要…"这种空洞话),经典风格的破解对 AI 腔也有效,但要先识别是"AI 腔"而非"人写烂"。 +- Pinker 的"找读者反馈"默认存在一个"愿意读草稿的目标读者"。在很多场景(内部备忘 / 公开博文)没有这种读者,必须用其他破解(隔夜重读 / 找非目标读者代读)替代。 + +(/curse-of-knowledge) + +## 容易混淆的邻近方法 + +- **Dunning-Kruger 效应**:知识水平低的人高估自己,知识诅咒是反方向——知识水平高的人想象不到自己拥有的知识。这两个不是同一个机制,治疗方式也不同。 +- **"以读者为中心"写作建议**:这是常识,没有"为什么"也没有"怎么破",知识诅咒提供了具体的认知机制 + 三个可执行破解。 +- **认知负荷理论(cognitive load theory)**:知识诅咒是"信息选择"层面的问题,认知负荷是"工作记忆容量"层面的问题。两者相关但不同——诅咒让你选错了信息(太多术语),认知负荷让你选对信息后还放不下(句法嵌套太深)。 + +(/curse-of-knowledge) + +## 与相邻方法的区分(源单元内引用) + +- 与 classic-style 的区分与配合:区分面——classic-style 提供"姿态"(解药),curse-of-knowledge 提供"诊断"(病灶)。前者是"应该怎么写",后者是"为什么会写成这样"。配合方向——诅咒破解 → 经典风格可生效:先把诅咒诊断出来、补上缺失的步骤,经典风格的姿态才落得下去。(注:classic-style 未入综合 skill 库。) +- 与 web-tree-string 的区别:web-tree-string 解决"句法层级让读者累",curse-of-knowledge 解决"术语和跳步让读者看不懂"。前者是句子结构问题,后者是内容选择问题。(注:web-tree-string 未入综合 skill 库。) +- 与 metadiscourse-killer 的区分与配合:区分面——metadiscourse-killer 删"作者谈论写作本身的话",curse-of-knowledge 删"作者无意识地假设读者已经知道的步骤"。前者是自我指涉,后者是信息缺失。配合面——元话语是诅咒的"自我看不见"表现:作者看不见自己在绕着自己说话,正如看不见读者缺了什么信息,两个方法治的是同一种看不见。(注:metadiscourse-killer 为非虚构专用单元,裁剪未入库,仅存于 craft/books/。) +- 与 zombie-noun-revival 的配合:zombie 名词是诅咒的典型表现。(注:zombie noun 的中文落地例子见 [show-vs-tell.md](show-vs-tell.md) 的"过度抽象模式"节。) +- 与 show-don't-tell 的关系:诅咒是病灶,show 是治疗——用具象绕过诅咒,见 [show-vs-tell.md](show-vs-tell.md)。 + +(/curse-of-knowledge) + +## 中文落地说明 + +Pinker 以英文写作场景立论,中文落地时: + +1. **中文的"显然"信号词**:除"显然 / 不用说 / 众所周知"外,"大家都知道""不言而喻""顾名思义""懂的自然懂"同样几乎一定是诅咒发作。 +2. **中文的组块化词**:源单元给出的拆词例子本身就是中文——"决策 / 杠杆 / 赋能 / 做这个分析",这类词在中文公文腔、互联网黑话里密集出现,反向拆解直接可用(中文适配)。 +3. **中文术语邮件的对应物**:源单元案例 3 的 "Please effectuate a leverage of the existing core competency" 在中文语境对应"抓手、闭环、对齐颗粒度"式堆砌;读者同样会归因于"对方故弄玄虚"而不是知识诅咒,Hanlon's Razor 反转(第一时间想"我没写清楚")同样适用。 + +(中文落地说明;方法本体来自/curse-of-knowledge) diff --git a/framework/catalog/dsh/skills/show-and-omission/references/show-omission-checklist.md b/framework/catalog/dsh/skills/show-and-omission/references/show-omission-checklist.md new file mode 100644 index 0000000..4796a9b --- /dev/null +++ b/framework/catalog/dsh/skills/show-and-omission/references/show-omission-checklist.md @@ -0,0 +1,109 @@ +# 展示与留白检查清单 + +> 汇总六个源单元的可执行检查项,按写作进程排列:写作中 → 修订阶段 → 完稿验收。 +> 每条注明来源;方法细节与案例见 references/ 对应文件。 + +## 一、写作中:抽象标签扫描 + +写情绪、氛围、性格评价时逐条核对(/show-dont-tell): + +- [ ] 全文搜过抽象标签:英文 effective / successful / important / optimal / professional / innovative / high-quality / meaningful / efficient;中文"很 / 十分 / 充满 + 情绪词"与评价式形容词(勇敢 / 专业 / 重要 / 有效) +- [ ] 每个标签都问过"具体是什么":哪个动作 / 数字 / 场景 / 对话让你想用这个词 +- [ ] 拆不出具体内容的标签已删或已换——拆不开,说明作者自己没看清那个场景 +- [ ] 每一段都能回答"读者在这里应该看到、听到、触到什么" +- [ ] 只传信息(时间、地点、电话号码、定义、总结)的地方允许直接告知,不为 show 而 show +- [ ] 中文里没有拿四字套话当具象("灯红酒绿""心如刀绞"是成语库存,不是画面)(中文适配) + +## 二、写作中:极端情绪场景(无心理描写) + +确认人物处于狂喜 / 极度悲伤 / 恐惧 / 愤怒 / 杀人后 / 求爱等"兵荒马乱"时刻时执行(/no-psychological-description): + +- [ ] 段落里没有"他感到…""她心想…""心中充满…"式直接心理陈述(判停:人物内心平静则跳过本清单,可直接写心理,但不超过段落 1/3) +- [ ] 至少写了 3 种身体/感官维度:动作 / 视觉 / 听觉 / 身体状态(姿势、呼吸、体温、肌肉) +- [ ] 给角色一个"不由自主"的小动作:反复检查、走来走去、突然停下、机械性重复 +- [ ] 读者只凭动作就能感到情绪,不需要一句解释 +- [ ] 没有"先用心理陈述兜底、再补一个动作"的点缀式写法——动作是替代,不是装饰 + +## 三、写作中:超现实内容(想象锚点) + +写奇幻 / 梦境 / 超现实情节时逐条核对(/imagination-to-fact): + +- [ ] 列出了全部超现实设定(人变甲虫、人飞上天、死人说话等) +- [ ] 每个设定配了至少一个现实锚点:读者经验里有的物品 / 力量 / 动作 / 细节(床单之于飞天,闹钟与迟到之于变甲虫) +- [ ] 超现实部分周围是写实笔法:人物反应日常(惊讶、困惑、继续生活),不戏剧化 +- [ ] 没有解释"为什么会这样"(越解释越假) +- [ ] 全书内在一致:不符合现实逻辑可以,但必须符合作品自己的逻辑 + +## 四、写作中:冰山(一个动作扛多层信息) + +写关键场次、对话、短篇结尾时执行(/bifeiyu-iceberg): + +- [ ] 写前列了水下清单:人物心理状态 / 环境氛围 / 关系张力 / 主题暗示 / 情感重量 +- [ ] 选了一个具体动作 / 对话 / 物件承载,附着 3 个以上元素算优秀,只扛 1 个算浪费 +- [ ] 冰山比在 1/8 到 1/3 之间(水面字数 / 总字数):太多没留白,太少读不懂 +- [ ] 做过删字测试:"我觉得气氛很紧张""他很害怕"式形容词句已删,换成一个具体动作 +- [ ] 读者读完想的是"原来如此",不是"他告诉我" + +## 五、写作中:反逻辑与飞白 + +写秘密、暗流、复杂人物关系时执行(/bifeiyu-anti-logic): + +- [ ] 列过"按逻辑谁该有什么反应"的清单,标出实际没写 / 反着写的地方 +- [ ] 每一处"没写"都问过归因:没想到 → 补上;刻意 → 深挖;藏 → 设计飞白 +- [ ] 反常反应有明确指向:不该反应的人反应 → 揭示隐藏关系;该反应的人无反应 → 揭示心理距离;该反应的人反常反应 → 揭示深藏性格 +- [ ] 飞白处写了周围人的反应,没写主角的心思,读者能从周围推导主角 +- [ ] 每处空白都留了暗示——读者事后能反推"为什么没写";推不出就加暗示或删掉 +- [ ] 密度可控:短篇 1-2 处,中篇 3-5 处,长篇每章约 1 处 +- [ ] 确认不是动作戏或悬疑推理——这两类要逻辑严密,不用反逻辑 +- [ ] 没有滥用巧合:反逻辑是结构选择,巧合是偷懒 + +## 六、写作中:视角知识边界 + +写多视角 / 第一人称 / 第三人称限制视角时执行(/curse-of-knowledge): + +- [ ] 每个视角段落动笔前写过:这个人物此刻不该知道什么 +- [ ] 该段对话与内心独白没有越界(没说、没想视角外的信息;反例:侦探在凶手 POV 段说"凶手用的是 .38 口径") +- [ ] 第一人称没写"我"不在场的事(除非后来被告知) +- [ ] 第三人称限制的内心独白只来自该视角人物 +- [ ] 每个角色的话只基于他此刻知道的信息 +- [ ] 信息差是设计出来服务张力的(戏剧反讽或悬念),不是无意漏出去的 +- [ ] 全知叙述者没有用太多(用太多读者觉得"在作弊") + +## 七、修订阶段:读者读不懂的诊断 + +收到"读不懂 / 跟不上 / 术语太多"反馈,或自己怀疑跳步时执行(/curse-of-knowledge): + +- [ ] 能列出"读者读这段前必须已经知道的 3 个前置信息";列不出 = 抽象层级太高,列出但没显式给出 = 跳步 +- [ ] 全文标过"显然 / obviously / 众所周知 / 不用说 / 大家都知道 / 不言而喻"——每一处问"对哪个读者层级显然?","对我显然"就改写 +- [ ] 术语 / 缩写 / 行业黑话列过清单:入门读者能解释的留下,不能的第一次出现附简短解释,有更简单同义词就替代 +- [ ] 组块化抽象词(决策 / 杠杆 / 赋能 / 做这个分析)已拆回具体动作(谁 / 做了什么 / 在什么场景);拆不开的删 +- [ ] "我从未"双重否定自检:至少找到 1 个"自己写的、自己却要查"的词 +- [ ] close the loop:找至少 1 个目标读者代表读完**复述一遍**(不是问"清不清楚") +- [ ] 隔夜重读过一遍:第二天"显然"不再显然的地方已暴露 + +## 八、修订阶段:画面自检(show 验收) + +- [ ] 通读时逐段问"读者读完脑中应该出现什么画面",答不上的段落还在 tell(/show-dont-tell) +- [ ] "如果只能记一句"测试:目标读者读完能说出一个具体场景,而不是"它很有效"(/show-dont-tell) +- [ ] 抽象/具象比例反映内容需要:不是全 show(啰嗦)也不是全 tell(抽象)(/show-dont-tell) + +## 九、完稿验收:留白核对 + +- [ ] 留白处都有内容:水下至少有一个暗示痕迹,没有"直接不写"的偷懒省略(/bifeiyu-iceberg;/bifeiyu-anti-logic) +- [ ] 没有满篇冰山:关键场次用冰山,叙述段保持正常密度(/bifeiyu-iceberg) +- [ ] 飞白检验自问过:"我从没写到主角的心思,但读者读出来了吗?"(/bifeiyu-anti-logic) +- [ ] 全篇没有"形容词式心理描写"残留(我觉得气氛很紧张 / 他很害怕)(/bifeiyu-iceberg) + +## 十、快速排错表 + +| 症状 | 诊断 | 处方 | 来源 | +|------|------|------|------| +| 读者说"没有画面感 / 太抽象" | 抽象标签堆砌,还在 tell | 按第一节扫描替换:标签 → 动作 / 数字 / 场景 / 对话 | /show-dont-tell | +| 情绪场景苍白、像心理学教科书 | 用了直接心理分析 | 关掉心理通道,按第二节写身体感官 | /no-psychological-description | +| 读者说"写得假 / 出戏" | 超现实内容没有现实锚点,是虚幻不是想象 | 按第三节补锚点,删解释,周围写实 | /imagination-to-fact | +| 对话动作平淡、没第二层 | 水面没有扛水下 | 按第四节列水下清单,换一个动作承载 | /bifeiyu-iceberg | +| 读者困惑、读不懂留白 | 水下无迹可循,或把留白做成省略 | 加暗示痕迹;关键场次才用冰山 | /bifeiyu-iceberg;/bifeiyu-anti-logic | +| 秘密没藏住 / 反逻辑没人读出来 | 空白处没留暗示,或反逻辑点太多 | 每处空白留可反推痕迹;短篇压到 2 处以内 | /bifeiyu-anti-logic | +| 视角穿帮(人物知道了不该知道的) | POV 越界 | 按第六节逐句检查,信息改由转述 / 事后得知进入 | /curse-of-knowledge | +| 读者说"读不懂 / 跳步 / 术语多" | 知识诅咒发作 | 按第七节诊断:前置信息、"显然"扫描、close the loop、隔夜重读 | /curse-of-knowledge | +| 心理描写绕来绕去,该冲过去的地方绕开 | 90% 作家的通病:绕开极端场景 | 用身体动作冲过去,不绕 | /no-psychological-description | diff --git a/framework/catalog/dsh/skills/show-and-omission/references/show-vs-tell.md b/framework/catalog/dsh/skills/show-and-omission/references/show-vs-tell.md new file mode 100644 index 0000000..dab7fad --- /dev/null +++ b/framework/catalog/dsh/skills/show-and-omission/references/show-vs-tell.md @@ -0,0 +1,201 @@ +# 把抽象标签换成具体场景:展示而非告知 + +> 本文件管"展示"的总原则和抽象标签的替换方法。极端情绪场景的身体呈现见 [extreme-emotion-body.md](extreme-emotion-body.md);一个动作扛多层信息见 [iceberg.md](iceberg.md);读者读不懂的诊断见 [reader-gap-diagnosis.md](reader-gap-diagnosis.md)。 + +## 原文引文 + +> Classic style minimizes abstractions, which cannot be seen with the naked eye. It says: even when we write about abstract topics, we should treat them as if they were objects and forces that would be recognizable to anyone standing in a position to see them. +> +> — Steven Pinker, *The Sense of Style*, Chapter 2 + +(/show-dont-tell) + +古典风格把抽象最小化——抽象是肉眼看不见的东西。它说:即使我们写抽象主题,也要把它们当作站在某个位置上就能看到的事物和力量来处理。(/show-dont-tell,白话转述) + +## 为什么 show 强于 tell:认知基础 + +"Show, don't tell" 在 Pinker 这里有具体的认知科学基础,不只是文学修辞(/show-dont-tell): + +- 读者处理"具体动作"时,大脑的**镜像神经元(mirror neurons)**激活,部分"运行"那个动作(感受到动作)。 +- 读者处理"抽象标签"(高效 / 重要 / 优化)时,只在脑的语义层处理,没有感官激活。 +- 结果:读者被"告知"后是"理解",被"展示"后是"体验"。 + +## 方法核心:Pinker 四步法(从抽象到具象) + +1. **识别抽象标签**:凡是用 "effective" / "successful" / "important" / "optimal" / "professional" / "innovative" 这种形容词的,都是 tell。 +2. **问"具体是什么"**:"effective" = 什么具体动作 / 数字 / 场景让作者觉得 effective?答:"在 X 时间内完成了 Y,没有 Z 错误"——这就是 show。 +3. **替换为具象**:抽象形容词 → 数字 / 动作 / 场景 / 对话。 +4. **"读者能想象吗"自检**:通读,问"读者读完脑中应该出现什么画面"。如果没有,还在 tell。 + +(/show-dont-tell) + +## 对照例:Tell 与 Show + +- Tell: "The presentation was effective."(一个抽象标签) +- Show: "The CEO took notes, asked three follow-up questions, and stayed for twenty minutes after the talk ended."(三个具体动作,读者能想象) + +- Tell: "The team performed well."(抽象) +- Show: "In three months, the team reduced the bug count from 47 to 4, and shipped on schedule."(数字 + 动作) + +(/show-dont-tell) + +## Pinker 反对的"过度抽象"模式 + +这些名词化短语都属于 tell(也是 zombie noun,僵尸名词): + +- "做出一个决定" → 决定 +- "进行一个调查" → 调查 +- "提供解决方案" → 解决 + +(/show-dont-tell) + +## Pinker 自己的 show 范本 + +- **Dawkins**:"We are going to die, and that makes us the lucky ones. Most people are never going to die because they are never going to be born."(用"死"的具体状态,不是"存在"的抽象讨论) +- **Greene**:"invisible fog uniformly spread through space"(用"雾"让读者想象暗能量) +- **Pinker 的兔错觉重写**:"受试者闭眼伸出手臂,实验者依次轻敲手腕、手肘、肩,受试者感觉像一连串轻敲沿手臂跑上去,像兔子跳一样。"(用一连串具体动作) + +(/show-dont-tell) + +## 书中案例 + +### 案例 1:兔错觉的"告知 vs 展示"重写 + +- **问题**:一个学术期刊摘要,用 "stimulus" / "poststimulus event" / "rabbit illusion" 描述一个简单的知觉实验——Pinker 自己(知觉领域 30+ 年)都读不懂。 +- **方法论的使用**:Pinker 把这段重写为"具体动作"——闭眼、伸手臂、被敲手腕、敲手肘、敲肩、有兔子跳的感觉。 +- **结论**:学术摘要用"刺激"标签描述实验,同行读不懂;用"动作"描述,一般读者能懂。 +- **结果**:这是 Pinker 论证 "show, don't tell" 在科学写作中最有说服力的案例。 + +(/show-dont-tell) + +### 案例 2:Brian Greene 的暗能量说明 + +- **问题**:"暗能量"是高度抽象的物理概念。 +- **方法论的使用**:Greene 把暗能量比喻为"均匀分布在空间中的看不见的雾"——读者能想象"有东西在推"。 +- **结论**:即使是数学化的物理,也能用具象(雾)表达,不丢精度。 +- **结果**:Greene 的科普成为畅销书,是科学写作的范本之一。 + +(/show-dont-tell) + +### 案例 3:Goldstein 的哲学问题 + +- **问题**:"个体同一性"是抽象的哲学问题。 +- **方法论的使用**:Goldstein 把问题用"她"这个具体人设承载:"是什么让她是她,而不是别人"。 +- **结论**:抽象问题用具象人设,读者能跟着想。 +- **结果**:Pinker 引此为例,说"哲学散文很少能写得这样清楚"。 + +(/show-dont-tell) + +## 触发场景与语言信号 + +用户会在什么情境下需要这个方法(/show-dont-tell): + +1. 用户写完一段评估 / 描述 / 总结,抽象标签堆满,想要具象化。 +2. 用户被反馈"我读不出你到底在说什么" / "没有具体例子"——需要 show。 +3. 用户写 PPT 旁白 / 演讲稿,担心太抽象,想要可视觉化的描述。 +4. 用户写培训材料 / 教程,想要让学员"看到"怎么操作——需要动作化。 +5. 用户改一篇文章,想把"形容词堆砌"换成"具体场景"。 + +语言信号(用户的话里出现这些就应激活): + +- "没有画面感" / "太抽象" / "读者脑子里没有画面" +- "形容词太多了" / "像宣传文案" / "太空" / "太泛" +- "show don't tell" / "too abstract" / "feels generic" / "I can't picture it" +- "没有具体例子" / "no concrete detail" / "how do I make this vivid" +- "什么是'有效'" / "怎么把'重要'写具体" + +## 可执行步骤 + +当这个方法被激活后,按以下步骤执行(各步完成标准来自源单元)(/show-dont-tell): + +1. **全文搜抽象标签**:"effective / successful / important / optimal / professional / innovative / high-quality / meaningful / efficient" 等。 + - 完成标准:至少识别 5 处抽象标签,标记在文档中。 +2. **每个标签问"具体是什么"**:这个标签背后,作者看到的"具体动作 / 数字 / 场景"是什么? + - "effective" = 多少时间内完成了什么,没有出什么错? + - "successful" = 实现了哪个具体的指标,谁的反应? + - "important" = 为什么?对谁?缺了会怎样? + - "professional" = 哪个具体行为让作者觉得 professional? + - 完成标准:每个标签都有"具象版本"。 +3. **替换为具象**:用数字 / 动作 / 场景 / 对话 / 具体感官细节替代抽象标签。 + - 完成标准:改写率 > 80%。 +4. **"读者能想象吗"自检**:通读,问"读者读完脑中应该出现什么画面"。如果没有,还在 tell。 + - 完成标准:每一段都能回答"读者应该看到什么"。 +5. **"如果只能记一句"测试**:让一个目标读者读完后,问"你脑中记的最清晰的画面是什么?"。如果他说的是抽象概念("它很有效"),还在 tell;如果他说的是具体场景(那个人做了什么),是 show。 + - 完成标准:目标读者能描述具体场景,而非"这文章讲的是有效"。 +6. **平衡**:不要为了 show 而 show——一些必要的抽象(定义 / 分类 / 总结)还是需要的。判断标准:这段是否依赖读者脑中"看到"才能理解?如果是,show;如果只是传递信息(电话号码 / 日期),tell 没问题。 + - 完成标准:文章的抽象/具象比例大致反映内容需要,不是全 show(显得啰嗦)或全 tell(显得抽象)。 + +## 小说落地:怎么用 + +Show, don't tell 是小说创作的核心理念(Pinker 借的),在小说里比非虚构更重要、更深(/show-dont-tell): + +- **角色情绪**:"她感到愤怒" → 她摔门、握拳、用一种克制到近乎陌生的声音说话。 +- **场景氛围**:"阴森的森林" → 树枝像骨指戳向天空,脚下踩到软绵绵的东西。 +- **故事节奏**:一连串动作 vs 抽象总结,用动作推进。 +- **对话**:"我很高兴" → 角色说话的方式(语气、动作、表情)+ 之后发生的事。 +- **角色塑造**:不用"她很勇敢",让她在危险时做只有勇敢的人会做的事。 + +**镜像神经元视角**(Pinker 给了认知科学基础): + +- 一串具体动作激活镜像神经元,读者"运行"那个场景。 +- 抽象标签(高效 / 重要 / 创新)在小说里**完全无效**——读者读小说不是来"理解标签"的。 +- 体感细节(湿冷 / 沙哑 / 钻痛)比情绪标签(悲伤 / 恐惧)强 10 倍。 + +**同一方法的多书视角**:余华的无心理描写法把这条原则推到极端情绪场景——不写心理分析,写身体和感官(见 [extreme-emotion-body.md](extreme-emotion-body.md));毕飞宇的冰山法则从信息密度一端说同一件事——别告诉读者"紧张",用一个错误动作让读者自己紧张(见 [iceberg.md](iceberg.md))。 + +## 小说专属边界 + +以下情况不该机械 show 化(/show-dont-tell): + +- 文学修辞故意反 show(意识流、抽象诗化叙述如《了不起的盖茨比》开头)——是合法表达。 +- 第一人称 POV 主观体验("我感到一阵晕眩")——主观体验是合法的,不该全部 show 化。 +- 全知叙述者的"评估"(在哈代、托尔斯泰笔下)——是叙述特权,不该一律 show 化。 + +## 不要在这些情况使用 + +- **诗歌 / 文学散文**:那里 show-don't-tell 有更复杂的传统,包含主观体验和意识流,不是 Pinker 的"客观呈现"。 +- **法律 / 学术的高度抽象领域**:一些概念必须保持抽象(正义 / 自由 / 效率)才能讨论,show 反而失精度。 +- **新闻报道的"概要"段落**:新闻导语和概要需要快速传递信息,show 不适合,应该在主体里 show。 +- **作者的"想要模糊"**:有时作者就是想让读者感觉"模糊"(营造氛围 / 制造悬念 / 写文学),show 反而破坏意图。 +- **元评论 / 哲学讨论(含神学)**:用户写的是抽象观念为主(哲学 / 神学),那里"具象"不是目标;"存在" / "意识"这类主题本身就是抽象,强行具象反而失深度。 + +(/show-dont-tell) + +## 失败模式(作者在书中警告) + +- **"形容词 = 烂"的简化**:形容词本身不是问题,"空的形容词"才是。"X 是红色"(具体)不是 tell,"X 是漂亮"(空)是 tell。 +- **"show 永远好"的过度**:一些场景需要抽象(总结 / 定义),全 show 反而冗长。 +- **"具体 = 数字"的简化**:数字是 show 的一种,但动作、场景、对话、感官细节都是 show,不只是数字。 +- **"作者自己看到的就是 show"**:作者脑子里的"画面"是经过认知诅咒的,可能不共享给读者。要 close the loop,让目标读者说"我看到了什么"。 + +(/show-dont-tell) + +## 盲点与时代局限 + +- 写于 2014,当时还没有 LLM 写作。今天 LLM 输出的"AI 腔"大量是 tell——空泛形容词 + 抽象副词 + 没有具体动作,show-don't-tell 是直接对症。 +- Pinker 主要讲英文。中文的 show 也有其特点——中文常用四字成语(但很多是 zombie cliché),也有具象的传统(白描)。show 在中文里更需小心:不是所有"具体"都好,有些"具体"是 cliché(如"灯红酒绿"),需要 show 但非 cliché。 +- 没有处理"读者不想看"的情况:即便 show 完美,如果读者根本不想读这个主题,任何 show 都救不了。 + +(/show-dont-tell) + +## 容易混淆的邻近方法 + +- **"多用动词少用形容词"的笼统建议**:这是 show 的简化版,但 show 不只是词性选择——动作、场景、对话、感官细节都算,不仅限于动词。 +- **"数据可视化"的设计建议**:那是 show 的视觉版本,适用于数据展示,不适用于纯文字写作。 +- **"叙事医学 / 叙事心理学"的"讲故事"建议**:那是 show 的一种(故事化),但 show 不需要完整故事,一个动作 / 一句对话也是 show。 + +(/show-dont-tell) + +## 与相邻方法的区分 + +- 与知识诅咒的区别:curse-of-knowledge 是"作者以为读者懂"的认知机制,show-don't-tell 是"用具象绕过诅咒"的具体方法。**诅咒是病灶,show 是治疗。**(/show-dont-tell) + +## 中文适配 + +Pinker 以英文立论,中文落地时注意(标注"中文适配"): + +1. **中文的"具体"不等于四字成语**:"灯红酒绿""心如刀绞"是现成套话(zombie cliché),读者脑中不会生成画面,读到的是别人的旧句子;要给出这一篇独有的细节。这一条直接来自源单元的盲点小节("有些'具体'是 cliché(如'灯红酒绿')"),中文白描传统(寥寥几笔写实物实态)是 show 的本土资源。 +2. **中文抽象标签的搜法**:英文清单(effective/important 等)在中文里对应"很 / 十分 / 充满 + 情绪词"(很悲伤、十分愤怒、充满矛盾)和评价式形容词(勇敢、专业、重要、有效、高质量、有意义)。扫描时按中文的这些形态搜。 +3. **中文名词化 tell**:"做出一个决定 / 进行一个调查 / 提供解决方案"这类动词名词化短语,在中文公文腔里尤其密集,Pinker 的 zombie noun 清单在中文里直接可用。 + +(中文适配;基础内容来自/show-dont-tell) diff --git a/framework/catalog/dsh/skills/story-ending/SKILL.md b/framework/catalog/dsh/skills/story-ending/SKILL.md new file mode 100644 index 0000000..380d629 --- /dev/null +++ b/framework/catalog/dsh/skills/story-ending/SKILL.md @@ -0,0 +1,67 @@ +--- +name: story-ending +description: | + 小说收尾阶段激活。当用户问"结尾怎么写"、担心烂尾、觉得最后几章拖尾或结尾无力、 + 在开放式与闭合式结局之间拿不定主意、想从终局倒推前文、系列小说要协调本集结局与系列结局、 + 或需要判断读者读完是"被关起来"还是"被打开"时使用。 + 关键 trigger:"怎么结尾" / "收尾" / "烂尾" / "拖尾" / "结尾无力" / "结尾策略" / "结局设计" / + "倒推" / "从最后一章写起" / "chain of execution" / "完成还是打开" / "收束还是扩展" / + "戛然而止" / "意犹未尽" / "被关起来" / "被打开" / "ending"。 + 不适用于:以"无结尾"本身为表达的开放实验文学与反叙事解构作品、短抒情诗与散文、 + 刻意反高潮的平铺直叙、必须闭环的事务性场景(合同签署、手术完成、机器启动) + 与必须收束的紧急信息("立即撤离"类)。 + 与 foreshadow-payoff 交接:收束前未兑伏笔债归 foreshadow-payoff;终局姿态与倒推路径归本 Skill。 + 与 story-structure 交接:全书里程碑/四箱/中段结构成因归 story-structure;只谈收尾姿态用本 Skill。 + 与 narrative-momentum 交接:结尾前金币/势/弃读归后者。 +--- + +# story-ending 结尾设计 + +结尾要回答两个问题:终局在哪里,终局给读者什么姿态。前者是工程——先定结尾再倒推路径;后者是姿态——把读者关进一个紧凑的整体,还是放他带着更大的世界离开。 + +## 方法索引 + +按创作动作组织。方法细节、操作步骤、案例全文、原文摘录都在 references 里,本文件只做指针。 + +- **写下终局画面**:动笔前先定最后一幕的核心画面或最后一句,具体到地点、时间、动作、人物状态,不用主题陈述代替 → references/fix-final-scene.md +- **倒推债务清单**:从终局倒推每个终局元素该在前文哪里埋伏或建立,逐条列出;无法前置就改终局,不要硬写 → references/fix-final-scene.md +- **选收尾策略**:从十种收尾策略(闭合圆环、回扣开头、时间框架、空间框架、兑现、尾声、问题-解法、适配引语、看向未来、动员读者)里选,短篇 1 种、长篇 2-3 种嵌套,叠加超过 3 种显得刻意 → references/ending-strategies.md +- **层层嵌套结尾**:全书末章、章末段、段末句、句末词都要回响终局,每章末有一个小结尾与终局形成镜像、伏笔或主题回响 → references/execution-chain.md +- **找自然止点砍拖尾**:手盖住最后一段问"如果在这里结束呢?",逐段上移,直到再少一段就觉得缺 → references/natural-stop.md +- **选收尾姿态**:完成是把所有线索收束、把读者关起来;扩展是留下未答的问题、放读者带着更大的世界离开;两种姿态都合法,但小说承载的人性内容多,应优先扩展 → references/expansion-completion.md +- **诊断姿态并补代价**:判断读者读完是"被关进紧凑的整体"还是"被打开一个比书更大的世界";选扩展就加一个仪式性收束防止被当成没写完,选完成就留一个带节奏的开口防止把读者关死 → references/expansion-completion.md +- **边界与常见误区**:不适用场景、失败模式与常见误区、作者的盲点与时代局限、易混淆方法与相邻 skill 区分 → references/pitfalls-and-boundaries.md + +伏笔的埋设与回收归 `foreshadow-payoff`,章间钩子与中段奖励归 `narrative-momentum`,整体结构与开篇归 `story-structure`,整体形式诊断归 `novel-diagnosis`;本 skill 只管结尾本身。 + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|---------| +| references/fix-final-scene.md | 先有结尾再写路径的总纪律、终局画面要求与判停问法、倒推债务清单、Rowling 与 Hemingway 案例、英文原文摘录全量 | +| references/ending-strategies.md | 十种收尾策略及选择标准、开放式结局"有意 vs 无意"判断、兑现陈词滥调误区 | +| references/execution-chain.md | Chain of Execution 嵌套结尾、《了不起的盖茨比》绿光案例、逐章检验、系列双层结尾与网文分卷收尾(中文适配) | +| references/natural-stop.md | Rachmaninoff 拖尾警告、手盖法找自然止点、拖尾的信号/机制/预警 | +| references/expansion-completion.md | 完成 vs 扩展两种姿态、征兆与检验公式、代价与风险、《战争与和平》/贝多芬《第五交响曲》/《使节》案例全文、原文摘录全量、Clark 与福斯特的规则冲突与调和 | +| references/pitfalls-and-boundaries.md | 不适用边界、失败模式与常见误区索引、作者盲点、激活场景与语言信号、易混淆方法与相邻 skill 区分 | +| references/_coverage.md | 覆盖对照表(唯一追溯文件):全部方法点、案例、引文的来源落点 | + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 红线 + +- 只给当前创作阶段的建议,不越权改设定主权、不绕过检测链、不复制粘贴其它 Skill 的 owner 定义。 +- 无用户明确授权不得替用户定稿或提交 Git。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/dsh/skills/story-ending/references/_coverage.md b/framework/catalog/dsh/skills/story-ending/references/_coverage.md new file mode 100644 index 0000000..a933264 --- /dev/null +++ b/framework/catalog/dsh/skills/story-ending/references/_coverage.md @@ -0,0 +1,16 @@ +# story-ending 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| aspects-of-the-novel/expansion-vs-completion | references/expansion-completion.md | +| aspects-of-the-novel/expansion-vs-completion | references/execution-chain.md | +| aspects-of-the-novel/expansion-vs-completion | references/ending-strategies.md | +| aspects-of-the-novel/expansion-vs-completion | references/natural-stop.md | +| aspects-of-the-novel/expansion-vs-completion | references/pitfalls-and-boundaries.md | +| writing-tools-clark/write-toward-ending | references/fix-final-scene.md | +| writing-tools-clark/write-toward-ending | references/execution-chain.md | +| writing-tools-clark/write-toward-ending | references/ending-strategies.md | +| writing-tools-clark/write-toward-ending | references/natural-stop.md | +| writing-tools-clark/write-toward-ending | references/pitfalls-and-boundaries.md | diff --git a/framework/catalog/dsh/skills/story-ending/references/ending-strategies.md b/framework/catalog/dsh/skills/story-ending/references/ending-strategies.md new file mode 100644 index 0000000..d490339 --- /dev/null +++ b/framework/catalog/dsh/skills/story-ending/references/ending-strategies.md @@ -0,0 +1,41 @@ +# 十种收尾策略与选择标准 + +## 十种收尾策略 + +Clark 给出 10 种收尾策略,各条括注为落地释义(中文适配): + +1. **闭合圆环**——结尾回到开头的场景、意象或句子,首尾成环(落地释义) +2. **tieback(回扣开头)**——收束时系回开篇,与开头形成呼应(落地释义) +3. **时间框架**——用一个时间跨度收束(从何时到何时)(落地释义) +4. **空间框架**——用一个地点 / 空间收束(落地释义) +5. **兑现**——兑现前文的承诺,结算伏笔债务(落地释义;兑现的登记端归 `foreshadow-payoff`) +6. **尾声**——主结尾之后加一段尾声,交代后事(落地释义) +7. **问题-解法**——以"提出问题—解决问题"的结构收束(落地释义) +8. **适配引语**——用一句贴切的引语收束(落地释义) +9. **看向未来**——结尾指向人物或世界在故事之后的去向(落地释义;开放式结局常落在这里) +10. **动员读者**——把行动交给读者,邀请读者去做点什么(落地释义) + +## 选择标准(判断标准) + +- 选定 1-2 种主策略:**短篇 1 种,长篇 2-3 种嵌套**。 +- **判停条件:不要"叠加"超过 3 种,会显得刻意。** + +## 开放式结局:是策略之一,不是"没结尾" + +- 开放式结局是 10 种策略之一(落在"看向未来 / 留白"一带),不是"无结尾"。 +- **关键判断:这个"开放"是作者有意的,还是无意的?** 有意的开放是设计,无意的开放是没写完。 +- **开放式结局也要有"锚点"**:即使是开放式结局,也应有 1 个"锚点"(最后一句 / 最后一个动作)给读者抓住。开放的是答案,不是连抓手也撤掉。 +- 福斯特的补充视角:开放式结局是"叙事结构的特征",而"扩展"是"作者对读者意识的姿态"——前者可以是后者,但不一定是。两者区分详见 references/expansion-completion.md 与 references/pitfalls-and-boundaries.md。 +- 把"没写完"说成"扩展"是给写作失败辩护,是误区,见 references/pitfalls-and-boundaries.md。 + +## 误区:兑现陈词滥调(失败模式全量) + +- **失败模式**:用"他们从此幸福地生活在一起"等套话结尾。 +- **信号**:读者觉得"又是这个"。 +- **机制**:作者没找到属于自己的"独特终局"。 +- **预警**:10 种策略选错,或未本地化——回到本文件重选策略。 + +## 中文落地 + +- 十种策略名为中文译名,可直接用于中文网文、类型小说与严肃文学的收尾设计;选型标准(短篇 1 种、长篇嵌套、不超 3 种)不变。(中文适配) +- 中文网文"分卷收尾"在十种策略里没有现成对应,要单独设计,见 references/execution-chain.md 的中文适配条。 diff --git a/framework/catalog/dsh/skills/story-ending/references/execution-chain.md b/framework/catalog/dsh/skills/story-ending/references/execution-chain.md new file mode 100644 index 0000000..b461bf4 --- /dev/null +++ b/framework/catalog/dsh/skills/story-ending/references/execution-chain.md @@ -0,0 +1,49 @@ +# 执行链:结尾是嵌套结构,不是单点(Chain of Execution) + +## 方法细节 + +结尾不是单点——是嵌套结构,四层逐级回响终局: + +```text +全书末章 → 章节末段 → 段末句 → 句子末词 +``` + +与终局锚定(references/fix-final-scene.md)合起来构成完整框架:先定终局是"锚",执行链是让锚的回声渗透到每一层收束位置。 + +## 案例(保留原文细节) + +### Fitzgerald《了不起的盖茨比》——绿光 + +- **问题**:长篇 160 页,如何让"主题"(美国梦的破灭)贯穿? +- **方法论的使用**:第 1 章末的"绿光"(盖茨比在码头上望向黛西家)和最后一章的"绿光"互为镜像——首章末预演终章。Gatsby 第 1 章末的"绿光"预演 160 页后的"绿光"。Chain of Execution 的金标准。 +- **结论**:结尾是嵌套结构——全书末 / 章末 / 段末 / 句末都应回响终局。 +- **结果**:成为"主题回响"+"嵌套结尾"的金案例。 + +## 逐章检验(可执行步骤) + +- **操作**:逐章检查章末——每章末有没有一个"小结尾",与终局形成镜像、伏笔或主题回响。 +- **完成标准**:每章末有 1 个"小结尾",与终局形成镜像 / 伏笔 / 主题回响。 + +## 失败模式:开头/结尾无关联(全量) + +- **失败模式**:开头和结尾是"两个不同的故事"。 +- **信号**:读者读完后回想开头,觉得"和结尾没关系"。 +- **机制**:作者没先定结尾,写到中段失去方向。 +- **预警**:Chain of Execution 检验失败——回到 references/fix-final-scene.md 重新锚定终局。 + +## 系列小说的双层结尾 + +系列小说的"本集结局"和"系列结局"要协调,典型用户情境是"系列小说不知道'本集结局'和'系列结局'怎么协调——担心读者失去耐心"。 + +用 Chain of Execution 的"双层结尾"处理:**本集结尾要预演系列结尾**(伏笔 / 镜像 / 主题回响),但**不能直接剧透**。 + +担心读者失去耐心的,本卷先结算本卷债务,系列终局只做回声。(中文适配) + +## 中文适配:网文分卷收尾 + +网文分卷收尾是 Chain of Execution 的变体:**本卷末先结算本卷债务,再给下一卷留钩子**。注意两条: + +- 留钩子属于章间悬念(归 `narrative-momentum`),**不能替代本卷终局的回响**; +- 十种收尾策略里没有"留钩子"的现成对应,要单独设计。 + +(中文适配;Clark 的盲点自查也承认:中国网文"留钩子"结尾和"开放式收尾"是 Clark 框架之外的形态。) diff --git a/framework/catalog/dsh/skills/story-ending/references/expansion-completion.md b/framework/catalog/dsh/skills/story-ending/references/expansion-completion.md new file mode 100644 index 0000000..f278a96 --- /dev/null +++ b/framework/catalog/dsh/skills/story-ending/references/expansion-completion.md @@ -0,0 +1,107 @@ +# 收尾姿态二选一:完成 vs 扩展(Completion vs Expansion) + +## 方法定位 + +小说/艺术应追求的**审美姿态二选一**: + +- **完成(Completion)**:倾向于收束,把听众/读者"关"起来。戏剧、有界面的艺术可以采用。 +- **扩展(Expansion)**:倾向于打开,像交响曲终了时"那些编织起整部乐曲的音符和曲调都摆脱了束缚,它们在整体的节奏中找到了各自的自由"。**小说应追求后者。** + +## 原文摘录(全量) + +> "'扩展'。这是小说创作者必须牢牢抓住的概念。不是'完成', 而是'扩展'。不是'收束', 而是'打开'。当一曲交响乐终了, 我们会感觉那些编织起整部乐曲的音符和曲调都摆脱了束缚, 它们在整体的节奏中找到了各自的自由。" + +> "小说也能这样吗?《战争与和平》里难道不是已经有了些这样的意味?——我们的讲座从这部小说开始, 现在也该当以它作为结束。这样庞大浩繁的一部巨著。然而, 当我们沉浸其中, 难道不是有宏大的和弦在我们身后奏响吗?" + +> — E. M. 福斯特, 《小说面面观》第八讲 模式与节奏 + +## 方法细节 + +### 1. 承认两种姿态都合法 + +戏剧(拉辛的《贝蕾妮丝》)可以追求"完成"(美是舞台上的女皇);小说应追求"扩展"(因为小说承载了"人性的肥满内容")。 + +执行时的完成标准:明确说出"完成/扩展都合法,但小说应优先扩展,戏剧可以优先完成"。 + +### 2. 完成的征兆 + +- 作品结束,读者感到"被关在了一个紧凑的整体里" +- 所有问题都得到回答,所有线索都收束 +- 收尾"戛然而止"——婚姻/死亡等仪式性结尾 + +### 3. 扩展的征兆 + +- 作品结束,读者感到"被打开了一个比书更大的世界" +- 关键问题未回答,反而提出新问题 +- 收尾"意犹未尽"——托尔斯泰式的"宏大和弦在身后奏响" + +### 4. 检验公式 + +- 作品结束时,读者是感到"被关在了一个紧凑的整体里"(完成)还是"被打开了一个比书更大的世界"(扩展)? +- 注意:**扩展不等于"未完成"**(那是写作失败)。扩展是"故意打开,让你带着更大的世界离开"。 + +### 5. 扩展的代价与完成的风险 + +- **扩展的代价**:容易被读者误解为"没写完"。 +- **完成的风险**:容易让读者感到"被关起来",失去主动思考的空间。 + +### 关键认识 + +**扩展 ≠ 拖戏,完成 ≠ 烂尾。两者都需要写作功力。** 福斯特把"扩展"作为小说的标志:戏剧可以追求"完成",但小说家如果追求"完成"就阉割了小说的人性内容。 + +## 案例(全文保留) + +### 案例 1:托尔斯泰《战争与和平》——扩展的范本 + +- **问题**:《战争与和平》"庞大浩繁",战略战术的罗列都有,结束时它给人什么感觉? +- **方法论的使用**:福斯特诊断——"当我们沉浸其中, 难道不是有宏大的和弦在我们身后奏响吗? 当我们读完整个故事, 难道不是感觉其中的桩桩件件, 甚至包括战略战术的罗列, 都变成了比当初更加醒目、更加壮观的存在吗?" +- **结论**:这是"扩展"的范本——读完时,一切都"比当初更加醒目、更加壮观"。 +- **结果**:福斯特把《战争与和平》同时作为开篇和结尾——因为它是"扩展"的代表。 + +### 案例 2:贝多芬《第五交响曲》——音乐中"扩展"的对照 + +- **问题**:音乐中有"扩展"吗? +- **方法论的使用**:福斯特明示——"当管弦乐团完成演奏, 曲终弦静, 我们依旧能听到某种从未实实在在被奏响的东西。开场乐章、行板, 以及联合组成了第三部分的三声中部—谐谑曲—三声中部—终曲—三声中部—最后乐章, 一齐涌上人心头, 相互延展交汇, 成为一个统一的整体。这个统一整体, 这个全新的产物, 就是一部浑然一体的交响曲" +- **结论**:交响曲是"扩展"的范本——终了时,听众感到的统一整体"从未实实在在被奏响过",是"涌上心头"的。 +- **结果**:借此福斯特把小说的"扩展"对照音乐,说明这是艺术的高级形态。 + +### 案例 3:亨利·詹姆斯《使节》——模式 vs 扩展的反例 + +- **问题**:詹姆斯追求"完整闭环"(沙漏模式),这是"完成"还是"扩展"? +- **方法论的使用**:福斯特诊断——詹姆斯的"美"是"完成型"的,阉割了人物/情节/幻想/预言,让人物像阿肯纳顿时期的埃及艺术,"巨大的头颅, 细小的下肢, 但依然充满魅力"。 +- **结论**:沙漏模式 = 完成的极致,但"美如期而至, 只是模样太霸道了些"——小说不需要这种完成。 +- **结果**:借此福斯特说明,"完成"是合法的审美选择,但小说家应警惕它阉割人性的风险。 + +## 操作步骤(可执行) + +1. **承认两种姿态都合法** + - 完成标准:明确说出"完成/扩展都合法,但小说应优先扩展,戏剧可以优先完成"。 +2. **诊断当前作品的姿态** + - 完成标准:评估"它结束时,读者/听众感到被关起来还是被打开"。 + - 给出具体征兆:"X 在 Y 段落戛然而止(完成)/ X 在 Z 段落提出新问题(扩展)"。 +3. **选择姿态** + - 完成标准:明确说"我选完成" / "我选扩展",并说明理由。 + - 理由模板:"因为 X 是 [小说/戏剧/产品/活动],所以 [扩展/完成] 更合适"。 +4. **设计具体结尾** + - 完成标准:至少 1 条具体修改(如"在结尾段加入一个未回答的问题,让读者带走"或"加入一个仪式性收束,让读者感到完成")。 + - **不要空话(如"留下想象空间")——给可操作修改。** +5. **检查"完成"的潜在风险 / "扩展"的潜在代价** + - 完成标准:明确说"完成的风险是 [阉割人性/失去主动思考] / 扩展的代价是 [被误解为没写完]"。 + - 设计对策:对完成,加 1 个"小乐句"式节奏;对扩展,加 1 个"仪式性收束"。 + +### 完成与扩展可以组合 + +"完成 + 扩展"不矛盾:仪式感结尾(完成)之后加 1 个"小乐句"式开放元素(扩展),读者既得到闭环又带着余味离开。 + +## Clark 与福斯特的规则冲突与调和 + +Clark 的十种收尾策略里有多种"完成型"收束(闭合圆环、tieback、兑现、问题-解法,见 references/ending-strategies.md),福斯特则明确警告小说追求"完成"会阉割人性。两书规则都保留,冲突按以下方式调和: + +- Clark 的闭合策略是**可用工具**,用于结算作品自身的债务(线索回收、承诺兑现); +- 福斯特的警告是**用后的姿态检查**:结算完债务,还要看读者是被关死还是被打开; +- 调和做法即福斯特第 5 步的对策——完成式收尾要加 1 个"小乐句"式节奏开口,别让读者关在里头。 + +## 中文落地 + +- 福斯特自认的盲点之一是"西方文学中心的视角——东方叙事的'留白'传统(中国画、禅宗)与'扩展'有相似性,但未充分讨论"。中文写作正好接得上这个传统:留白、留余味、"言有尽而意无穷"是中文读者熟悉的审美,扩展式结尾在中文语境里不容易被当成没写完。 +- **(中文适配)** 但网文连载环境里,长期不闭环会消耗读者耐心:扩展要建立在"本卷债务已结算"的基础上(见 references/execution-chain.md 的分卷收尾条),打开的是世界,不是欠条。 diff --git a/framework/catalog/dsh/skills/story-ending/references/fix-final-scene.md b/framework/catalog/dsh/skills/story-ending/references/fix-final-scene.md new file mode 100644 index 0000000..11e386c --- /dev/null +++ b/framework/catalog/dsh/skills/story-ending/references/fix-final-scene.md @@ -0,0 +1,59 @@ +# 先定终局,再写路径 + +## 方法定位 + +Clark 给长篇/中篇写作的核心纪律:**先有结尾,再写路径**。不需要完整大纲,但需要"最后一幕的核心画面 / 最后一句 / 最后一个字"。 + +这是"嵌套结构 + 倒推"复合框架的地基: + +- **单层**:先定终局(本文件) +- **多层**:终局 / 章末 / 段末 / 句末形成回声网络(→ references/execution-chain.md) +- **反推**:从终局反推全书债务(本文件"倒推债务清单") + +## 原文摘录(全量) + +> I did not write from an outline, or even from much of a plan, but I knew that in the final chapter +> the good guy, who is afraid of heights and lightning, would be fighting the bad guy at midnight, +> atop a giant bridge, in a hurricane. In other words, I didn't know the stopping points along the +> way, but I wrote with an ending in mind. +> +> — Roy Peter Clark, *Writing Tools* (Tool 39) + +中文译文(译文为中文落地而附,非原书文字):我没有按大纲写作,甚至没什么像样的计划,但我知道在最后一章里,一个恐高、怕闪电的好人,会在午夜、飓风之中、一座大桥的顶端,和坏人搏斗。换句话说,我不知道沿途的停靠站在哪,但我是心里装着结尾往前写的。 + +## 方法细节 + +### 终局画面先行 + +动笔前用一两句话写下"最后一幕的核心画面"或"最后一句"。 + +- **完成标准**:画面是"具体的"——地点、时间、动作、人物状态都清楚,不是"主题陈述"。 +- **判停条件**:若用户写不出终局画面,改问两个问题——"故事最后一个画面应该是什么情绪?" / "读者合上书时,应该看到什么?" + +注意顺序:终局画面先于路径存在,但**不要求**完整大纲。Clark 本人写书时"不知道沿途的停靠站",只知道终局(见上引原文)。 + +### 倒推债务清单 + +终局定下后,从终局倒推"必须在前文埋伏 / 建立"的元素清单。 + +- **操作**:每个终局元素(人、物、场景、信息)都要回答——它必须在前文哪里埋伏或建立?逐条列出。 +- **完成标准**:每条"终局元素"都有对应的"前文位置"或"前文创建任务"。 +- **判停条件**:若终局元素与前文无关,加契诃夫之枪(伏笔登记与兑现归 `foreshadow-payoff`);若无法前置,**改终局**,不要硬写。 + +## 案例(保留原文细节) + +### 案例 1:J. K. Rowling 从最后一章写起 + +- **问题**:写 7 卷长篇,如何避免中段塌陷、保证"终局连贯"? +- **方法论的使用**:Rowling 承认她从最后一章写起——先知道"哈利与伏地魔的最终对峙"是什么样的,再反推前 6 卷如何铺垫。J. K. Rowling《哈利·波特》第一个字写的就是最后一章。 +- **结论**:先定结尾比先定开头对长篇小说结构更重要。 +- **结果**:成为"先定结尾倒推动笔"工作流的核心论据。 + +### 案例 2:Hemingway《老人与海》的最后一句 + +Hemingway《老人与海》的最后一句"他终于驶进港口,梦见狮子"在动笔前就已存在——终局先于全书。 + +## 中文落地 + +- **(中文适配)** Clark 的盲点自查里承认:"从最后一章写起"在长篇奇幻中可行(JK Rowling),但在中国当代文学(严肃文学)中罕见——后者更常"先定情绪基调",而非"先定终局画面"。中文落地时可以先定终局的**情绪**("结尾该是什么味道"),再用判停问法把情绪落成具体画面。 +- 中文网文的"留钩子"结尾(留悬念给下集)和"开放式收尾"(主角不死、敌人未灭)在 Clark 框架之外,是中文语境特有的结尾形态,处理见 references/execution-chain.md 的中文适配条。 diff --git a/framework/catalog/dsh/skills/story-ending/references/natural-stop.md b/framework/catalog/dsh/skills/story-ending/references/natural-stop.md new file mode 100644 index 0000000..23ec245 --- /dev/null +++ b/framework/catalog/dsh/skills/story-ending/references/natural-stop.md @@ -0,0 +1,26 @@ +# Rachmaninoff 警告:手盖法找自然止点,砍掉拖尾 + +## 方法定位 + +Clark 的收尾警告:**绝不要"拖尾"**(Rachmaninoff 式——像拉赫玛尼诺夫协奏曲一样没完没了)。结尾之后多出来的每一段,都在稀释终局。 + +## 操作步骤:手盖法 + +- **操作**:用手盖住最后一段,问"如果在这里结束呢?",然后反复上移——盖住最后两段、三段……直到找到"自然止点"。 +- **判停标准**:上移到"再少一段就觉得缺"的位置,那里就是自然止点;止点之后的内容全砍。(中文适配) + +## 失败模式:拖尾式收尾(全量) + +- **失败模式**:最后几段"反复总结主题 + 复述情节 + 补道德教训"。 +- **信号**:读者读到最后一段觉得"可以结束了"。 +- **机制**:作者不舍得放手,觉得"我还没说完"。 +- **预警**:Clark 的检验法——"手盖住最后一段,问'如果在这里结束呢?'",反复上移找自然止点。 + +## 与其他动作的衔接 + +- 砍掉拖尾后,回头跑一遍 references/execution-chain.md 的逐章检验,确认砍掉的部分没有带走终局回声。 +- 拖尾和"扩展"是两回事:拖尾是稀释,扩展是打开。把注水当扩展是误区,见 references/pitfalls-and-boundaries.md。 + +## 中文落地 + +中文里对应的毛病叫"画蛇添足""狗尾续貂";判断标准一样——读者在最后某一段已经觉得"可以合上书了",后面的就是拖尾。(中文适配) diff --git a/framework/catalog/dsh/skills/story-ending/references/pitfalls-and-boundaries.md b/framework/catalog/dsh/skills/story-ending/references/pitfalls-and-boundaries.md new file mode 100644 index 0000000..bc68219 --- /dev/null +++ b/framework/catalog/dsh/skills/story-ending/references/pitfalls-and-boundaries.md @@ -0,0 +1,107 @@ +# 边界、误区、盲点与激活场景 + +本文件集中承载不适用边界、失败模式与常见误区、作者盲点与时代局限、易混淆方法与相邻 skill 区分、激活场景与语言信号。 + +## 不适用场景(不要在这些情况使用本 skill) + +- **开放式实验文学**——故意不收束的作品。 +- **反叙事的解构作品**——用"无结尾"本身作为表达。 +- **短抒情诗 / 散文**——抒情节奏不靠"结局"收束。 +- **刻意反高潮的平铺直叙**——比如某些新写实主义小说。 +- **真正需要闭环的事务**——如合同签署、手术完成、机器启动,必须收束,不能"打开"。 +- **必须收束的紧急信息**——"立即撤离",不能让听众带着"还有别的方案"离开。 +- **重复使用同一类型作品**——一次决策后不必每次都重新评估。 +- **极其简短的内容**——一条推文、一句话邮件,不需要"扩展"姿态。 + +## 常见误区与失败模式(索引 + 全量) + +### Clark 三条 + +1. **"Rachmaninoff 式"拖尾**:失败模式是最后几段"反复总结主题 + 复述情节 + 道德教训"。信号:读者读到最后一段觉得"可以结束了"。机制:作者不舍得放手,觉得"我还没说完"。预警:手盖法反复上移找自然止点。→ 细节与操作见 references/natural-stop.md +2. **"开头/结尾无关联"**:失败模式是开头和结尾是"两个不同的故事"。信号:读者读完后回想开头,觉得"和结尾没关系"。机制:作者没先定结尾,写到中段失去方向。预警:Chain of Execution 检验失败。→ 细节见 references/execution-chain.md +3. **"兑现陈词滥调"**:失败模式是用"他们从此幸福地生活在一起"等套话结尾。信号:读者觉得"又是这个"。机制:作者没找到属于自己的"独特终局"。预警:10 种策略选错,或未本地化。→ 细节见 references/ending-strategies.md + +### Forster 四条 + +4. **追求"完成"到阉割人性**——詹姆斯式,普洛克路斯忒斯之床。把人物和情节削足适履,砍掉小说的人性内容。案例细节见 references/expansion-completion.md 案例 3。 +5. **追求"扩展"到拖戏**——现代电视剧/小说的注水,误把"拖"当"扩展"。扩展是读完一切更醒目,不是更松散。 +6. **强行收束于"婚姻/死亡"**——多数小说的"虎头蛇尾"。把仪式性事件当唯一收束手段。 +7. **把"未完成"当"扩展"**——写作失败的辩护。先回答这个"打开"是作者故意的还是写不下去的遮羞布(与 Clark 的"有意 vs 无意"判断合流,见 references/ending-strategies.md)。 + +## 作者的盲点 / 时代局限 + +### Clark 的盲点 + +- Clark 主要讲西方叙事(美国长篇小说 + JK Rowling 英式奇幻 + 经典文学)。中文网文"留钩子"结尾(留悬念给下集)和"开放式收尾"(主角不死、敌人未灭)需要单独讨论——这些是 Clark 框架之外的形态。 +- "从最后一章写起"在长篇奇幻中可行(JK Rowling),但在中国当代文学(严肃文学)中罕见——后者更常"先定情绪基调",而非"先定终局画面"。 + +### Forster 的盲点 + +- **音乐 vs 小说类比的限制**——音乐有"终了"但无"页码",小说有"最后一页",二者形式不同。 +- **1927 年的视角**——没看到 60 年代后的"开放结局"(新浪潮电影)的极端。 +- **西方文学中心的视角**——东方叙事的"留白"传统(中国画、禅宗)与"扩展"有相似性,但福斯特未充分讨论。 + +## 容易混淆的邻近方法论 + +### Clark 侧:inciting-incident、chekhov-gun、开放式结局 + +- 与 `inciting-incident` 的区别:那是"启动事件"(开头),这是"终局事件"(结尾)。对称结构。(inciting-incident 现归 `story-structure`) +- 与 `chekhov-gun` 的区别:那是"埋伏"(承诺),这是"兑现"(履行)。前者为结尾铺路,后者是结尾本身。(chekhov-gun 现归 `foreshadow-payoff`) +- 与"开放式结局"的区别:开放式结局是 10 种策略之一,不是"无结尾"。关键判断:作者有意还是无意的开放? + +### Forster 侧:戏剧结构、开放式结局、续集 + +- **vs 戏剧结构(Dramatic Structure)**——戏剧结构是"完成的极致",不是"扩展";但现代戏剧早已拒绝亚里士多德。 +- **vs 开放式结局(Open Ending)**——开放式结局是"叙事特征",扩展是"读者意识的姿态";前者可以是后者,但不一定。 +- **vs 续集(Sequel)**——续集是"另写一部",扩展是"在一部内打开"——不能混为一谈。 + +## 与相邻 skill 的区分 + +### Clark 侧:story-engine、chekhov-gun、gold-coins、internal-cliffhanger + +- 与 `story-engine` 的区别:那个是"贯穿全书的核心问题"(问题驱动),这个是"先定终局再反推"(答案驱动)。前者问"故事要回答什么",后者问"故事要在哪里结束"。(story-engine 现归 `concept-design`) +- 与 `chekhov-gun` 的区别:那个是"埋伏笔"(承诺),这个是"兑现伏笔"(履行)。前者是债务建立,后者是债务结算。 +- 与 `gold-coins` 的区别:那个是"沿途给奖励",这个是"终局给大奖"。前者是中段,后者是结尾。(gold-coins 现归 `narrative-momentum`) +- 与 `internal-cliffhanger` 的区别:那个是"维持叙事钩子"(局部),这个是"收束整本"(全局)。(internal-cliffhanger 现归 `narrative-momentum`) + +### Forster 侧:pattern-vs-rhythm、time-vs-value-life、开放式 vs 封闭式结局 + +- 与 `pattern-vs-rhythm` 的区别:扩展/完成是**作品终点的姿态**,模式/节奏是**作品整体的形式感**;前者管结尾,后者管全程。(pattern-vs-rhythm 现归 `novel-diagnosis`) +- 与 `time-vs-value-life` 的区别:扩展/完成是**作者姿态**,时间/价值是**体验诊断**;前者管作品选择,后者管体验效果。(time-vs-value-life 现归 `novel-diagnosis`) +- 与"开放式结局 vs 封闭式结局"的区别:后者是"叙事结构的特征",扩展/完成是"作者对读者意识的姿态"。 + +## 激活场景与语言信号 + +### 用户情境 + +1. 写到 80% 进度,发现"最后 3 章不知道写什么",担心烂尾。 +2. 写完长篇觉得"拖尾"——最后 5000 字其实是第 3 段结尾,不是终局。 +3. 系列小说不知道"本集结局"和"系列结局"怎么协调——担心读者失去耐心。 +4. 网文写到最后几章,担心"付费点后"读者弃读。 +5. 短篇不知道"最后一句"该怎么收。 +6. **写小说/剧本/演讲/课程结束的章节**——决定结尾是"收束"还是"打开"。 +7. **设计产品发布/活动收尾/演示结尾**——选"完成"(清晰闭环)还是"扩展"(留下思考空间)。 +8. **做一份报告/讲演**——决定"用结论收束"还是"用问题打开"。 +9. **策划一个有"结束感"的事件**——婚礼、毕业典礼、纪念活动,选"仪式闭环"还是"开放留白"。 +10. **读一个作品/看一个演出**——评估"它结束得让我被关起来,还是被打开了"。 +11. **教学/讲课时**——决定一节课的结尾是"总结"还是"留个悬而未决的问题"。 + +### 语言信号 + +- "怎么结尾" / "如何结尾" +- "烂尾" / "结尾无力" +- "ending" / "倒推写作" / "write toward an ending" +- "chain of execution" +- "结尾策略" / "结局设计" +- "结局如何设计" / "收尾" +- "从最后一章写起" +- "本集结局" / "系列结局" +- "我该怎么收尾" +- "完成 vs 打开 / 收束 vs 扩展" +- "X 让我感到被关起来 / 被打开" +- "X 戛然而止 / 意犹未尽" +- "我想让听众/读者带着 X 离开" +- "怎么结尾?" +- "X 是闭环 / 开放" +- "X 结束得太突兀 / X 结束得拖沓" +- "我要给 X 留白 / 收口" diff --git a/framework/catalog/dsh/skills/story-planning/SKILL.md b/framework/catalog/dsh/skills/story-planning/SKILL.md new file mode 100644 index 0000000..07f54fc --- /dev/null +++ b/framework/catalog/dsh/skills/story-planning/SKILL.md @@ -0,0 +1,93 @@ +--- +name: story-planning +description: | + 激活场景:用户在规划新故事、做故事蓝图或节拍表;纠结"凭灵感写还是按计划写";有一个想法想变成完整故事; + 凭灵感写作卡在中段、故事乱、不知道接下来写什么;写完一稿想诊断故事哪里出了问题。 + 关键 trigger:"节拍表 / beat sheet / 什么是节拍表 / 节拍表是什么 / 故事大纲 / 故事规划 / story planning / + 故事蓝图 / 写之前要做什么 / 我应该怎么规划故事 / 灵感写作 / pantsing / 计划写作 / plotting / 凭灵感写 / + 凭感觉写 / 短篇怎么开始 / 小说怎么写 / 故事写作步骤 / 我想写小说 / 我有一个想法 / 怎么把想法变成完整故事 / + 故事没头没尾 / 卡在故事中段 / 接下来写什么 / 写到第 5 稿还在找故事"。 + 不适用于:故事结构本身的定义(四箱、六里程碑见 story-structure);场景、对话、叙述层面的改稿技巧; + 作者日常写作习惯与心态调节;非虚构写作;实验性非线性写作(节拍表假设线性)。 + 与 concept-design 交接:只有模糊 idea、引擎不清 → concept-design;概念已定、要节拍表与工作流 → 本 Skill。 +--- + +# 故事规划工作流(story-planning) + +一句话定位:把"找故事"挪到动笔之前——先决定工作流,再准备和酝酿素材,用节拍表摊开全局,然后一气呵成地动笔。 + +## 方法索引 + +按创作动作组织;方法细节、案例、引文都在 references 里,这里只给一句话和指针。 + +### 选工作流:凭灵感还是做计划 + +- 凭灵感写不是不规划,是用 3-5 稿代替规划,是最昂贵的一种;三种工作流,多数人该选 Plotter → references/plan-vs-pantsing.md +- 知情灵感有两个前提:King 级的结构内化,或愿意付 5 稿重写的代价 → references/plan-vs-pantsing.md +- 自评流程:判断自己是哪一型 → 问是不是 King → 在 30 分钟节拍表与 5 个月重写之间二选一 → references/plan-vs-pantsing.md + +### 写前准备:找想法、备素材 + +- 找一个坐下来就能完成的简单想法,且它必须对你有情感价值 → references/draft-flow.md +- 用 1-2 天做前期准备:想透 1-3 个主要人物及其背景,细到"门把手的质地",哪怕根本不写进书里 → references/draft-flow.md + +### 酝酿:让无意识干活 + +- 放下 1-3 天不动笔,做梦梦到它是好信号,等"想写"的冲动自然出现再动笔 → references/draft-flow.md + +### 蓝图:用节拍表摊开全局 + +- 一个场景一条 bullet,每条写这一场的任务(mission)和关键内容,可重排、廉价修改 → references/beat-sheet.md +- 节拍表 ≠ 大纲:节拍表一行,大纲一段,大纲是节拍表的扩展,先做节拍表后做大纲 → references/beat-sheet.md +- 排序后逐一验证四箱(布局/反应/进攻/解决)与六里程碑的位置,结构定义见 story-structure → references/beat-sheet.md +- 节拍表双用途:写前规划全局,写后诊断哪里不好 → references/beat-sheet.md + +### 动笔:锚定首尾、一气呵成 + +- 动笔前定下第一句和最后一句:第一句是跳板,最后一句是降落点,中间不会迷路 → references/draft-flow.md +- 不等完美开头、不等完美状态、不中途修改,短篇应当天写完保住情绪 → references/draft-flow.md + +### 收尾:搁置再读,节拍表复盘 + +- 完稿立刻放一边,至少隔一夜(通常 2-3 天)再用陌生人的眼光重读 → references/draft-flow.md +- 写完也能做节拍表:从完稿反向列 bullet,看哪一场没有任务、哪一场位置不对 → references/beat-sheet.md + +### 跨书差异说明(两条都保留) + +- 篇幅分工:布兰德六阶段针对 5000-30000 字短篇("当天完成"是短篇标准,对长篇不适用);Brooks 节拍表针对长篇(一个故事约 60 个场景)。各管各的篇幅,详见 references/draft-flow.md 的"盲点"节与 references/beat-sheet.md 的"两种用法"节。 +- 两种节奏:布兰德让无意识酝酿领路,警告写作中途用理性干预;Brooks 让理性规划领路,动笔前摊开全局。两者不冲突,可串联——先用布兰德的前三阶段找素材并酝酿,长篇再上 Brooks 的节拍表,动笔时回到布兰德的一气呵成纪律。 + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|---------| +| references/plan-vs-pantsing.md | 灵感写作 = 用草稿做规划、三种工作流与作者立场、知情灵感两条件、Stephen King 案例、普通 Pantser 与"我没时间规划"反例、四步自评操作、触发场景与语言信号、失败模式/盲点/易混、中文适配 | +| references/beat-sheet.md | 节拍表定义原文与中文转译、本质、≠ 大纲、两种用法、为什么有效、操作法、蓝天使与作者 5 部小说案例(与 pantsing 单元同案去重合并)、直接开写反例、7 步操作(含四箱百分比与六里程碑校验)、触发场景、失败模式/盲点/易混、中文适配 | +| references/draft-flow.md | 短篇六阶段完整流程(找想法/前期准备/酝酿/充满信心地写/一气呵成/搁置重读)、R 段原文、福特方法等三案例全文、7 步操作(含诊断提问与判停)、四条不可跳、触发场景、失败模式/盲点/易混、相邻方法区分(含裁剪单元注记)、中文适配 | +| references/_coverage.md | 三个源单元的覆盖对照表 | + +## 脚本 + +| 脚本 | 用途 | +|------|------| +| references/planning-workflow-checklist.md | 规划工作流台账:工作流自评、节拍表制作与结构校验清单、短篇六阶段卡壳诊断、完稿后复盘 | + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落。 + +## 红线 + +- 只给当前创作阶段的建议,不越权改设定主权、不绕过检测链、不复制粘贴其它 Skill 的 owner 定义。 +- 无用户明确授权不得替用户定稿或提交 Git。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/dsh/skills/story-planning/references/_coverage.md b/framework/catalog/dsh/skills/story-planning/references/_coverage.md new file mode 100644 index 0000000..25e0939 --- /dev/null +++ b/framework/catalog/dsh/skills/story-planning/references/_coverage.md @@ -0,0 +1,10 @@ +# story-planning 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| becoming-a-writer/story-draft-flow | references/draft-flow.md | +| story-engineering/workflow-beat-sheet | references/beat-sheet.md | +| story-engineering/workflow-pantsing-is-planning | references/beat-sheet.md | +| story-engineering/workflow-pantsing-is-planning | references/plan-vs-pantsing.md | diff --git a/framework/catalog/dsh/skills/story-planning/references/beat-sheet.md b/framework/catalog/dsh/skills/story-planning/references/beat-sheet.md new file mode 100644 index 0000000..8415500 --- /dev/null +++ b/framework/catalog/dsh/skills/story-planning/references/beat-sheet.md @@ -0,0 +1,181 @@ +# 节拍表:用一行一条把故事全局摊开 + +来源:(Larry Brooks,《Story Engineering》(2011),Part 8 · Getting It Written) + +## 原文摘录 + +> "A beat sheet is a list of short, bulleted descriptions that define each scene in your story. They may not even be scenes at first, just moments and ideas. If you have sixty scenes in your story, create a beat sheet with sixty entries that describe the mission and the content for each scene. Each entry on the beat sheet describes what the scene does in context to story exposition. It explains why it is there." +> +> — Larry Brooks, *Story Engineering* (2011), Part 8 + +() + +中文转译(中文适配):节拍表是一份简短的 bullet 描述清单,定义你故事里的每一个场景。一开始它们甚至可以还不是场景,只是一些瞬间和想法。如果你的故事有 60 个场景,就做一份有 60 个条目的节拍表,每个条目描述该场景的任务和内容。节拍表上的每个条目都描述这个场景在整个故事铺陈中起什么作用——它解释这个场景为什么在那里。 + +## 节拍表是什么 + +节拍表是写正文之前的**最小单元规划**——把每个未来场景/节拍写成 1 行 bullet,描述 mission + 内容。它先于 outline,是"故事在脑/纸上完整走一遍"。 + +本质: + +- 1 故事 = 60 个场景(平均) +- 1 场景 = 1 行 bullet +- bullet 含:场景的 mission + 场景的关键内容 +- bullet 可重新排序,廉价修改 + +() + +## 节拍表 ≠ 大纲 + +- 大纲是"段落式",100+ 字 +- 节拍表是"列表式",1 行 +- 大纲是节拍表的扩展(从 1 行扩到 1 段) +- 节拍表先做,大纲后做 + +() + +## 节拍表的两种用法 + +1. **Pre-draft(写前)**:写正文前做,看到全局 +2. **Post-draft(写后)**:写完一稿后做,诊断"哪里不好" + +() + +## 为什么有效 + +- "找故事"在写正文前完成,不用 5 稿重写 +- 看完整序列 = 可优化全局 +- bullet 廉价修改(vs 重写章节) + +() + +## 操作法 + +- 准备:便利贴/索引卡/白板/Markdown 列表/任何能"看到全局"的工具 +- 列出:60 个 bullet +- 每个 bullet 含:场景 mission + 关键内容 +- 排序:验证 4 箱 + 6 里程碑位置 +- 修改:任何不对的地方直接动 bullet + +() + +## 案例全文 + +### 案例 1:蓝天使飞行表演 — 节拍表类比 + +- **方法**:飞行员表演前,围桌口头走完整流程 +- **结论**:"看到全局"是专业表演的关键 +- **类比**:节拍表 = 写作的"飞行员预演" + +() + +### 案例 2:作者自述 — 5 部小说都用节拍表(合并案例) + +同一案例出现在同书两个单元: 案例 2 与 案例 2,同书同案例同角度,按合并规则去重留最全: + +- **方法**:5 部小说写正文前,必做节拍表 +- **结果**:5 部全出版,1 本 8 周写完,1 本年度最佳 +- **验证**:节拍表 + 6 核 = 高效写作;同时支撑 pantsing 单元"Plotter 高效"的论点 + +(、workflow-pantsing-is-planning;合并说明为本次合并所加) + +### 案例 3:反例 — 直接开写 + +- **问题**:写作者直接开写,不做节拍表 +- **诊断**:写到 50% 发现"前面要改",但已经写完,改起来痛苦 +- **方法**:改用节拍表(即使 Post-draft),列出 60 个 bullet,重新排序 +- **结果**:看清楚问题,改起来明确 + +() + +## 操作步骤 + +1. **选 1 个故事(新/旧)** + - 完成标准:用户指定 1 个故事 + - 新 = 写前 + - 旧 = Post-draft +2. **准备工具** + - 完成标准:便利贴/白板/Markdown 列表(任选) +3. **列 bullet(目标 60 个)** + - 完成标准:60 个 bullet(可少于 60,不可多于 100) + - 每个 bullet 含: + - 场景 mission(1 句) + - 关键内容(1-2 句) +4. **排序 + 验证 4 箱** + - 完成标准:验证 4 箱位置 + - 0-25% = Setup + - 25-50% = Response + - 50-75% = Attack + - 75-100% = Resolution +5. **验证 6 里程碑** + - 完成标准:6 个里程碑都在 + - 任何缺 = 补 bullet +6. **修改** + - 完成标准:列出"哪些 bullet 要改/删/并" + - 廉价修改(vs 重写) +7. **(可选)转大纲** + - 完成标准:把 bullet 扩到段落 = 大纲 + +() + +## 触发场景 + +1. **新项目启动**:"我要写新故事,怎么规划?" +2. **改稿诊断**:"我写完一稿,但故事乱" +3. **写作卡壳**:"我不知道接下来写什么" +4. **Pantser 转 Plotter**:"我以前凭灵感写,现在想做规划" + +语言信号: + +- "节拍表 / beat sheet" +- "故事大纲 / 故事规划 / story planning" +- "我应该怎么规划故事 / 写之前要做什么" +- "故事蓝图 / story blueprint" + +() + +## 与相邻方法的区分 + +- **故事结构(structure-*)**:是"结构"(4 箱/6 里程碑,节拍表用这些),合并库中见综合 skill story-structure +- **工作流哲学(反对纯灵感)**:与本单元互补,见本包 references/plan-vs-pantsing.md +- **本单元**:是"具体规划工具"(节拍表本身) + +(;指针为本次合并更新到合并库) + +## 边界 + +### 不要在以下情况使用 + +- 写 flash fiction/中短篇——节拍表 overkill +- 写实验性/非线性——节拍表假设线性 +- 已经是大纲——节拍表已包含 + +### 作者警告的失败模式 + +- bullet 太详细——节拍表是 1 行,大纲是 1 段 +- bullet 只写"内容"不写"mission"——mission 让排序有依据 +- bullet 太多(> 100)——故事太长/太散 +- bullet 太少(< 30)——故事可能不够细 + +### 作者盲点 + +- 假设节拍表只用于 Pre-draft——Post-draft 同样有效(用于诊断) +- 假设节拍表 = 大纲——节拍表更小,大纲是扩展 +- 假设节拍表只 1 种格式——任何"看到全局"的形式都行 + +### 易混方法论 + +- "Outline"——大纲,是节拍表的扩展 +- "Story Bible"——是完整世界设定,远比节拍表宽 +- "Snowflake Method"——是从 1 句扩展到全文,不是节拍表 + +() + +## 中文适配 + +- 中文落地工具:原文的便利贴/索引卡/白板,对应中文写作者常用的码字卡片、思维导图、Excel/Markdown 列表,要求不变——能一眼看到全局。 +- 篇幅换算:Brooks 假设的纸书长篇约 60 个场景;中文网文动辄百万字,不要给全书做一张节拍表,按卷做——开一卷之前先把这一卷的场景列出来,一场景一条 bullet,每卷条数参照 30-100 的区间。 +- 中文网文连载流程里,节拍表就是"粗纲"工具;平台或编辑要求交细纲时,沿操作步骤第 7 步把每条 bullet 扩成一段即成细纲。 +- 四箱中文译名本包用:布局(Setup)/反应(Response)/进攻(Attack)/解决(Resolution);六里程碑的定义在综合 skill story-structure,这里只当校验槽位用,不重复定义。 + +(本节为本次合并补充的中文落地说明) diff --git a/framework/catalog/dsh/skills/story-planning/references/draft-flow.md b/framework/catalog/dsh/skills/story-planning/references/draft-flow.md new file mode 100644 index 0000000..377aad5 --- /dev/null +++ b/framework/catalog/dsh/skills/story-planning/references/draft-flow.md @@ -0,0 +1,233 @@ +# 短篇完整流程:从一个想法到完稿的 6 阶段 + +来源:(多萝西娅·布兰德,《成为作家》第十四章) + +## 原文摘录 + +> "你现在还没有开始写呢。你正在做的工作是前期准备。过一两天, 你将全神贯注于这些细节当中。 +> 你将理性地分析这些细节, 如果必要的话, 还要去读些参考书, 补充你的事实。 +> 然后做梦你都会梦到它。你将把这些人物分开一个一个地思考, 再把他们合在一起。 +> 你打算为这个故事做一切努力, 轮番运用你的理性思考和无意识冥想。 +> 现在, 立即开始写作。就像你自己进行第六章里的时间练习一样, +> 不要找任何借口, 拒绝任何居场的感觉, 只是开始写作。 +> 你开始写作之前, 把故事的第一句话和最后一句确定下来, +> 你会发现这非常有好处。这样你就可以用第一句作为跳板, 延伸你的故事, +> 用最后一句作为降落点。 +> 这个故事还应该在开始的当天完成。" +> +> — 多萝西娅·布兰德,《成为作家》第十四章 + +() + +## 六阶段流程总览 + +写一个完整故事(短篇 5000-30000 字)的 **6 阶段流程**。每个阶段有明确动作,不能混淆。 + +### 阶段 1:找到一个简单的想法(从清晨素材中找) + +- **来源**:清晨随手写的、开会时冒出的、生活中观察到的、读书时联想的(中文写作者可用自己的素材笔记替代,见文末中文适配) +- **标准**:这个想法必须**简单**——一个你"坐下来就能完成"的东西 +- **不要**:想写一部"涵盖我整个人生观"的长篇(那是更大的项目) +- **要**:找"小"——一个片段、一段对话、一个场景、一个瞬间 +- **判断**:这个想法对你"有情感价值"吗?有,就继续;没有,放下 + +### 阶段 2:前期准备(1-2 天,理性分析) + +- **不要马上动笔!** 这个阶段是"前期准备",不是"开始写" +- **具体动作**: + - 确定主要人物(1-2 个,最多 3 个) + - 想象他们的生活背景:长相、教育、家庭、工作、性格 + - 即使你"不会写到"这些细节,**想象它们能让你写得更可信** + - 福特的名言:"**除非我了解我要写的那个地方的最远的历史,我绝不开始动笔**" +- **持续时间**:1-2 天 +- **关键**:理性 + 无意识交替("轮番运用你的理性思考和无意识冥想") + +### 阶段 3:酝酿(做梦阶段,1-3 天) + +- 放下稿子,让无意识接管 +- 做梦都会梦到它——这是好信号 +- **不要粗暴拒绝"还没准备好"**的感觉,让它再沉一沉 +- 等待"**想写**"的冲动自然出现 +- 持续时间:1-3 天 + +### 阶段 4:充满信心地写作(立即开始) + +- **不要"等完美的开头"**——如果想不到好开头,把它放在一边,稍后再写 +- **不要"等完美状态"**——立即开始 +- **不要"中途修改"**——一气呵成 +- **减少重读**——只时不时读 1-2 个句子,确认方向 +- **关键技巧**:动笔前确定**第一句 + 最后一句** + - 第一句 = 跳板 + - 最后一句 = 降落点 + - 中间无论怎么写,都不跑题 + +### 阶段 5:一气呵成(当天写完) + +- **"在开始的当天完成"**——情绪状态要在同一天内保持 +- 中间可以暂停(喝水/休息),但**不要放下超过几个小时** +- 如果实在写不完:起身前**约定下次时间**,形成"催眠式"连续性 +- 完成的标志:写完最后一个字,合上文档 + +### 阶段 6:搁置 + 批评式阅读(2-3 天后再读) + +- 写完**立刻放一边**,不重读 +- 最少隔一夜,通常 2-3 天,实在等不及 1 周 +- 然后用"陌生人眼光"重读 + +(;裁剪单元注记为本次合并所加) + +## 为什么这 6 阶段是必要的 + +- 阶段 1-2 = 给无意识**素材** +- 阶段 3 = 让无意识**整合素材** +- 阶段 4-5 = 让意识 + 无意识**协作输出** +- 阶段 6 = 让意识**客观评价**(避免被写作时的情绪污染) + +() + +## 关键警告:四条不可跳 + +- 阶段 1-2 不能跳过(无意识没有素材) +- 阶段 3 不能省略(无意识需要时间整合) +- 阶段 4-5 不能拆分("中间停几天再写" = 风格割裂) +- 阶段 6 不能提前(写完立刻读 = 必然觉得烂) + +() + +## 案例全文 + +### 案例 1:布兰德的"前期准备" — 福特的方法 + +- **问题**:不知道写故事前要准备到什么程度 +- **方法论的使用**:福特:"我必须了解窗户的形状、门把手的质地、厨房的装潢、衣服的布料、鞋子的皮革、马车劳动的方式, 以及汽车标的种类等等。" +- **结论**:"**我在书中根本不会用到这些东西**。但是如果我不知道他的手指握的是哪种门把手, 我如何能 — 为了我自己满意 — 让我的人物握住它?" +- **结果**:写出来的人物动作**可信**,因为作者知道每个细节(即使不写出来) + +() + +### 案例 2:布兰德的"充满信心地写作"原则 + +- **问题**:不知道何时动笔 +- **方法论的使用**:"如果想不到一个好的开头, 就把它放在一边, 稍后再写" + "立即开始写作" +- **结论**:不要"等完美开头",也不要"没准备好就动笔";用**第一句 + 最后一句**锚定,立即开始 +- **结果**:故事能写完,且不跑题 + +() + +### 案例 3:布兰德的"一气呵成" — 写作风格的一致性 + +- **问题**:写到一半放下几天,前后风格割裂 +- **方法论的使用**:"**这个故事还应该在开始的当天完成**" +- **结论**:中间停太久 = 情绪状态切换 = 风格割裂("像拼接的棉被") +- **结果**:同一天写完 = 风格统一,情绪连贯 + +() + +## 操作步骤 + +激活后按以下步骤执行: + +1. **诊断:用户卡在 6 阶段的哪一步** + - 完成标准:用户能指出"我卡在阶段 X" + - 提问:"你现在的状态是 — 有想法?在准备?在酝酿?在写?在写完?在重读?" + - 判停条件:若用户说"我都还没开始" → 路由到阶段 1 +2. **阶段 1:帮用户找到"简单的想法"** + - 完成标准:用户能用 1-2 句话说出他的想法 + - 提问:"你现在最想写的**一个**东西是什么?不用大,一个场景/一段对话/一个瞬间" + - 判停条件:若用户说"我想写一部涵盖我整个人生观的长篇" → 缩到"长篇中你想先写的**一个**场景" +3. **阶段 2:帮用户列"前期准备清单"** + - 完成标准:用户能列出主要人物 + 他们的 3-5 个背景细节 + - 关键:不需要"完美",需要"够用"(福特的方法是"我要知道",不是"我要写到") +4. **阶段 3:建议"放下几天"** + - 完成标准:用户承诺"准备完后,放下 1-3 天,不动笔,让它沉" + - 关键:这是无意识整合时间,不是"拖延" +5. **阶段 4:帮用户确定"第一句 + 最后一句"** + - 完成标准:用户能给出第一句和最后一句 + - 关键:这两个锚点让你"不会迷路" + - 提问:"这个故事**开始**时,第一个画面/声音/动作是什么?**结束**时,最后一个画面/声音/动作是什么?" +6. **阶段 5:让用户承诺"当天写完"** + - 完成标准:用户能说出"我 X 时候开始,当天 X 点前写完" + - 关键:给自己一个 deadline;写不完就起身约定下次(见 `scheduled-writing`,已裁剪单元) +7. **阶段 6:让用户承诺"2-3 天后重读"** + - 完成标准:用户承诺"写完后立刻放一边,至少隔一夜再重读" + - 详见 `set-aside-the-manuscript`(已裁剪单元) + +(;裁剪单元注记为本次合并所加) + +## 触发场景 + +1. **"我想写一个短篇小说,不知道从哪开始"**——经典起步场景 +2. **"我有一个想法,怎么变成完整故事"**——有 idea,没流程 +3. **"我写故事没头没尾"**——缺结构 +4. **"我卡在故事中段"**——缺流程中的某个步骤 +5. **"我该按什么流程写一个故事"**——直接询问流程 +6. **"我有一个场景,怎么扩成完整故事"**——反向:局部到整体 +7. **"我写完一篇不知道算不算'完'"**——缺"写完"的标准 + +语言信号(用户的话里出现这些就应激活): + +- "我想写小说" +- "我有一个想法" +- "故事没头没尾" +- "怎么写完整故事" +- "短篇怎么开始" +- "我卡在中段" +- "我有个场景想扩" +- "我写完不知道算不算完" + +() + +## 边界 + +### 不要在以下情况使用 + +- **写长篇(> 30000 字)**——短篇流程不适用,长篇有自己的结构(三幕/英雄之旅等);长篇规划改用本包节拍表,见 references/beat-sheet.md(补充指针为本次合并所加) +- **已经能流畅写完整故事的人**——这是基础,不是优化 +- **非虚构/技术写作**——故事写作的 6 阶段不适用,那是调研-写作-审校的流程 +- **用户只想"写一个片段"**——那是 `fiction-scene-craft` 或 `fiction-dialogue` 范围(合并库中见综合 skill scene-craft、dialogue-craft) +- **用户的"想法"是模糊的**——阶段 1 需要"简单",模糊的想法属于动笔前的心理障碍,不是流程能解决的 + +### 作者在书中警告的失败模式 + +- **写时读太多**(ce12):写到一半读别人作品,自己的调子被污染 +- **模仿风格**(ce02):模仿别人的"味道",永远追不上 +- **写完就删**(ce04):写完立刻重读觉得烂 +- **模仿别人的内容**(f10 边界):因为别人用过某题材成功,你就跟着用 +- **公开宣告**(ce03):写之前跟朋友讲构思,招来嘲讽 + +### 作者的盲点/时代局限 + +- **1934 年没有"碎片化阅读"**——当时读长篇是常态,现在读者注意力更短 +- **"前期准备 1-2 天"在今天可能太短**——复杂题材需要更长 +- **不区分"严肃文学"和"类型小说"**——流程一样,但类型小说对"情节结构"要求更严 +- **"当天写完"对长篇不适用**——布兰德的"当天"是短篇标准 +- **没考虑"AI 协作"**——今天可以用 AI 做前期准备(列人物清单/查资料),不是"自己"准备 + +### 容易混淆的邻近方法论 + +- **"写小说"的 7 步法(通用)**——类似结构,但更工业化 +- **"雪花写作法"(Snowflake Method)**——类似,但强调"10 步扩展",不是 6 阶段 +- **"英雄之旅"(Hero's Journey)**——是**结构**,不是流程 +- **"三幕剧"**——是**结构**,不是流程 + +() + +## 与相邻方法的区分 + +原书相邻 skill,指针更新到合并库: + +- **与 `fiction-opening` 的区别**:story-draft-flow 是"整个流程"(6 阶段);fiction-opening 是"阶段 4"(开头怎么写)的具体技术。前者是宏观,后者是微观。fiction-opening 在合并库中归综合 skill story-structure(开篇部分)。 +- **与 `fiction-scene-craft` 的区别**:story-draft-flow 是"故事整体"(短篇完稿);fiction-scene-craft 是"故事内部"(场景与节奏)。前者是 size,后者是 craft。合并库中见综合 skill scene-craft。 +- **与 `fiction-dialogue` 的区别**:对话是阶段 4-5 的内部技术,合并库中见综合 skill dialogue-craft。(本条由原单元 frontmatter related_skills 补充) +- **与"搁置手稿"的区别**:本流程包含阶段 6(搁置 + 批评式阅读);搁置手稿是阶段 6 的具体技术。前者是流程,后者是单步细节。该方法未入本技能库,原指针按原文保留。 +- **与"定时写作"的区别**:定时写作是"每天 15 分钟"的纪律;本流程是"写一个完整故事"的纪律。前者是日常,后者是项目。该方法未入本技能库,原指针按原文保留。 + +## 中文适配 + +- 《成为作家》为中译本,六阶段流程、诊断提问、福特方法可直接用于中文短篇写作自查与教学,不需要转译。 +- 阶段 1 的素材来源是原书的"清晨页笔";中文写作者用自己已有的素材本、随手记、备忘录等素材积累习惯替代即可,标准不变:想法要小、要有情感价值。 +- "当天完成"是短篇标准;中文网文的日更连载模式不适用,连载的连续性问题改用节拍表按卷规划解决,见本包 references/beat-sheet.md。 +- 布兰德的盲点条款在中文语境同样成立:类型小说(悬疑、仙侠、言情)比严肃文学更吃情节结构;复杂题材的前期准备 1-2 天通常不够。 +- 阶段 6 的搁置重读与完稿心态,原书另有专章讲述,未入本技能库;此处只保留"搁置 + 批评式阅读"这一步骤本身。 + +(本节为本次合并补充的中文落地说明) diff --git a/framework/catalog/dsh/skills/story-planning/references/plan-vs-pantsing.md b/framework/catalog/dsh/skills/story-planning/references/plan-vs-pantsing.md new file mode 100644 index 0000000..e441b83 --- /dev/null +++ b/framework/catalog/dsh/skills/story-planning/references/plan-vs-pantsing.md @@ -0,0 +1,162 @@ +# 灵感写作实际是用草稿做规划 + +来源:(Larry Brooks,《Story Engineering》(2011),Introduction · Outlining vs. Organic Storytelling) + +## 原文摘录 + +> "The less story planning writers do before they begin the drafting process, the deeper hole they dig for themselves. Too often they don't even recognize the pit they're in, so when the rejection slips arrive they don't have a clue as to why. Newer writers who don't understand those fundamentals, and who try to write the same way? Not so much. It pours out of their head and basically spills all over the place. Two words: a mess." +> +> — Larry Brooks, *Story Engineering* (2011), Introduction + +() + +中文转译(中文适配):写作者在动笔之前做的故事规划越少,给自己挖的坑就越深。太多人甚至意识不到自己已经在坑里,所以退稿信寄来时,他们根本不知道原因。不懂这些基本功、还想照样写的新手呢?更糟。东西从他们脑子里倒出来,基本溅得到处都是。两个词:一团糟。 + +## 核心断言:"凭灵感写" = 用 3-5 稿做规划 + +- "凭灵感写"(pantsing)实际是"用 3-5 稿做故事规划"的另一种说法——你以为在写正文,实际在反复找故事。 +- 草稿不能规划故事,草稿只是把当下脑子里的东西倒出来。 +- 如果你脑子里的东西没结构,倒出来还是没结构。 +- "灵感写作"实际是"用 5 稿重写",极其低效,应该改成"用 30 分钟节拍表 + 1 稿正文"。 + +() + +## 三种工作流 + +1. **Pantser(纯灵感)**:不规划,直接写,写 5+ 稿 +2. **Plotter(按计划)**:节拍表 + outline + 1 稿 +3. **Informed Pantser(知情灵感)**:不写节拍表,但脑中有结构感 + +作者立场:Plotter > Informed Pantser > Pantser(对普通写作者而言)。 + +() + +### 知情灵感的两个条件 + +- 你是 King 那种天才(知道结构但不必写下来) +- 你愿意接受"5 稿重写"的代价 + +两个都不满足,就该老老实实做节拍表。 + +() + +## 操作法 + +- 接受现实:用草稿找故事 = 低效 +- 选:节拍表(30 分钟)vs 5 稿重写(5 个月) +- 多数人应选节拍表 + +() + +## 案例全文 + +### 案例 1:Stephen King — 知情 Pantser + +- **方法**:King 不写节拍表,但他脑中"已知道结构" +- **理由**:King 是天才,已 60+ 年写作,结构内化 +- **结论**:对 King 有效,对普通人无效 +- **警示**:不要学 King,学你 5 年后能成为的他 + +() + +### 案例 2:作者 5 部小说 — Plotter(合并案例) + +同一案例出现在同书两个单元: 案例 2 与 案例 2,同书同案例同角度,按合并规则去重留最全,最全版本落在 references/beat-sheet.md 的"案例 2"(含"1 本年度最佳"与"节拍表 + 6 核 = 高效写作"的验证)。本单元的论点(Plotter 高效:5 部小说都先做节拍表,5 部全出版,1 部 8 周写完)由该案例完整覆盖。 + +(;合并说明为本次合并所加) + +### 案例 3:反例 — 普通 Pantser + +- **问题**:写作者写到第 5 稿还在"找故事" +- **诊断**:用草稿做规划,极度低效 +- **方法**:改用节拍表,1 稿即用 +- **结果**:效率提升 5 倍 + +() + +### 案例 4:反例 — "我没时间规划" + +- **问题**:写作者说"灵感写作才自然,规划扼杀灵感" +- **诊断**:这是"灵感写作"派自我安慰,不是事实 +- **方法**:演示节拍表(30 分钟)效果 +- **结果**:写作者体验后改 Plotter + +() + +## 操作步骤 + +1. **自评:我现在的工作流是什么?** + - 完成标准:用户能说出"我是 Pantser / Plotter / Informed Pantser" + - 提示:看你写第 1 稿前有没有节拍表 +2. **判断:我是 King 吗?** + - 完成标准:用户诚实回答 + - 是(有 60 年写作经验)= 可继续 Pantser + - 不是 = 应转 Plotter +3. **选择:30 分钟节拍表 vs 5 稿重写** + - 完成标准:用户选 1 个 + - 多数人选 30 分钟节拍表 +4. **试用 1 次节拍表** + - 完成标准:用户做 1 稿节拍表(具体做法见本包 references/beat-sheet.md) + - 试用 = 知行 + +(;第 4 步原文指向 workflow-beat-sheet,合并库中即本包 references/beat-sheet.md) + +## 触发场景 + +1. **工作流选择**:"我应该怎么写作?" +2. **卡壳诊断**:"我写到第 5 稿还在'找故事'" +3. **辩论**:"凭灵感写 vs 计划写" +4. **教学**:"我教写作,怎么解释这个" + +语言信号: + +- "灵感写作 / pantsing / organic writing" +- "凭灵感写 / 凭感觉写" +- "plotting / 计划写作 / 大纲" +- "我写不下去 / 我找不到故事" + +() + +## 与相邻方法的区分 + +- **节拍表**:是"具体规划工具"(节拍表本身),见本包 references/beat-sheet.md;本单元是"工作流哲学"(为什么不用 pantsing),两者互补。 +- **故事结构(structure-*)**:是"结构本身",合并库中见综合 skill story-structure,与本单元互补。 + +(;指针为本次合并更新到合并库) + +## 边界 + +### 不要在以下情况使用 + +- 已经是 Plotter,想优化规划(用节拍表,见 references/beat-sheet.md) +- 已经是天才(King 那种)——不需要改 +- 实验性/非结构化写作——节拍表不适用 + +### 作者警告的失败模式 + +- 把"灵感写作"当"自然"——实际是"低效" +- 把"大纲扼杀灵感"当真——大纲是脚手架,不是枷锁 +- 把"知情灵感"当"我也能"——知情灵感需要先"知情"(知道结构) + +### 作者盲点 + +- 假设"结构" = "公式"——实际不是 +- 假设所有写作者都想要"出版"——实验作家可能不在意 +- 假设"高效"是唯一目标——有人享受 5 稿重写的过程 + +### 易混方法论 + +- "Discovery Writing"(不同作家)——类似,但更尊重 Pantser +- "Snowflake Method"——是 Plotter 的一种,1 句扩展 +- "Save the Cat"——接近,但 Snyder 强调"15 节拍" + +() + +## 中文适配 + +- pantsing / plotting 在中文写作圈没有完全对应的固定译法,常见说法是"灵感派/大纲派"或"体验派/规划派";本包译作"纯灵感/按计划/知情灵感",引用原文术语时两个都写。 +- 中文网文日更场景:"想到哪写到哪"地日更就是 pantsing,而且连载里 5 稿重写的代价更高——读者等不起。Brooks 的断言照样成立:开新一卷之前花 30 分钟把这一卷的节拍表列出来,连载比边写边找稳得多。 +- 中文类型小说(悬疑、仙侠、言情)的故事骨架与读者预期绑定更紧,"知情灵感"需要的结构内化程度比 Brooks 描述的更高,新手别走 King 路线。 +- Discovery Writing 在中文写作者中同样存在;Brooks 自己承认它接近自己的立场、只是"更尊重 Pantser",两派分歧主要是姿态,操作上都要先有结构感。 + +(本节为本次合并补充的中文落地说明) diff --git a/framework/catalog/dsh/skills/story-planning/references/planning-workflow-checklist.md b/framework/catalog/dsh/skills/story-planning/references/planning-workflow-checklist.md new file mode 100644 index 0000000..3bad365 --- /dev/null +++ b/framework/catalog/dsh/skills/story-planning/references/planning-workflow-checklist.md @@ -0,0 +1,96 @@ +# 规划工作流台账 + +用法:按篇幅分两条轨道。短篇(5000-30000 字)先做第 1 节自评,再走第 3 节六阶段;长篇或多卷连载用第 2 节节拍表。完稿后的诊断走第 4 节。每节有"过关线",不达标按标注回退。判断标准全部来自本包 references/ 各文件,这里只是填写骨架;方法细节、案例与引文见各节标注的落点。 + +--- + +## 1. 工作流自评(→ references/plan-vs-pantsing.md) + +1. 写第 1 稿之前,你做不做节拍表或任何形式的场景清单? + - □ 做 → 你是 Plotter,本节过关,直接进第 2 节 + - □ 不做,凭感觉写 → 继续往下填 +2. 不写清单,但你"脑中已经能看到结构"吗? + - □ 能 → 知情灵感(Informed Pantser)候选,继续往下填 + - □ 不能 → 纯灵感(Pantser),继续往下填 +3. King 之问:你有几十年写作积累、结构已经内化了吗? + - □ 有 → 可以继续现在的工作流 + - □ 没有 → 应该转 Plotter +4. 二选一:30 分钟的节拍表,对 5 个月的 5 稿重写。我选:____ +5. 承诺:下一部新作/下一卷开写前,先做一次节拍表。□ + +过关线:能说出自己是哪一型;不是 King 就选节拍表。"大纲扼杀灵感"不算不选的理由——大纲是脚手架,不是枷锁。 + +## 2. 节拍表制作与结构校验(→ references/beat-sheet.md) + +### 2.1 准备 + +- 工具(任选其一,要求一眼看到全局):□ 便利贴/码字卡 □ 索引卡 □ 白板 □ Markdown 列表 □ 思维导图/Excel +- 故事:____(新故事 = 写前规划;已有完稿 = Post-draft 诊断) + +### 2.2 列 bullet + +一场景一行,每条必须含两件事: + +| # | 场景任务 mission(1 句:这一场在故事铺陈中做什么,它为什么在那里) | 关键内容(1-2 句) | +|---|---|---| +| 1 | | | +| 2 | | | +| 3 | | | +| … | | | + +数量线:目标 60 条(长篇平均)。多于 100 条 = 故事太长/太散;少于 30 条 = 可能展开不够。当前共 ____ 条。 + +失败自检:□ 没有 bullet 写成了一整段(节拍表一行,大纲一段) □ 没有 bullet 只写内容不写任务(mission 是排序的依据) + +### 2.3 排序与结构校验 + +四箱位置校验(四箱与六里程碑的定义见综合 skill story-structure,这里只当校验槽位): + +| 箱 | 应在位置 | 实际对应的 bullet 编号范围 | 在位? | +|---|---|---|---| +| 布局 Setup | 0-25% | | □ | +| 反应 Response | 25-50% | | □ | +| 进攻 Attack | 50-75% | | □ | +| 解决 Resolution | 75-100% | | □ | + +六里程碑核对(任何缺 = 补 bullet): + +| 里程碑 | 对应 bullet 编号 | 缺? | +|---|---|---| +| 里程碑 1 | | □ | +| 里程碑 2 | | □ | +| 里程碑 3 | | □ | +| 里程碑 4 | | □ | +| 里程碑 5 | | □ | +| 里程碑 6 | | □ | + +### 2.4 修改与转大纲 + +- 列出要动的地方:要改的 bullet ____;要删的 ____;要并的 ____;要重排的 ____ +- 这是全文最廉价的修改阶段:能在这里动的,别留到正文重写。 +- (可选)转大纲:把每条 bullet 扩成一段,就是大纲。□ 已转 □ 不需要 + +过关线:bullet 数量在 30-100 条、每条有 mission、四箱在位、六里程碑不缺。 + +## 3. 短篇六阶段卡壳诊断(→ references/draft-flow.md) + +先回答诊断问题:"你现在的状态是——有想法?在准备?在酝酿?在写?在写完?在重读?"定位到阶段,只做对应行。若"都还没开始",从阶段 1 走。 + +| 阶段 | 过关线 | 判停条件 | +|---|---|---| +| 1 找简单想法 | 能用 1-2 句说出想法;想法简单(坐下来就能完成)且对你有情感价值 | 想写"涵盖整个人生观的长篇" → 缩到"长篇里你最想先写的一个场景";没有情感价值 → 放下换 | +| 2 前期准备(1-2 天) | 能列出 1-3 个主要人物和每人 3-5 个背景细节(长相、教育、家庭、工作、性格) | 标准是"够用"不是"完美":福特要的是"我要知道",不是"我要写到" | +| 3 酝酿(1-3 天) | 承诺"放下 1-3 天,不动笔,让它沉";做梦梦到它是好信号 | "还没准备好"的感觉不要粗暴拒绝,但也不是无限拖延——等"想写"的冲动自然出现 | +| 4 充满信心地写作 | 能给出第一句和最后一句(跳板与降落点) | 想不到好开头就把它放一边、稍后再写,不等完美状态 | +| 5 一气呵成 | 能说出"我 X 时开始,当天 X 点前写完" | 写不完:起身前约定下次时间,形成催眠式连续性;暂停可以,放下别超过几个小时 | +| 6 搁置 + 批评式阅读 | 承诺"写完立刻放一边,至少隔一夜(通常 2-3 天)再重读" | 写完立刻重读 = 必然觉得烂,禁止 | + +四条不可跳自检:□ 准备没跳过(无意识要有素材) □ 酝酿没省略(素材要时间整合) □ 写作没拆成两天(拆了风格割裂) □ 重读没提前(提前必然觉得烂) + +## 4. 完稿后诊断(Post-draft,→ references/beat-sheet.md"两种用法") + +- 从完稿反向列节拍表:实际写出来的每个场景一条 bullet,写清这一场的任务和内容。 +- 逐条对照检查:哪一场没有任务?哪一场位置不对(对照四箱百分比)?哪两场其实该并?哪一场该删? +- 重读和诊断都要在搁置至少一夜之后做,用陌生人的眼光。 + +过关线:能指出具体哪几条 bullet 要改/删/并/重排,而不是只说"故事乱"。 diff --git a/framework/catalog/dsh/skills/story-structure/SKILL.md b/framework/catalog/dsh/skills/story-structure/SKILL.md new file mode 100644 index 0000000..36e40b4 --- /dev/null +++ b/framework/catalog/dsh/skills/story-structure/SKILL.md @@ -0,0 +1,81 @@ +--- +name: story-structure +description: | + 激活场景: 为长篇/中篇小说或剧本搭结构骨架、改稿时做结构诊断、判断开头与关键节点该放在哪、 + 处理"中段塌陷""故事没启动""赌注不升""开头抓不住读者"等结构问题、写前确认短中长篇体裁。 + 关键 trigger: "故事结构 / 四箱 / 三幕 / 6 里程碑 / first plot point / FPP / 第一情节点 / midpoint / 中点 / + 煽动事件 / inciting incident / 触发事件 / Setup 段 / 开篇五件事 / 中段塌陷 / 赌注没升 / up the ante / + 不知道怎么开头 / 想不到第一句 / 开头抓不住读者 / 开头没冲突 / 主角的日常没被打破 / 开头像介绍背景 / + 短中长篇体制 / 主角转主动 / 主角太英雄 / 故事节奏 / pinch point / 夹点 / 故事没启动"。 + 不适用于: 非叙事内容(纯数据/公文)、没有可识别人物主角线的纯设定集、意识流与抒情散文(不靠外部事件推动)、 + 新闻导语与学术摘要类非虚构开头、单场景内的微观写作(归 scene-craft)、作者写作习惯与心理状态(作者培养类)。 + 与 narrative-momentum 交接:「中段塌陷」的结构成因(里程碑/赌注/四箱)归本 Skill;弃读、章末钩子、势链/金币/内悬念归后者。 +--- + +# 故事结构 (story-structure) + +管长篇叙事的结构全链路:先按体裁选对尺子,再搭"四箱 + 六里程碑"骨架,然后把开头、启动、转折逐段放对位置,全程抬升赌注,最后用诊断表改稿。 + +## 方法索引 + +### 动笔之前 + +- **定体制**:短篇、中篇、长篇是三种完全不同的体制,不是长短问题——短篇看"瞬间",中篇看"转折",长篇看"命运",写前先用体制确认表选对尺子。→ references/length-system.md +- **写开头**:想不出完美第一句就跳过,用第一句当跳板、最后一句当降落点,五种开头方法里默认用画面/动作开头。→ references/opening.md + +### 搭整体骨架 + +- **四箱切段**:全篇按功能切成 Setup(0-25%)/Response(25-50%)/Attack(50-75%)/Resolution(75-100%),每段功能不能提前也不能延后。→ references/four-boxes.md +- **六里程碑定点**:在四箱内定六个固定位置的节点(Hook、第一情节点、两个夹点、中点、第二情节点),位置是硬约束,功能比强度重要。→ references/six-milestones.md + +### 写开篇段(0-25%) + +- **Setup 五使命**:Setup 段要完成赌注、共情、背景故事、内在恶魔、钩子加伏笔五件事,缺一件后面 75% 都受影响。→ references/setup.md +- **触发事件与赌注加码**:找一个彻底打破主角生活平衡的瞬间事件(1-15%),之后每 3-5 章把赌注跨维度抬升一级,停在原地故事就死。→ references/inciting-incident.md +- **煽动事件不是第一情节点**:开篇惊天大事只负责点火,赋予意义的时刻留给 25% 处,用三问区分两者。→ references/inciting-vs-fpp.md +- **第一情节点**:25% 处让对抗力量亮相、主角接任务、赌注明确,三条缺一不可,戏剧强度不是标准。→ references/first-plot-point.md + +### 写中段(25-75%) + +- **第二段主角是漫游者**:25-50% 主角只能跑、躲、分析、观察、重算、计划招募,主动对抗和解决问题是禁忌,攒够"做不到"中点转向才有戏。→ references/part2-wanderer.md +- **中点转向**:50%±3% 处让主角从被动转主动,形式可以是觉醒、承诺、新盟友或新赌注,没有中点四箱塌成两箱。→ references/midpoint.md + +## 引用索引 + +| 文件 | 覆盖内容 | +|---|---| +| references/length-system.md | 短中长篇三种体制、各自硬规则、跨体裁转换红线、案例(《杀手》《促织》《红楼梦》《项链》) | +| references/opening.md | 三条铁律、首尾双锚点、五种开头方法及例句、开头失败模式与盲点 | +| references/four-boxes.md | 四箱切段与各段功能、三个分界点、案例(《达·芬奇密码》《末路狂花》)、诊断步骤与边界 | +| references/six-milestones.md | 六里程碑位置表、三组功能、位置硬约束、案例与"应有 vs 实际"诊断 | +| references/setup.md | Setup 段五使命与建议顺序、打勾诊断、案例与篇幅越界问题 | +| references/inciting-incident.md | 触发事件定义与判据、赌注加码楼梯、案例(9/11、《国王的演讲》)、每 3-5 章自检 | +| references/inciting-vs-fpp.md | 煽动事件与第一情节点的区别、三问判断法、操作法、案例(《末路狂花》《借刀杀人》)、Field 术语冲突标注 | +| references/first-plot-point.md | FPP 三必要功能、强度不是标准、位置约束、案例(《末路狂花》《禁闭岛》《达·芬奇密码》) | +| references/part2-wanderer.md | 第二段六类允许动作与三个禁忌、合法例外、案例与巡查步骤 | +| references/midpoint.md | 中点两功能与四种形式、50%±3% 硬约束、三种假中点、案例(《冷山》等) | +| references/_coverage.md | 唯一追溯文件:源单元 → 落点小节与内容对照 | + +## 脚本 + +- references/structure-checklists.md —— 结构诊断工作表:体制确认表、四箱切段表、六里程碑定位与"应有 vs 实际"诊断表、Setup 五使命打勾表、开篇事件三问、FPP 验证表、漫游者巡查表、中点验证表、加码楼梯表与每 3-5 章赌注自检;新稿搭骨架按第 0 节的十步顺序走。 + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 红线 + +- 只给当前创作阶段的建议,不越权改设定主权、不绕过检测链、不复制粘贴其它 Skill 的 owner 定义。 +- 无用户明确授权不得替用户定稿或提交 Git。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/dsh/skills/story-structure/references/_coverage.md b/framework/catalog/dsh/skills/story-structure/references/_coverage.md new file mode 100644 index 0000000..9fa8c14 --- /dev/null +++ b/framework/catalog/dsh/skills/story-structure/references/_coverage.md @@ -0,0 +1,17 @@ +# story-structure 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| becoming-a-writer/fiction-opening | references/opening.md | +| bifeiyu-novel-skill/bifeiyu-system | references/length-system.md | +| story-engineering/structure-first-plot-point | references/first-plot-point.md | +| story-engineering/structure-four-boxes | references/four-boxes.md | +| story-engineering/structure-inciting-vs-plot-point | references/inciting-vs-fpp.md | +| story-engineering/structure-inciting-vs-plot-point | references/inciting-incident.md | +| story-engineering/structure-midpoint | references/midpoint.md | +| story-engineering/structure-part2-wanderer | references/part2-wanderer.md | +| story-engineering/structure-setup-five-missions | references/setup.md | +| story-engineering/structure-six-milestones | references/six-milestones.md | +| writing-tools-clark/inciting-incident | references/inciting-incident.md | diff --git a/framework/catalog/dsh/skills/story-structure/references/first-plot-point.md b/framework/catalog/dsh/skills/story-structure/references/first-plot-point.md new file mode 100644 index 0000000..b922502 --- /dev/null +++ b/framework/catalog/dsh/skills/story-structure/references/first-plot-point.md @@ -0,0 +1,110 @@ +# 第一情节点(First Plot Point)必须在 1/4 位置 + +> 与煽动事件的区别见 `inciting-vs-fpp.md`;Setup 段的五件事见 `setup.md`;它在四箱中的位置见 `four-boxes.md`。 + +## 原文摘录 + +> "The very end of Part 1—the arrival of the First Plot Point moment—is the first full view of the story's primary antagonistic force... the bad guy, if you will. Full doesn't mean that the true nature of the antagonistic force is by any means complete, but rather, it's the first time the hero (and the reader) actually gets a notion of the nature and extent of the opposing force." +> +> — Larry Brooks, *Story Engineering* (2011), Part 5 + +## 方法骨架 + +First Plot Point(FPP)是故事的"启动时刻"——对抗力量亮相, 主角接到任务, 故事从 Setup 进入 Response。FPP 必须在 25% 位置(硬约束)。 + +**FPP 的 3 个必要功能**: +1. **对抗力量亮相**: 读者第一次完整看到主要对抗力量是什么 +2. **主角接任务**: 主角被推向新方向(新目标/新身份/新威胁) +3. **赌注明确**: 读者知道"主角将失去什么/获得什么" + +**3 个功能缺一不可**。最常见的失败: 主角接任务了, 但对抗力量没亮相(读者不知道威胁); 或对抗力量亮相了, 但主角没接任务(角色是被动地卷入)。 + +**FPP 的"戏剧强度"不是标准**: +- FPP 可以是"对话"(Thelma 的"我们跑吧") +- FPP 可以是"微妙"(Shutter Island 的幽灵耳语) +- FPP 可以是"动作"(大爆炸、追车) +- **关键是功能, 不是强度** + +**位置约束**: +- 小说 300-400 页: FPP 在 75-100 页 +- 剧本 110 页: FPP 在 25-30 页 +- 短篇: 单场景, FPP 几乎立刻 +- 不可偏离 25%±3% 太多 + +## 书中案例 + +### 案例 1: Thelma & Louise(《末路狂花》)的 FPP +- **位置**: 31 分钟(剧本 110 页的 28%)——略晚, 接近 25% +- **形式**: 只是一段对话, "我们不回头" +- **功能**: 对抗力量(警长追捕)亮相 + 主角接任务(亡命天涯)+ 赌注(自由 vs 监狱)明确 +- **关键**: 不是杀人事件(19:30, 太早), 而是"决定跑" + +### 案例 2: Shutter Island(《禁闭岛》)的 FPP +- **位置**: 88/369 页(24%)——几乎完美 +- **形式**: 幽灵般的耳语 "Laeddis is here" +- **功能**: 对抗力量(主角的疯狂)亮相 + 任务(找到 Laeddis)明确 +- **关键**: 戏剧强度极低, 但功能完整 + +### 案例 3: The Da Vinci Code(《达·芬奇密码》)的 FPP +- **位置**: 约 100/454 页(22%)——略早 +- **形式**: Saunière 死后, Langdon 收到神秘信息 +- **功能**: 对抗力量(神秘组织)亮相 + 任务(解读信息)明确 +- **关键**: 戏剧动作(杀人)是 inciting, FPP 是"主角接任务" + +### 案例 4: 反例——FPP 缺失 +- **问题**: 写作者写到 25% 还没让主角接任务 +- **方法论的使用**: 诊断发现: FPP = 0 +- **结论**: 故事没启动, 读者 25% 时还不知"主角要做什么" +- **结果**: 增补 FPP 场景, 故事节奏改善 + +## 可执行步骤 + +1. **找出当前 FPP** + - 完成标准: 用户能指认 1 个 FPP 候选场景 + - 提示: 找"主角接到新任务/新身份/新威胁"的瞬间 +2. **验证 3 个功能** + - 完成标准: 3 问全 yes + - 对抗力量亮相了吗? + - 主角接任务了吗? + - 赌注明确了吗? +3. **验证位置** + - 完成标准: 在 25%±3% 范围 + - 偏早(20% 之前)= Setup 段不足 + - 偏晚(30% 之后)= Setup 段过满, Response 段被压缩 +4. **强度判断(不是标准)** + - 完成标准: FPP 可以弱强度, 关键功能到位 + - 不要因为"不够精彩"就重写一个更"大"的 +5. **修稿建议** + - 完成标准: 给出 1-2 个具体改写方案 + +## 边界 + +### 不要在以下情况使用 + +- 已经在区分 inciting 和 FPP(用 `inciting-vs-fpp.md`) +- 整体 4 箱诊断(用 `four-boxes.md`) +- 多 POV 故事——每个 POV 独立诊断 + +### 作者警告的失败模式 + +- 把"开篇大事件"当 FPP——大事件往往是 inciting +- 把"主角第一次行动"当 FPP——行动 ≠ 接任务 +- 把"对抗力量完美解释"当 FPP——FPP 只需"亮相", 不需完整解释 + +### 作者盲点 + +- FPP 默认"主对抗力量"——反派小说 FPP 是反派的对手亮相 +- 假设 FPP 是"动作场景"——实际常是对话/决策 +- 假设 FPP 必须"大"——强度不是标准 + +### 易混方法论 + +- "Inciting Incident"(Field)——是 FPP 之前的引子, 不是 FPP 本身(注意 Field 与本用法的术语冲突,见 `inciting-vs-fpp.md` 的术语冲突说明) +- "Inciting Incident"(不同书)——概念混用, 本书用法不同 +- "Catalyst"(Story Grid)——接近, 但 Story Grid 给了更多功能要求 + +## 中文落地(中文适配) + +- 位置按字数换算:30 万字长篇的 FPP 落在 6.6 万-8.4 万字(25%±3%,即 22%-28%);网文黄金三章是商业例外,FPP 常被压到前 3 章内,此时要检查 Setup 五使命是否被挤掉(见 `setup.md` 的中文适配)。 +- 中文小说里 FPP 常以"对话/消息/一封信"的形式出现(家书、密令、讣告、师门传讯),强度低没关系,三功能齐全即可——与 Shutter Island 的耳语同理。 +- 武侠/仙侠的"灭门惨案"常发生在开篇:它是 inciting,不是 FPP;主角在约四分之一处"决意复仇/拜师学艺/下山追查"的那场戏才是 FPP。 diff --git a/framework/catalog/dsh/skills/story-structure/references/four-boxes.md b/framework/catalog/dsh/skills/story-structure/references/four-boxes.md new file mode 100644 index 0000000..023212a --- /dev/null +++ b/framework/catalog/dsh/skills/story-structure/references/four-boxes.md @@ -0,0 +1,111 @@ +# 四箱结构:Setup / Response / Attack / Resolution + +> 长篇(及电影剧本)的宏观骨架。箱内的具体节点见 `six-milestones.md`。 + +## 原文摘录 + +> "You are always either setting something up, responding to what you've set up, attacking the problem, or resolving the problem. The available resources of concept, character, and theme are there to make those four phases of the story dramatic and meaningful." +> +> — Larry Brooks, *Story Engineering* (2011), Part 5 + +## 方法骨架 + +整本小说/剧本/电影, 按功能可切成 4 个 25% 段落, 各自有唯一功能。这是故事工程的"物理定律"——任何故事都必然经过这 4 段, 跨段功能错位 = 故事错。 + +**4 段的功能**: + +| 段 | 位置 | 功能 | 主角状态 | +|---|---|---|---| +| Setup | 0-25% | 建立赌注/角色/伏笔/钩子 | 孤儿, 无任务 | +| Response | 25-50% | 对 First Plot Point 的反应/摸索 | wanderer, 被动 | +| Attack | 50-75% | 主动进攻/觉醒/翻转局势 | attacker, 主动 | +| Resolution | 75-100% | 收束/高潮/主题兑现 | 完成或失败 | + +**关键洞察**: +- 4 段不是"4 幕", 是"2 个 50%(Setup+Response / Attack+Resolution)各 2 段" +- 25% / 50% / 75% 是硬约束——非到 1/4 不给任务, 非到 1/2 不觉醒 +- 每段功能**不能提前**或**不能延后**——Setup 段让主角"接任务" = 错位 +- 段内是"任务驱动"——每段内 1 个主要戏剧任务, 配合次要情节 + +**2 段分界点的功能**: +- **First Plot Point (25%)**: Setup → Response, 对抗力量亮相, 任务下达(详见 `first-plot-point.md`) +- **Midpoint (50%)**: Response → Attack, 主角从被动转主动(详见 `midpoint.md`) +- **Second Plot Point (75%)**: Attack → Resolution, 重大反转/最后信息, 给高潮充能 + +**为什么是 4 箱不是 3 幕**: +- 3 幕隐含 Setup 是 50%, 但 Setup 段只能 25%(否则 Attack 段没戏) +- 4 箱 = 2 幕各 2 段, 更精确 + +## 书中案例 + +### 案例 1: The Da Vinci Code(《达·芬奇密码》) +- **Setup (0-25%)**: Langdon 在卢浮宫被告知 Saunière 谋杀, 不知道为何被追 +- **Response (25-50%)**: 整段跑, 不知道谁在追, 不知道为什么 +- **Attack (50-75%)**: Midpoint 后他开始反击, 用符号学破解密码 +- **Resolution (75-100%)**: 找到圣杯真实位置, 揭露阴谋 +- **4 段都对位, 节奏紧凑** + +### 案例 2: Thelma & Louise(《末路狂花》) +- **Setup**: 0-25%, 两位主角日常, 酒吧偶遇 +- **First Plot Point (25%)**: 杀人 + 决定跑(31 分钟) +- **Response**: 25-50%, 整段跑, 警长在追 +- **Midpoint (50%)**: 决定不停下来, 加速跑 +- **Attack**: 50-75%, 主动决策(抢劫便利店/对抗警察) +- **Resolution (75-100%)**: 飞车冲下悬崖 +- **完美的 4 箱应用** + +### 案例 3: 反例——Setup 段过满 +- **问题**: 写作者 1/4 段就把对抗力量全面展开 +- **方法论的使用**: 诊断发现: 4 箱错位——Setup 段 50% 工作量 +- **结论**: Attack 段没戏, Resolution 段仓促 +- **结果**: 改稿时让 Setup 段回到 25%, 把"全面展开"移到 Response 段 + +## 可执行步骤 + +1. **把故事切成 4 段** + - 完成标准: 用户能说"我的故事, Setup 是 0-25%, Response 25-50%, Attack 50-75%, Resolution 75-100%" + - 用页数或场景数 +2. **验证每段功能** + - 完成标准: 4 段都过如下检查: + - Setup: 主角接任务了吗?(没 = 正确) + - Response: 主角主动攻击了吗?(没 = 正确) + - Attack: 主角主动进攻了吗?(是 = 正确) + - Resolution: 故事收束了吗?(是 = 正确) +3. **诊断错位** + - 完成标准: 任何"过早"或"过晚"都被列出 + - 例: "主角在 20% 就接了任务"(太早)或 "主角在 60% 还在 wanderer"(太晚) +4. **修结构(用节拍表工具)** + - 完成标准: 列出每段内的关键场景(1-3 个) + - 工具: 节拍表(规划工作流 skill story-planning 的 beat-sheet 方法) + +## 边界 + +### 不要在以下情况使用 + +- 中短篇/flash fiction——4 箱不适用, 单场景或单弧线(体裁判断见 `length-system.md`) +- 群像小说 / 多 POV——4 箱框架对每个 POV 独立使用 +- 实验性叙事(倒叙/非线性)——4 箱的"时间顺序"假设被打破, 需调整 + +### 作者警告的失败模式 + +- 4 箱不均分——25% 是平均值, 实际可 20%/30%/30%/20% 微调 +- 把 4 箱当死规则——文学/实验小说可有意打破 +- 忽略次要情节——次要情节可有自己的 4 箱, 但不可跨主情节 + +### 作者盲点 + +- 4 箱基于商业小说/好莱坞结构——欧洲艺术电影/日本文学不适用 +- 默认"线性时间"——非线性小说需重新理解 +- 默认"单一 POV"——多 POV 需对每个 POV 独立 4 箱 + +### 易混方法论 + +- "Three-Act Structure"(Field/Syd)——是粗略版, 4 箱是其细化 +- "Save the Cat 15 Beats"(Snyder)——是 4 箱内 15 个固定节拍 +- "Hero's Journey 12 Stages"(Campbell/Vogler)——是原型模式, 不是结构框架 + +## 中文落地(中文适配) + +- 中文长篇小说没有"页"的概念,位置按**字数比例**换算:30 万字的长篇,25% ≈ 7.5 万字,50% ≈ 15 万字,75% ≈ 22.5 万字;章回体可按回数换算(120 回的 25% = 第 30 回)。 +- 网络小说的"卷"不保证与 25% 对齐:诊断时以字数比例为准,不要硬把分界点塞到卷边界;若某卷恰好跨越分界点,检查功能落在哪一章即可。 +- 群像章回体(如多线并进的家族小说):对每条主角线独立做一次四箱,与本书"多 POV 独立四箱"同理。 diff --git a/framework/catalog/dsh/skills/story-structure/references/inciting-incident.md b/framework/catalog/dsh/skills/story-structure/references/inciting-incident.md new file mode 100644 index 0000000..1ebcf54 --- /dev/null +++ b/framework/catalog/dsh/skills/story-structure/references/inciting-incident.md @@ -0,0 +1,130 @@ +# 触发事件与赌注加码:把故事启动并不断升级 + +> 触发事件与第一情节点的区别见 `inciting-vs-fpp.md`;第一情节点本身见 `first-plot-point.md`。 + +## 原文摘录 + +> The inciting incident, writes McKee in his book *Story*, radically upsets the balance of forces in +> the protagonist's life. … While the inciting incident is crucial, the big bang that propels the story, +> it is never enough. The writer must raise the stakes for the main characters—in gambling slang, must +> "up the ante." +> +> — Roy Peter Clark, *Writing Tools* (Tool 55) + +## 方法骨架 + +### 触发事件(inciting incident)是什么 + +Clark 借编剧理论家 Robert McKee 的定义:触发事件是一个**具体的瞬间事件**,**彻底打破**主角原有的生活平衡(McKee 原话:"radically upsets the balance of forces in the protagonist's life")。 + +- **位置**: 通常出现在故事的 5-15%(第一幕内, 常在第 1 章末),是"故事真正开始"的那一秒钟。Brooks 的补充:它可以在 Setup 段任何位置,通常早于 25%,可以是开篇 1-5 页内。 +- **判断标准**: 能否用一句话回答"故事是从哪一天、哪一秒钟开始的"? 答不上来 = 故事还没启动。 +- **戏剧强度**: 极高——爆炸、死亡、发现、失踪。 +- **功能**: 引起紧张, 暗示有事要发生;**不**赋予"意义/任务/赌注"——赋予意义是 25% 处第一情节点的工作。 +- **必须是事件, 不是状态**: "主角渐渐意识到 X" / "主角慢慢长大"是状态变化, 不是事件,要改写为一个**具体动作**(接到电话 / 推门发现 / 错过末班车)。 +- **反直觉点**: 触发事件不一定是坏事,也可以"看似正面"——中奖、获赠、奇遇,都可能"be careful what you wish for",把主角推入更大的麻烦。 + +两家的关系说法:没有 inciting = 故事开局无聊;Inciting 是"火",第一情节点是"开始扑火"。 + +### 加码(up the ante) + +赌博隐喻。**触发事件只是大爆炸,不够**;之后每一段时间(每章 / 每幕 / 每 1/4 体量)必须**升高赌注**。 + +- 赌注从"个人尴尬"→"家庭危机"→"国家命运"这样**逐级抬升**;若停在原地,故事就死。 +- 触发事件是**单点**、加码是**序列**;两者必须同时存在,只做一半故事都会塌。 + +**Clark 的工作口诀**:先找到那一刻(定位 inciting incident),再数清楚从那一刻起发生了**几次赌注升级**(画出 ante 的台阶),最后自检——最近 3-5 章里赌注是否真的升了? + +### 画加码楼梯 + +- 从触发事件之后开始,列出"赌注升高的节点",列 5-7 级,每级用一句"从 X 升级到 Y"。 +- 每升一次,问:"这次比上次严重在哪?(范围更大? 代价更不可逆? 涉及更多人? 时限更短?)" +- 升级必须**跨维度**——个人 → 家庭 → 社群 → 公众 → 国家 → 文明;只升"压力"不升"维度"(每次都是"主角更焦虑了",全是个人内心戏),到 1/2 处读者已麻木。 +- 若"第 3 级 = 第 2 级"——这就是 ante 没升,故事在原地打转,需**重新设计赌注维度**(从"个人尴尬"升到"家庭破裂"升到"公众事件"升到"国家危机")。 + +## 书中案例 + +### 案例 1: Robert McKee《Story》——触发事件的"理论锚点" +- **问题**: 编剧圈内部已经用"inciting incident"几十年,但新闻和非虚构作者不熟悉这个概念。 +- **方法论的使用**: Clark 直接引用 McKee 的定义("radically upsets the balance of forces in the protagonist's life"),把"打破平衡"作为触发事件的**可操作判据**;并配上 Dorothy / 龙卷风的通俗例子,让非虚构读者也能秒懂。 +- **结论**: 理论锚 + 通俗例 = 把专业编剧概念降维到长篇小说作者可用。 +- **结果**: Clark 借 McKee 把"故事如何启动"从"凭感觉开篇"变成"可定位的事件",Tool 55 因此成为全书 55 个工具里**结构层**最重的一支。 + +### 案例 2: 9/11 +《The King's Speech》——触发事件 + 5 级加码 +- **问题**: 怎样把"触发 + 加码"的双层机制在一篇文章里同时演示? +- **方法论的使用**: + - **触发事件(单点)**: Clark 写自己 2001 年 9 月 11 日早上在 Florida 看 *Today Show* 的那一刻——Matt Lauer 突然被打断、第二架飞机撞入南塔——"A bolt from the blue. The inciting incident of our lifetimes." + - **加码(连续)**: Clark 列出 9/11 之后十年"赌注如何被持续抬高"——机场搜身、阿富汗伊拉克战争、刑讯、监听、经济衰退、移民和穆斯林被污名化、奥巴马击毙本·拉登;从"震惊"一路抬到"国家制度被撼动"。 + - **电影对照**: Clark 用《The King's Speech》(《国王的演讲》)给出**5 步加码时间表**——父亲去世(1) → 哥哥退位(2) → 希特勒上台(3) → 希特勒用 radio(4) → 新国王必须 radio 演讲(5)——"from a mild form of personal humiliation at the beginning, to the fate of the nation at the end." +- **结论**: 同一个故事,触发事件是**单点**、加码是**序列**;两者必须同时存在,只做一半故事都会塌。 +- **结果**: 9/11 段落成为 Clark 讲"触发事件力量"的金案例;《King's Speech》5 步列表成为"如何画 ante 楼梯"的标准范本。 + +### 触发事件的范例(Brooks 一侧) + +- 《末路狂花》(Thelma & Louise): 19:30 酒吧杀人事件——戏剧强度极高,但它只是煽动,不是第一情节点。 +- 《借刀杀人》(Collateral): 开场出租车顶掉下一具尸体——极高强度的煽动事件。 +- 反例:写"开篇 1 页主角父亲被谋杀"并立即把它当第一情节点用,等于故事启动过早,Setup 段被挤掉(详见 `inciting-vs-fpp.md` 案例 3)。 + +## 可执行步骤 + +1. **定位触发事件(给故事找出"那一刻")** + - 让用户用一句话回答:"你的故事是从哪一天、哪一秒钟、哪一个事件开始的?" + - 检验该事件是否**符合 McKee 定义**:"radically upsets the balance of forces in the protagonist's life"——即主角的日常**真的**被打碎了,不是"生活里出了一点小麻烦"。 + - 完成标准: 用户能用一句话定位一个**具体、可识别的瞬间事件**,且该事件前后主角生活平衡**可对比**(前: 稳定 / 后: 被打破)。 + - 判停条件: 若用户的"触发事件"其实是"主角慢慢长大" / "主角渐渐觉醒"——这是状态变化,**不是事件**,需改写为一个**具体动作**(接到电话 / 推门发现 / 错过末班车)。 +2. **列出加码时间表(画出 ante 的楼梯)** + - 从触发事件之后开始,让用户列出"赌注升高的节点"——每升一次,问:"这次比上次严重在哪?(范围更大? 代价更不可逆? 涉及更多人? 时限更短?)" + - 套用《King's Speech》模板: 列 5-7 步,每步用一句"从 X 升级到 Y"。 + - 完成标准: 一份**按时间顺序**的加码表,**至少 5 级**;每一级比上一级**赌注更高**(可量化: 影响范围 / 不可逆程度 / 时间压力 / 涉及角色数)。 + - 判停条件: 若用户的加码表里"第 3 级 = 第 2 级"——这就是 ante 没升,故事在原地打转,需让用户**重新设计赌注维度**(从"个人尴尬"升到"家庭破裂"升到"公众事件"升到"国家危机")。 +3. **每 3-5 章自检赌注(中段不塌陷的保险机制)** + - 写完每 3-5 章,问用户:"最近这段的赌注,比 3-5 章前更高吗? 如果删掉这段,故事会失去什么?" + - 若"删掉这段不影响赌注"——这段就是"中段塌陷"的元凶,需要**重写或删除**。 + - 完成标准: 用户能在每个 3-5 章节点**自证赌注升级**;若不能,需触发一次"加码回炉"。 + - 判停条件: 若整本书只有"开篇 + 结尾"两次赌注,中间是平的——这是中段塌陷的典型结构,**必须**插入至少 2-3 个中间加码点(可借助"be careful what you wish for"——新获得的东西变成新威胁)。 + +空白表格见 `../references/structure-checklists.md` 的"加码楼梯表"与"每 3-5 章赌注自检"。 + +## 边界 + +### 不要在以下情况使用 + +- **短篇集**——每篇独立成章,不需要"贯穿全书的加码楼梯";用每篇独立的 hook 即可。 +- **意识流 / 散文 / 抒情独白**——这类作品的目标是"内省流动",不靠外部事件推动;"打破平衡"的标准不适用。 +- **纯设定型世界观(无主角线)**——如 worldbuilding wiki、设定集——没有"主角生活平衡"可打破。 +- **没有可识别人物的非虚构**(纯数据报告 / 政策白皮书)——"主角"概念不成立。 +- **同一事件的多个视角重写**——触发事件已经发生(既定事实),加码方法论不适用;视角与呈现方式改用电影化视角/镜头距离(见场景执行 skill scene-craft)或细节马赛克(见人物呈现 skill character-presentation)。 + +### 作者在书中警告的失败模式 + +- **开篇没触发事件**——失败模式: 长篇在开篇就"建立世界"但**不打破平衡**——读者不知道"故事在解决什么问题"因而弃读。信号: 第一章读完,主角的生活和第一章前**完全一样**。机制: 人脑的注意力是**问题驱动的**——没有"问题"就没有"想知道答案"的拉力。 +- **中段没加码**——失败模式: 开篇有触发,但从 1/4 体量开始赌注不再升高,情节原地打转,读者在 2/3 处弃读。信号: 把 1/3 和 2/3 的章节互换位置,故事不受影响——意味着中间没变化。 +- **触发事件不"事件化"**——失败模式: 把触发写成"主角渐渐意识到 X" / "主角慢慢长大"——这是**状态变化**,不是**事件**;读者无法"看到"那一秒,因而无从感受"打破平衡"。 +- **加码只升"压力"不升"维度"**——失败模式: 每次加码都是"主角更焦虑了",但赌注的**类型**没变(全是个人内心戏);到 1/2 处读者已麻木。修正: 加码必须**跨维度**——个人 → 家庭 → 社群 → 公众 → 国家 → 文明(参照《King's Speech》5 步)。 + +### 作者的盲点 / 时代局限 + +- Clark 写于 2006 年(英文版),主要讲**新闻 + 电影剧本**——对**长篇小说**的迁移需要适配: + - 电影剧本的触发事件常在**前 10 页**,长篇小说常在**5-15% 体量**;若照搬"开篇立刻爆发"会牺牲长篇必要的"日常建立"——Clark 没给这个"延迟"提供明确指引。 + - Clark 引用 McKee 的例子(Dorothy、Rudolph、King's Speech)几乎都是**单人主角 + 单线情节**;对**多视角长篇**、**群像小说**、**POV 切换**结构里的"多个触发事件"如何对齐,Tool 55 没说。 + - 中文网络长篇特有的"卷 / 章回 / 阶段奖励"结构,与"每 3-5 章加码"的节奏**不完全一致**——需让用户自己调整加码频率。 + +### 容易混淆的邻近方法论 + +- **与"故事引擎"(Clark Tool 31)的混淆**: 那个管"贯穿全书的核心问题/叙事燃料"——是一根**持续燃烧的轴**;本条管"启动 + 升级"——是**第一下点火**和之后**每次加油**。前者是"为什么读到最后",后者是"为什么第一章要翻过去 + 为什么中段不弃读"。诊断: 若问题指向"故事动力" / "核心问题" / "不知道写什么",先找概念与前提类 skill(concept-design);若指向"故事从哪一秒开始" / "中段为什么没劲" / "赌注怎么升",用本条。 +- **与"金币"的区别**: "金币"方法管"沿途给读者的奖励"(小钩子、小反转、小爽点),是**回报侧**;本条管"赌注本身升高",是**压力侧**。一个让读者"想继续看",另一个让读者"不敢不看"。(两者都在叙事动力 skill narrative-momentum。) +- **与"段内悬崖"的区别**: "段内悬崖"方法管"段末钩子"——单章 / 单场景的**局部**悬念;本条管**全局赌注**——从开篇到结尾的**宏观**升级。前者是"章末转折",后者是"全书走势"。 +- **与"契诃夫之枪"的区别**: "契诃夫之枪"管"道具埋设和回收"——是**物件线**;本条管"事件链和赌注台阶"——是**事件线**。一个回答"这把枪什么时候响",另一个回答"为什么这一枪越打越响"。(伏笔类见 foreshadow-payoff。) +- **与"主线推进"的混淆**: 主线推进 = 情节往前走;触发事件 + 加码 = 情节**越走越危险**。前者可以平推,后者必须有台阶感。 + +### 组合使用(跨域指针) + +- **与伏笔与回收 skill(foreshadow-payoff)组合**: 加码可借助"埋下但延迟爆炸的物件"。 +- **与结尾设计 skill(story-ending)组合**: 加码的最后一级就是"为结尾蓄势"。 +- **与叙事动力 skill(narrative-momentum)组合**: 加码的章节里塞段末钩子。 + +## 中文落地(中文适配) + +- 网文的"卷 / 章回 / 阶段奖励"结构与"每 3-5 章加码"不完全一致:落地时按**卷定大台阶、按章定小台阶**——每卷赌注升一个维度(门派 → 江湖 → 朝堂 → 天下),卷内每 3-5 章升一次压力;阶段奖励(升级、夺宝)可以充当加码的可见刻度。 +- 电影剧本式"前 10 页爆发"照搬到中文长篇会牺牲日常建立;中文长篇的触发事件放在 5-15% 体量时,前段用 Setup 五使命(见 `setup.md`)填实。网文连载是例外:黄金三章把触发事件压到第 1-3 章,属于商业节奏对位置的合法改写。 +- "好事变坏事"(be careful what you wish for)在中文语境里对应常见的"奇遇反噬"开局:中奖、得传承、入仙门,开局是好事,随后把主角推入更大麻烦——用法与 Clark 所述一致。 diff --git a/framework/catalog/dsh/skills/story-structure/references/inciting-vs-fpp.md b/framework/catalog/dsh/skills/story-structure/references/inciting-vs-fpp.md new file mode 100644 index 0000000..90d4a16 --- /dev/null +++ b/framework/catalog/dsh/skills/story-structure/references/inciting-vs-fpp.md @@ -0,0 +1,109 @@ +# 煽动事件 ≠ 第一情节点:开篇大事件和故事启动是两回事 + +> 触发事件的定义与加码见 `inciting-incident.md`;第一情节点单点深入见 `first-plot-point.md`。 + +## 原文摘录 + +> "The shooting happens at 19:30, too soon to be a functioning First Plot Point. But very right-on-the-mark as an inciting incident. An inciting incident, yes, because it does incite what happens next. It's huge, a total game-changer. But only when something else happens, something that does meet the criteria by imparting meaning to it—by defining the journey and challenge that lies ahead for the heroes—does it become a legitimate Plot Point." +> +> — Larry Brooks, *Story Engineering* (2011), Part 5 + +## 方法骨架 + +"开篇惊天大事"和"第一情节点"是两个不同概念, 在结构上不同位置、不同功能。混淆是新手最常见的错误。 + +**Inciting Incident(煽动事件)**: +- **位置**: Setup 段任何位置, 通常早于 25% +- **戏剧强度**: 极高(爆炸、死亡、发现、失踪) +- **功能**: 引起紧张, 暗示有事要发生 +- **不**赋予"意义/任务/赌注" +- 可以是开篇 1-5 页内 + +**First Plot Point(第一情节点)**: +- **位置**: 25%(硬约束) +- **戏剧强度**: 可高可低(Thelma 是对话, Shutter Island 是耳语) +- **功能**: 赋予意义——主角接任务/对抗力量亮相/赌注明确 +- **不**必是惊天大事 + +**两者的关系**: +- Inciting 可以早于 FPP 出现, 也可以重合 +- Inciting 是"火", FPP 是"开始扑火" +- 没有 inciting = 故事开局无聊 +- 没有 FPP = 故事没启动 + +**常见错误**: 写作者写了"开篇大事件", 以为这就是 FPP, 结果 25% 位置空了, 故事后半部分动力不足。 + +**操作法**: +- 写一个开篇大事件(inciting)——在 1-15% +- 留出"读者不知道这意味着什么"的时间(10-15%) +- 在 25% 给主角"接任务"瞬间(FPP) + +## 书中案例 + +### 案例 1: Thelma & Louise(《末路狂花》)——完美分离 +- **Inciting (19:30)**: 酒吧杀人事件——戏剧强度极高 +- **FPP (31:00)**: 决定跑——戏剧强度中等(只是对话) +- **两件事相距 11 分钟** = 演示分离 +- **关键**: 杀人是"煽动", 决定是"赋予意义" + +### 案例 2: Collateral(《借刀杀人》)——早 inciting + 延迟 FPP +- **Inciting (开场)**: 出租车顶掉下一具尸体——极高强度 +- **FPP (~25%)**: 坏人坐到后座, 告诉司机今晚的"任务" +- **两件事相距近 25%** = 极致延迟 +- **关键**: 尸体是"煽动", 任务是"赋予意义" + +### 案例 3: 反例——inciting 当 FPP +- **问题**: 写作者写了"开篇 1 页主角父亲被谋杀", 之后花 30% 找凶手 +- **方法论的使用**: 诊断 = FPP 提前到 1%, 故事启动过早 +- **结论**: 主角立即接任务 = Setup 段(建立赌注/共情/伏笔)没了 +- **结果**: 改稿: 把"父亲被谋杀"移到 5%, 让主角在 25% 才"接任务" + +## 可执行步骤 + +1. **找出开篇大事件** + - 完成标准: 用户能指认 1 个开篇"大事件" + - 提示: 通常在 1-15% +2. **判断它是 inciting 还是 FPP** + - 完成标准: 用 3 问 + - 它赋予"任务/意义"吗?(yes = FPP, no = inciting) + - 它在 25% 位置吗?(yes = 可能是 FPP, no = inciting) + - 戏剧强度极高?(yes = 倾向 inciting) +3. **如果只有 inciting 没有 FPP** + - 完成标准: 在 25% 处设计 FPP + - FPP = 主角的"决策/任务/意义"瞬间 + - 可以弱强度, 必须明确意义 +4. **如果只有 FPP 没有 inciting** + - 完成标准: 故事开头会无聊 + - 增补开篇钩子(Hook)或小事件 + +## 边界 + +### 不要在以下情况使用 + +- 写非叙事内容 +- 中短篇/flash fiction——经常 inciting=FPP(短篇体制见 `length-system.md`) +- 多 POV 故事——每个 POV 独立诊断 + +### 作者警告的失败模式 + +- 把"开篇大事件"和 FPP 必然当成"1 个事"——可以是 2 个事 +- 把 inciting 拖到 25% 之后——故事无聊 +- 跳过 inciting 直接到 FPP——读者"不知道为什么" + +### 作者盲点 + +- 假设 inciting 必是"动作"——也可以是"发现"(一封信/一张照片/一个电话) +- 假设 FPP 必是"决策"——也可以是"信息"(知道某真相) +- 假设 inciting=FPP 是错的——实际上常常是错的 + +### 易混方法论与术语冲突(规则冲突,都保留) + +- **"Inciting Incident"(Field/Syd Field)**——用法不同, Field 当 FPP 用。**注意冲突**:同一个词,Field 指的是 Brooks 所说的第一情节点;Clark/McKee 所说的 inciting incident 才是 Brooks 所说的煽动事件。用哪家的词,就要看哪家的定义,先确认对方用哪把尺子。 +- **"Catalyst"(Story Grid)**——接近 FPP +- **"Call to Adventure"(Campbell)**——是原型术语, 位置更灵活 + +## 中文落地(中文适配) + +- 中文类型小说(悬疑、刑侦、仙侠)习惯"开篇命案/开篇灭门",这正是 inciting 前置的写法;诊断时照样问三问——命案发生在 1-5% 是合格的煽动事件,但要确认 25% 处另有一场"赋予意义"的戏(主角正式接下追查/复仇/入局的任务),否则后程动力不足。 +- 章回体里"楔子 + 正书"的结构天然支持分离:楔子常承担 inciting(大事件),正书前若干回完成 Setup,第一情节点落在正文约四分之一处。 +- 短篇里 inciting 常与 FPP 重合:中文微型小说、小小说不必强拆成两个事件。 diff --git a/framework/catalog/dsh/skills/story-structure/references/length-system.md b/framework/catalog/dsh/skills/story-structure/references/length-system.md new file mode 100644 index 0000000..08a41ad --- /dev/null +++ b/framework/catalog/dsh/skills/story-structure/references/length-system.md @@ -0,0 +1,130 @@ +# 短中长篇是三种体制——动笔前先选对尺子 + +> 这是结构工作的第一步:体裁定错了,后面所有结构工具都用错尺子。 + +## 原文摘录 + +> 「短篇小说、中篇小说、长篇小说是三个完全不同的体制,而不是小说的长短问题。」 +> ——《小说课》 + +毕飞宇在《故乡》分析中说: + +> “短篇小说由于篇幅的缘故,它是不允许[人物性格发育]的。” +> ——《小说课》 + +**关键洞察**:短篇/中篇/长篇不是"长度不同",是**体制不同**——它们有完全不同的运行规则。 + +## 三种体制的核心差异 + +| 维度 | 短篇 | 中篇 | 长篇 | +|-----|------|------|------| +| 人物数量 | 1-3 | 3-10 | 10+ | +| 性格发育 | 不允许 | 部分允许 | 必须 | +| 时间跨度 | 单一场景/瞬间 | 几天-几年 | 跨代 | +| 核心技法 | 冰山/反常/铺垫 | 性格转折 | 命运+复调 | +| 容忍度 | 极精微 | 中等 | 容忍粗线条 | +| 读者注意力 | 1-2 小时 | 半天 | 几天 | + +一句话判据: + +> **短篇看"瞬间",中篇看"转折",长篇看"命运"。** +> ——《小说课》 + +## 书中案例 + +### 案例 1:海明威《杀手》——短篇典范 + +- 五个人物,**全部用瞬间切片**呈现 +- 没有人物"前史"——只有当下 +- 短篇的"刀光剑影"在长篇里是**灾难**(会拖垮节奏) + +### 案例 2:蒲松龄《促织》——1700 字的"微小说" + +- 一家人、几件事、一个小孩变蛐蛐 +- **不允许性格发育**——成名就是"迂讷",没有"为什么迂讷" +- 用"两次寻死"代替了"人物心理转变" + +### 案例 3:曹雪芹《红楼梦》——长篇的反面教材 + +> 「读《红楼梦》如果你只读过一遍,和没读也没什么两别。」 + +毕飞宇承认《红楼梦》作为长篇"太精微了"——**短篇的精微用在长篇上是负担**。 + +### 案例 4:莫泊桑《项链》——短篇的标准结构 + +> 「凤头、猪肚、豹尾」 + +开头漂亮(借项链)、中间丰满(十年艰辛)、结尾有力(项链是假的)——**典型短篇结构**。 + +## 什么时候想到这条方法(触发场景) + +1. 你开始写一个文本前——先确认体裁 +2. 你被"卡住"了——可能用错了体裁的尺子 +3. 你想从短篇扩成长篇——这是**改写**,不是扩写 +4. 你评价别人的小说——先看体裁 +5. 你读不懂一部小说——可能你用错体裁的阅读方式 + +## 可执行步骤 + +### 步骤 1:写之前先定体裁 + +```yaml +我要写的: + 体裁:[短篇 / 中篇 / 长篇] + 核心人物数:[N] + 时间跨度:[N] + 核心技法:[冰山/铺垫/反常/性格发育/复调/命运] + 读者注意力预算:[X 小时] +``` + +### 步骤 2:短篇的硬规则 + +- **人物 ≤ 3**(含次要) +- **场景 ≤ 5**(含过渡) +- **时间 ≤ 24 小时** 或 单一回溯 +- **必须有 1 个反常事件**(短篇不靠性格发育,靠"反常"推动) +- **结尾必须有冲击**(豹尾) + +### 步骤 3:中篇的硬规则 + +- 人物 3-10 +- **必须有一个明确的"性格转折"** +- 时间跨度可以放宽 +- 可以分章节,但节奏要紧凑 +- 短篇技法(冰山、铺垫)依然适用,但要"摊薄" + +### 步骤 4:长篇的硬规则 + +- **必须有人物"命运"**(性格的累积变化) +- 短篇技法**不可照搬**——精微处要少用 +- 允许"粗线条" +- **复调**(多线并进)是长篇的特权 +- "延宕"是长篇的核心能力 + +### 步骤 5:跨体裁转换的红线 + +- 短 → 长:**加人物、加时间、加命运**——不是把句子写长 +- 长 → 短:**做减法**——只保留最核心的 1-2 个场景 +- 任何 → 短:**检查反常点**——短篇必须有它 + +## 边界与常见错误 + +### 适用边界 + +- **适用于**虚构叙事(小说为主) +- **部分适用**剧本(电影是"长篇"逻辑,单集剧是"短篇"逻辑) +- **不适用**纯散文、纯抒情诗 + +### 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 用短篇的精微写长篇 | 读者累、节奏拖 | 长篇允许"粗" | +| 用长篇的篇幅写短篇 | 拖沓、肿瘤 | 短篇必删到 5000-15000 字 | +| 中篇用短篇的人物密度 | 平面、单薄 | 中篇必须有"性格转折" | +| 长篇用中篇的命运刻度 | 不够深 | 长篇命运要"沉" | + +## 与其他结构方法的关系 + +- 本条是**框架性方法**:本 skill 其余方法(四箱、六里程碑、Setup 五使命等)都是长篇(及电影剧本)工具;中短篇不可整套照搬,短篇里触发事件常与第一情节点重合。短篇只取"触发事件 + 反常 + 豹尾"。 +- 跨域指针:长篇才有人物"命运"可言 → 见 character-presentation(人物命运);短篇铺垫极简、长篇铺垫可以是一整章 → 见 foreshadow-payoff;短篇的冰山在长篇要"摊薄" → 见 show-and-omission。 diff --git a/framework/catalog/dsh/skills/story-structure/references/midpoint.md b/framework/catalog/dsh/skills/story-structure/references/midpoint.md new file mode 100644 index 0000000..ee1c0e6 --- /dev/null +++ b/framework/catalog/dsh/skills/story-structure/references/midpoint.md @@ -0,0 +1,104 @@ +# 中点(Midpoint):主角从被动转主动的那堵墙 + +> 中点之前主角必须是漫游者(见 `part2-wanderer.md`);中点在四箱与六里程碑中的位置见 `four-boxes.md`、`six-milestones.md`。 + +## 原文摘录 + +> "In Part 3, though, the hero begins to try to fix things. That's the context of this quartile—to become proactive and downright courageous and ingenious in the quest to attain the goal. The hero starts to conquer inner demons and begin doing things a little differently than before, or at least come to understand how they have been standing in his own way. That the hero needs to change if he is to succeed. In Part 3 the hero summons courage and applies creative thinking." +> +> — Larry Brooks, *Story Engineering* (2011), Part 5 + +## 方法骨架 + +Midpoint(50%)是故事的"墙"——Part 2 结束, Part 3 开始。Midpoint 之前, 主角是 wanderer(反应/摸索); Midpoint 之后, 主角是 attacker(主动进攻)。 + +**Midpoint 的 2 个核心功能**: +1. **主角心态转向**: 从"反应"变"主动"——主角开始"做"而不是"被做" +2. **新信息/觉醒/承诺**: 通常伴随一个"新认识"或"决心" + +**Midpoint 的常见 4 种形式**: +- **觉醒**: 主角明白自己一直错了(例如知道真相) +- **承诺**: 主角做出不可逆的承诺(例如"我要回故乡") +- **新盟友**: 主角获得新力量/新信息/新朋友 +- **新赌注**: 主角面对更大的威胁, 决心升级 + +**Midpoint 不是"故事过半的某个点"**, 是"主角本质的转变"。 + +**位置约束**: +- 50% ± 3%(硬约束) +- 偏早(45% 之前)= Response 段太短 +- 偏晚(55% 之后)= Attack 段太短 + +**没有 Midpoint = 故事平铺直叙 = 4 箱变 2 箱。** + +## 书中案例 + +### 案例 1: The Da Vinci Code(《达·芬奇密码》) +- **Midpoint (~50%)**: Langdon 和 Sophie 在某个关键发现后, 决定不再跑, 主动反击 +- **形式**: 承诺 + 新信息 +- **效果**: 之后 Langdon 开始主动破译密码、对抗神秘组织, 不再"被追" + +### 案例 2: Thelma & Louise(《末路狂花》) +- **Midpoint (~50%)**: 两位主角的对话"我们不回头了" +- **形式**: 承诺 +- **效果**: 之后她们开始主动决策(抢劫、对抗警察), 不再只跑 + +### 案例 3: Cold Mountain(《冷山》) +- **Midpoint (~50%)**: Inman 决定回家, 面对漫长旅程 +- **形式**: 承诺 +- **效果**: 旅程从"被动求生"变"主动回家" + +### 案例 4: 反例——Midpoint 缺失 +- **问题**: 写作者写完, 故事中段平 +- **方法论的使用**: 6 里程碑扫描发现: Midpoint 缺失 +- **结论**: 主角没有"从被动转主动"瞬间, 整部平 +- **结果**: 增补一个"主角觉醒/承诺"场景, 故事张力立现 + +## 可执行步骤 + +1. **找 Midpoint 候选** + - 完成标准: 用户能指认 1 个"主角变主动"的瞬间 + - 提示: 找"主角开始做决定"或"主角觉醒"瞬间 +2. **验证 2 个功能** + - 完成标准: + - 主角心态/行为转向了吗?(是 = 通过) + - 有新信息/觉醒/承诺吗?(是 = 通过) +3. **验证位置** + - 完成标准: 在 50% ± 3% 范围 + - 偏早(45% 之前)= Response 太短 + - 偏晚(55% 之后)= Attack 太短 +4. **如果缺失或偏离** + - 完成标准: 列出 1-2 个改写方案 + - 增补 Midpoint: 找 Part 2 结尾 + Part 3 开头的"主角觉醒"瞬间 + +## 边界 + +### 不要在以下情况使用 + +- 整体 6 里程碑诊断(用 `six-milestones.md`) +- 检查 Part 2 角色状态(用 `part2-wanderer.md`) +- 多 POV 故事——每个 POV 独立诊断 + +### 作者警告的失败模式(三种假中点) + +- 把"反派大动作"当 Midpoint——反派动 = 主角被动, 不是主角主动 +- 把"主角小胜利"当 Midpoint——胜利不是心态转向 +- 把"信息揭示"当 Midpoint——没有主角"用这个信息做事" = 不是 Midpoint + +### 作者盲点 + +- 假设 Midpoint 是"觉醒"——承诺/新赌注/新盟友也有效 +- 假设 Midpoint 后立即"开打"——Attack 段还可能再 wander 几次, 再开打 +- 假设 Midpoint = 1 个场景——可能是跨 2-3 个场景的"段" + +### 易混方法论 + +- "Midpoint"(Save the Cat)——略不同, Snyder 给的是"假胜利/真失败" +- "Midpoint Reversal"(不同书)——接近, 但强调"反转" +- "Hero's Journey: The Abyss"——类似, 但更神秘化 + +## 中文落地(中文适配) + +- 位置按字数换算:30 万字长篇的中点在 14.1 万-15.9 万字之间;章回体按回数折算(120 回的第 57-63 回)。 +- 中文叙事传统里的中点常以"誓言/明志"场面呈现——歃血为盟、当众立誓、决意下山、撕毁休书——对应四种形式中的"承诺";检查时仍看两功能:心态是否从被动转主动、是否有新信息或不可逆决心。 +- Setup 段暗示过的"内在恶魔"在此处开始被克服(原文摘录引文:"conquer inner demons"):中文长篇里对应主角的心结、旧伤、执念在中点前后被正面处理,这条因果链要在 Setup 就埋好(见 `setup.md` 使命 4)。 diff --git a/framework/catalog/dsh/skills/story-structure/references/opening.md b/framework/catalog/dsh/skills/story-structure/references/opening.md new file mode 100644 index 0000000..72355e0 --- /dev/null +++ b/framework/catalog/dsh/skills/story-structure/references/opening.md @@ -0,0 +1,188 @@ +# 落笔写开头:不等完美第一句,用首尾两句当路标 + +> 讲"怎么写下第一句"的写作姿态与技术。Setup 段该完成哪些功能使命见 `setup.md`,开篇该放什么事件见 `inciting-incident.md` 与 `inciting-vs-fpp.md`。 + +## 原文摘录 + +> “现在, 立即开始写作。就像你自己进行第六章里的时间练习一样, +> 不要找任何借口, 拒绝任何居场的感觉, 只是开始写作。 +> 如果想不到一个好的开头, 就把它放在一边, 稍后再写。 +> 尽可能快地写, 对你自己的写作过程留意的越少越好, +> 尽量轻松而快速地工作, 开始和结束一个句子都要清晰有力。 +> 要减少重读的次数, 只时不时地读一两个句子, 以确保你在正确的轨道上。 +> 你开始写作之前, 把故事的第一句话和最后一句确定下来, +> 你会发现这非常有好处。这样你就可以用第一句作为跳板, 延伸你的故事, +> 用最后一句作为降落点。” +> +> —— 多萝西娅·布兰德,《成为作家》第十四章 + +## 方法骨架:3 条铁律 + 2 个锚定技术 + 5 种开头方法 + +### 3 条铁律(开头的反直觉规则) + +**铁律 1: 不要"等完美开头"** +- 想 30 分钟没想出好开头? **先跳过, 稍后再写** +- 你想出来的"好开头"通常是"陈词滥调"(因为它在脑内已经想得太久, 已经俗了) +- 真正的好开头, 是在**写中**涌现的, 不是在**想中**涌现的 + +**铁律 2: 立即开始** +- 就像固定写作时间纪律的"4 点必须写"一样 +- 不要"等准备好了" +- 拒绝"居场的感觉"(那种想拖延的感觉) + +**铁律 3: 减少重读** +- 写的时候, 只时不时读 1-2 个句子, 确认方向 +- **不要每写一句就回看**——那是无意识的杀手 +- 流畅 > 完美, 一气呵成 > 字字打磨 + +### 2 个锚定技术(开头不迷路的方法) + +**锚定 1: 确定"第一句"** +- 第一句 = 跳板, 让你"有地方开始" +- 不需要是"完美的第一句", 只需要是"够用的第一句" +- 标准: 这一句**已经**把读者带进故事——不是介绍背景, 是**进入画面** + +**锚定 2: 确定"最后一句"** +- 最后一句 = 降落点, 让你"知道要去哪" +- 写之前**先想好**这一句, 整个故事会"奔向"它 +- 关键: 最后一句**不是结尾的转折**(那是常见误区), 是**最后一个画面/声音/动作** +- 标准: 这一句**已经**让读者感到"完结"——不是问题被解决, 是**故事在这个时刻停住** + +**两个锚点的协同** +- 第一句 + 最后一句 = 一条路 +- 中间无论怎么写, 都不跑题 +- 这就是布兰德的"路标"技术 + +### 5 种开头方法(布兰德散落各章) + +**方法 1: "画面/动作"开头**(推荐, 最常用) +- 第一句就是一个**具体的画面**: “她在雨里跑了三十分钟。” +- 不是介绍, 是"你看到了什么" +- 适用于: 几乎所有小说 +- 优点: 立即把读者拉进故事 + +**方法 2: "对话"开头**(第 8 章强调) +- 第一句就是角色在说话 +- “'你来了,' 她说。” +- 适用于: 人物关系重要的故事 +- 优点: 立即建立声音, 暗示冲突 +- 风险: 读者不知道谁在说话, 可能困惑——配合"是谁"的指示 + +**方法 3: "声音/感官"开头**(第 14 章暗示) +- 第一句是一个声音/气味/触感 +- “走廊里有什么东西在动。” +- 适用于: 悬疑/惊悚/感官小说 +- 优点: 立即建立"在场"感 + +**方法 4: "反常/惊讶"开头**(第 12 章反例, 慎用) +- 第一句是一个反常/惊讶的事 +- “我母亲昨天死了。但我不哭。” +- 适用于: 想立刻建立张力 +- 风险: **容易落入"令人吃惊的结尾"陷阱**(第 12 章警告)——为"原创"而原创, 反而失真 + +**方法 5: "日常"开头**(第 11 章暗示) +- 第一句就是日常, 但日常中有"不寻常" +- “那个星期三的早餐和往常一样, 除了她在咖啡里加了盐。” +- 适用于: 慢热/心理小说 +- 优点: 反衬张力 + +### 5 种开头方法的选用 + +- 不确定用什么? **默认用方法 1(画面/动作)** +- 故事以人物关系为主? 用方法 2(对话) +- 想立刻建立紧张? 用方法 3(声音/感官)或方法 4(反常) +- 慢热/心理小说? 用方法 5(日常) + +### 与"开头"相关的"结尾"反例(第 12 章) + +布兰德的反例: 不要为"原创"而写"令人吃惊的结尾"——那是**为原创而原创**, 人物行为失真。 +- 正确: 结尾是**人物会做的事**, 不是作者强加 +- 错误: 结尾是"出乎意料", 但人物**不会**那样做 + +## 书中案例 + +### 案例 1: 布兰德的"路标"技术 +- **问题**: 写到一半不知道自己在写什么 +- **方法论的使用**: 动笔前确定"第一句 + 最后一句" +- **结论**: 这两个锚点让中间不跑题 +- **结果**: 故事能写完, 且不散 + +### 案例 2: 福特的"前期准备" +- **问题**: 不知道人物会做什么 +- **方法论的使用**: 前期准备"知道"一切(即使不写到) +- **结论**: 写起来, 第一句/最后一句自然涌现 +- **结果**: 开头不会"卡", 因为素材充足 +- 前期准备的完整流程见规划工作流 skill(story-planning)。 + +### 案例 3: 海明威的"日常+反常"开头 +- **问题**: 想写"一个人很痛苦" +- **方法论的使用**: 海明威的《永别了, 武器》开头: “那年晚秋, 我们住在乡村一所木屋里...” +- **结论**: 日常中藏反常, 不直说痛苦 +- **结果**: 比直接说"他很痛苦"有力 10 倍 + +## 可执行步骤 + +1. **诊断: 用户卡在哪里** + - 完成标准: 用户能说出"我卡在 5 种开头方法的哪个 / 不知道用哪种 / 写出来不满意" + - 提问: "你现在的问题是——(a) 想不到第一句? (b) 想出来但不满意? (c) 写出来但抓不住读者?" + - 判停条件: 若用户说"我不知道写什么故事" → 先解决写什么的问题(规划工作流 story-planning 的起点阶段) +2. **拒绝"等完美开头"** + - 完成标准: 用户承诺"先写一个'够用'的开头, 之后再改" + - 关键: 布兰德的反例: 等完美开头 = 永远写不完 +3. **帮用户选 5 种开头方法之一** + - 完成标准: 用户能说"我用方法 X 开头" + - 默认推荐: 方法 1(画面/动作)——最通用 + - 提问: "你希望读者第一眼看到什么? 听到什么? 知道什么?" +4. **确定"第一句 + 最后一句"两个锚点** + - 完成标准: 用户能写出第一句和最后一句 + - 关键: 不需要完美, 需要"够用" + - 第一句标准: 让读者**进入画面**, 不是介绍背景 + - 最后一句标准: 让读者感到**完结**, 不是"问题解决" +5. **立即动笔, 不要回看** + - 完成标准: 用户承诺"写完一段不回看, 只时不时看 1-2 句" + - 关键: 流畅 > 完美 +6. **写完后, 不要立即重读** + - 完成标准: 写完后立刻放一边, 至少隔一夜再看 + +## 边界 + +### 不要在以下情况使用 + +- **用户不知道写什么**——先解决写什么(规划工作流 story-planning 的起点阶段) +- **写非虚构开头**(新闻导语/学术摘要)——那是 lead/abstract 技术, 不同领域 +- **写诗/散文**——开头逻辑不同, 不必"路标" +- **写剧本**——剧本开头是场景/角色, 不是叙事 +- **用户已经能流畅写开头**——这是基础技术, 不是优化 + +### 作者在书中警告的失败模式 + +- **等完美开头**: 等"完美" / 等"最后智慧" → 永远等不到 +- **模仿风格**: 模仿别人的"开头风格"——永远追不上 +- **写完就删**: 写完开头立刻重读, 觉得"开头不行" → 删 +- **模仿别人的题材**: 因为别人用过某开头很成功, 你就跟着用 +- **公开宣告**: 写之前跟朋友讲"我想到一个超棒的开头" → 招来评判 + +### 作者的盲点 / 时代局限 + +- **1934 年的"小说"偏严肃文学**——类型小说(悬疑/科幻/言情)的开头逻辑有差异 +- **不区分"章节开头" vs "故事开头"**——短篇只有 1 个开头, 长篇每章都有, 方法不同 +- **没考虑"网文"形态**——网络连载的"开篇三章"(黄金三章)有其商业规律 +- **"反常开头"的"反常陷阱"**——布兰德警告过, 但没给出"怎么判断反常是否合理"的方法 +- **不区分"第一人称" / "第三人称"**——视角影响开头 + +### 容易混淆的邻近方法论 + +- **"钩子"(Hook, 新闻业)**——类似机制, 但"钩子"是为快速消费设计, 小说更复杂 +- **"黄金三章"(网文)**——是商业规律, 不是文学规律 +- **"冷开场" vs "暖开场"**——是技术分类, 不是布兰德的分类 + +### 组合使用(跨域指针) + +- **与对话写作 skill(dialogue-craft)组合**: 方法 2(对话开头)的延伸——本条管"用对话写第一句",贯穿全文的对话整体技术归 dialogue-craft。 +- **与场景执行 skill(scene-craft)组合**: 方法 1(画面/动作开头)的延伸——第一句进画面之后,场景如何展开执行归 scene-craft。 + +## 中文落地(中文适配) + +- 布兰德的五种开头方法对中文小说同样适用,例句本身已是中文语境;中文开篇另有"闲笔起兴"的传统(先写环境再入人事),落到方法上等同于方法 5(日常开头)的变体,判断标准不变:第一句要把读者带进画面,不是交代设定。 +- 网络连载小说的"黄金三章"是商业规律而非文学规律:它要求把本条的"第一句进画面"与 Setup 段的钩子使命(见 `setup.md`)、触发事件(见 `inciting-incident.md`)一起压缩到前三章。方法本身不变,变的是完成时限。 +- 长篇每章都有开头:本条的"路标"技术用于全书的第一句和最后一句;章节开头另算,可复用五种方法,但每章第一句优先服务"进入画面",不重复交代背景。 diff --git a/framework/catalog/dsh/skills/story-structure/references/part2-wanderer.md b/framework/catalog/dsh/skills/story-structure/references/part2-wanderer.md new file mode 100644 index 0000000..80dbc89 --- /dev/null +++ b/framework/catalog/dsh/skills/story-structure/references/part2-wanderer.md @@ -0,0 +1,110 @@ +# 第二段(25-50%):主角必须是漫游者(wanderer) + +> 这一段结束于中点,中点见 `midpoint.md`;四箱全局见 `four-boxes.md`。 + +## 原文摘录 + +> "In Part 2 the hero is running, hiding, analyzing, observing, recalculating, planning, recruiting, or anything else required before moving forward. If you have your hero being too heroic here, being brilliant, already knocking heads with the bad guys (or some other dark force), it's too early. You're in violation of structural principles if that's the case." +> +> — Larry Brooks, *Story Engineering* (2011), Part 5 + +## 方法骨架 + +Part 2(25-50%)主角必须是 **wanderer**——反应/摸索/分析/学习/试错, 不是主动进攻。这是 Response 段的功能, 也是为 Midpoint 的转向蓄力。 + +**Part 2 主角的 6 个允许动作**: +1. **Running**: 跑 +2. **Hiding**: 躲 +3. **Analyzing**: 分析局势 +4. **Observing**: 观察敌人 +5. **Recalculating**: 重新计算计划 +6. **Planning/Recruiting**: 计划/招募盟友 + +**Part 2 主角的 3 个禁忌动作**: +1. **Knocking heads with the bad guys**: 主动对抗 +2. **Solving the problem**: 解决问题 +3. **Being brilliant**: 突然变聪明 + +**为什么**: +- Midpoint 的转向才有戏剧张力——需要 Part 2 累积"做不到" +- Part 2 主角主动 = Midpoint 无事可转 = 故事平 +- 主动过早 = Attack 段没戏 + +**何时破坏(合法的例外)**: +- 极小主动(例: 主角试 1 次, 失败) +- 主动只是"局部"(例: 解决小障碍, 不解决大冲突) +- 主动为 Midpoint 服务(例: 失败后觉醒) + +## 书中案例 + +### 案例 1: The Da Vinci Code(《达·芬奇密码》)——完美 Part 2 +- **位置**: 25-50% +- **主角动作**: 跑、躲、分析、不知所以 +- **关键**: 整段 Langdon 不知道谁在追、为什么被追 +- **效果**: 累积"做不到" = Midpoint 转向有戏 + +### 案例 2: Thelma & Louise(《末路狂花》)——Part 2 +- **位置**: 25-50% +- **主角动作**: 跑、躲、被警长追 +- **关键**: 整段她们只是跑, 没有主动决策 +- **效果**: 累积"逃不掉" = Midpoint 决定"不回头"有戏 + +### 案例 3: 反例——Part 2 主角太英雄 +- **问题**: 写作者在 30% 位置, 主角已经打败 1 个反派、破解 1 个谜题 +- **方法论的使用**: 诊断 = Part 2 越界, 主动过早 +- **结论**: Attack 段(50-75%)没戏, 故事结构错 +- **结果**: 把"主角打败反派"移到 55%+, 让 Part 2 真正 wanderer + +## 可执行步骤 + +1. **找 Part 2 关键场景** + - 完成标准: 用户能列出 3-5 个 25-50% 段的关键场景 +2. **检查每个场景的主角动作** + - 完成标准: 每个场景主角动作属于 6 个允许动作之一 + - 不在 6 个允许动作 = 越界 +3. **检查主角是否"主动"** + - 完成标准: 主角是否在做"主动进攻"类动作?(打怪/破案/解决冲突) + - 主动 = 越界, 需移到 Part 3 +4. **检查"局部主动"的合法性** + - 完成标准: 如果有主动, 是否满足: + - 极小主动? 或 + - 主动只是"局部"(小障碍)? 或 + - 主动为 Midpoint 服务(失败后觉醒)? +5. **改稿建议** + - 完成标准: 把越界场景移到 Part 3, 或改成"局部主动" + +空白巡查表见 `../references/structure-checklists.md` 的"漫游者巡查表"。 + +## 边界 + +### 不要在以下情况使用 + +- 整体 4 箱诊断(用 `four-boxes.md`) +- 检查 Midpoint(用 `midpoint.md`) +- 群像/POV 切换——每个 POV 独立 + +### 作者警告的失败模式 + +- 把"主角思考"当"主动"——思考是分析, 属于允许 +- 把"主角反击"当"wanderer"——反击 = 主动, 越界 +- 把"主角解决小障碍"当"小主动"——解决 = 主动, 即使"小"也算 + +注意上面两处的关系:合法例外允许的是**不碰核心冲突的局部主动**(解决小障碍、试一次就失败、为中点觉醒服务的失败);失败模式警告的是把"解决了障碍"误标成不算主动——局部主动本身仍是主动,只有满足三条之一才合法。 + +### 作者盲点 + +- 假设 Part 2 全是"反应"——实际上主角可以"招募盟友/收集信息"等主动准备 +- 假设 Part 2 不能有任何进展——可以有"小进展", 但不能"主问题进展" +- 假设 1 个 POV——多 POV 故事, 每个 POV 在自己 Part 2 是 wanderer + +### 易混方法论 + +- "Rising Action"(Freytag)——是 Part 2 的一部分, 但更强调"上升" +- "Complications"(Field)——类似, 但 Field 不分 2 段 +- "Hero's Journey: Tests"(Campbell)——是原型, 不是结构 + +## 中文落地(中文适配) + +- 武侠/仙侠的"逃亡学艺段"是天然的 Part 2:主角被追杀、隐姓埋名、观察仇家、拜师练功(招募盟友/收集信息属于允许动作);若在这一段就让主角手刃仇家,等于把 Attack 提前,中点后无戏可写。 +- 悬疑刑侦的"排查走访段"对应 wanderer:分析线索、观察嫌疑人、重新计算推理都属允许;"提前锁定并制服真凶"是禁忌动作,要移过中点。 +- 网文连载要注意:读者追更压力常逼作者让主角在第二段就"打脸反杀",这正是本条诊断的"30% 打败反派"越界;若确需爽点,用合法例外——小障碍可以解决,核心对手必须留到中点之后。 diff --git a/framework/catalog/dsh/skills/story-structure/references/setup.md b/framework/catalog/dsh/skills/story-structure/references/setup.md new file mode 100644 index 0000000..2c994a9 --- /dev/null +++ b/framework/catalog/dsh/skills/story-structure/references/setup.md @@ -0,0 +1,112 @@ +# Setup 段(0-25%)的五件事 + +> 开篇的写作姿态(怎么写第一句)见 `opening.md`;开篇该放的大事件见 `inciting-incident.md`;Setup 段结束处的情节点见 `first-plot-point.md`。 + +## 原文摘录 + +> "Five Missions for the Set Up of Your Story: Establish the stakes before the antagonistic force arrives. Establish character empathy. Define your hero's backstory enough for the reader to understand who he is now. Hint at the inner demons. Deliver a hook and foreshadow the forthcoming conflict." +> +> — Larry Brooks, *Story Engineering* (2011), Part 5 + +## 方法骨架 + +Setup 段(0-25%)不是"开始讲故事", 是"完成 5 件事"。任何 1 件缺失, Setup 段都不完整, 后面 75% 都受影响。 + +**5 大使命**: + +1. **建立赌注(Establish Stakes)**: 在对抗力量到来之前, 让读者知道"主角会失去什么/获得什么" + - 为什么: 没有赌注 = 读者不关心 +2. **建立角色共情(Establish Character Empathy)**: 让读者同情/理解/认同主角 + - 为什么: 没有共情 = 读者不在乎主角死活 +3. **给出够用的背景故事(Define Backstory Enough)**: 解释"主角为什么是现在这样", 不必全背景 + - 为什么: 读者需要 1-2 个"原来如此"的点 +4. **暗示内在恶魔(Hint at Inner Demons)**: 不全说, 但暗示"主角有更深的问题" + - 为什么: 内在恶魔是 Midpoint 转向的引擎, 早暗示才有意义(中点见 `midpoint.md`) +5. **钩子 + 伏笔(Hook + Foreshadow)**: 开篇悬念 + 暗示未来的冲突 + - 为什么: 没钩子 = 读者放下书; 没伏笔 = 高潮是"突然" + +**5 件事的顺序不一定**, 但都在 Setup 段内完成。 + +**常见错误**: +- 5 件事都做了, 但 Setup 段超过 25%(塞太多故事) +- 5 件事没做完, 但已经到 25%(Setup 段太薄) +- 5 件事做完, 但顺序乱(建议顺序: stakes → empathy → backstory → inner demons → hook/foreshadow) + +## 书中案例 + +### 案例 1: The Da Vinci Code(《达·芬奇密码》) +- **Stakes (10%)**: Langdon 著名的符号学家身份, 失去 = 学界地位 +- **Empathy (5-10%)**: Langdon 温文尔雅, 关心人 +- **Backstory (5-15%)**: Langdon 离婚后孤僻, 不擅长面对情感 +- **Inner Demons (10-20%)**: Langdon 害怕神秘/超自然事物(与天主事工对应) +- **Hook (1%)**: 开篇就是 Saunière 死后场景 +- **Foreshadow (10-25%)**: 警察紧逼 + 神秘人盯梢 +- **5 件事都到位** + +### 案例 2: Thelma & Louise(《末路狂花》) +- **Stakes (5-15%)**: Louise 的男友问题, Thelma 的丈夫问题 +- **Empathy (5-15%)**: 两位主角都是"被困住"的女人 +- **Backstory (5-15%)**: Thelma 长期被控制, Louise 早年创伤 +- **Inner Demons (10-20%)**: 各自的不安全感 +- **Hook (1%)**: 开篇对话"我们出去玩吧" +- **Foreshadow (15-25%)**: 酒吧里男人的危险暗示 +- **5 件事都到位** + +### 案例 3: 反例——缺 Stakes +- **问题**: 写作者写完 Setup 段, 读者反馈"不知道这本书讲什么" +- **方法论的使用**: 5 使命检查, 发现 Stakes 缺失 +- **结论**: 读者不知道"主角会失去什么" = 不关心 +- **结果**: 增补 Stakes 场景, 读者开始投入 + +## 可执行步骤 + +1. **把 Setup 段标出来** + - 完成标准: 用户能说出 0-25% 段 +2. **逐项检查 5 件事** + - 完成标准: 5 件事都有 yes/no 答案 + - Stakes: 读者知道主角会失去什么吗? + - Empathy: 读者同情主角吗? + - Backstory: 读者知道主角为什么是现在这样吗? + - Inner Demons: 读者感觉到主角有更深的问题吗? + - Hook/Foreshadow: 读者被吸引 + 感觉到未来冲突吗? +3. **统计 + 诊断** + - 完成标准: 5 全 yes = 通过 + - 4 yes = 还行, 但弱项要补 + - ≤ 3 yes = Setup 段没完成, 需改稿 +4. **改稿建议** + - 完成标准: 列出"缺哪件 + 怎么补" + - 补法: 在合适位置加 1-3 段 + +空白打勾表见 `../references/structure-checklists.md` 的"Setup 五使命打勾表"。 + +## 边界 + +### 不要在以下情况使用 + +- 整体 4 箱诊断(用 `four-boxes.md`) +- 检查 FPP 单点(用 `first-plot-point.md`) +- 中短篇(5 件事压缩, 不全适用, 体裁判断见 `length-system.md`) + +### 作者警告的失败模式 + +- 5 件事都做完, 但 Setup 段超过 30%——Setup 段功能完整, 但越界 +- 5 件事全 yes, 但读者反馈不行——可能其他 4 箱问题 +- 顺序乱, 但顺序不影响功能——顺序不是硬约束, 但建议 stakes/empathy 先做 + +### 作者盲点 + +- 5 件事假设"先 Setup 后剧情"——部分文学/实验小说可在 Setup 段就开打 +- 5 件事假设"主角 1 个"——群像/POV 切换需对每个主角各做 1 次 +- 5 件事假设"读者关心"——实际读者可能不关心, 需 1-2 个"反讽/惊喜"钩 + +### 易混方法论 + +- "Opening Hook"(不同作家)——只是 5 件事中的 1 件 +- "First Scene"(Save the Cat)——接近, 但 Snyder 只强调 1 个 hook +- "Inciting Incident"——是 5 件事完成后的"启动", 不是 Setup 段本身 + +## 中文落地(中文适配) + +- 网络连载的"黄金三章"相当于把五件事压缩进前三章:赌注和共情必须最先完成(读者决定去留就在前两章),背景故事拆成碎屑随事件带出,不能集中交代——中文读者对"介绍式背景"的耐受比英文商业小说更低。 +- 中文传统小说习惯先交代身世家门(如章回体的"话说某人,祖居某地"),这是把 backstory 前置的写法;用本条检查时,要确认它没有挤掉赌注和共情的位置,且内在恶魔的暗示仍在 Setup 段内完成。 +- 群像长篇(家族小说、多主角):对每个主角各做一遍五使命检查,与本书"群像各做一次"的盲点提醒同理。 diff --git a/framework/catalog/dsh/skills/story-structure/references/six-milestones.md b/framework/catalog/dsh/skills/story-structure/references/six-milestones.md new file mode 100644 index 0000000..8663890 --- /dev/null +++ b/framework/catalog/dsh/skills/story-structure/references/six-milestones.md @@ -0,0 +1,126 @@ +# 六大里程碑:在四箱之内定点 + +> 四箱是"段",里程碑是段内的固定"点"。宏观分段见 `four-boxes.md`,单点深入见 `first-plot-point.md`、`midpoint.md`。 + +## 原文摘录 + +> "In a 110-page screenplay, they show up at roughly pp. 1, 25, 37, 55, 75, 85, and 110. The same proportions apply to longer works, scaled accordingly. These are the dramatic milestones that anchor the structure: Hook, First Plot Point, First Pinch Point, Midpoint, Second Pinch Point, Second Plot Point, Resolution." +> +> — Larry Brooks, *Story Engineering* (2011), Part 5 + +## 方法骨架 + +在 4 箱之内, 故事有 6-7 个**固定位置**的关键节点。每个节点有特定功能, 位置偏离 = 结构错。 + +**6 大里程碑 + 1 终点**: + +| # | 名称 | 位置 | 功能 | +|---|---|---|---| +| 1 | Hook | 0-5% | 开篇钩子, 引起悬念 | +| 2 | First Plot Point (FPP) | ~25% | 对抗力量亮相, 主角接到任务 | +| 3 | First Pinch Point | ~37% | 提醒对抗力量仍存在 | +| 4 | Midpoint | ~50% | 主角从被动转主动 | +| 5 | Second Pinch Point | ~62% | 再次提醒对抗力量 | +| 6 | Second Plot Point (SPP) | ~75% | 重大反转/最后信息, 高潮充能 | +| 7 | Resolution | 95-100% | 故事收束 | + +**6 大里程碑的 3 组功能**: +- **激励组(Hook, FPP)**: 启动故事, 给任务 +- **推进组(Pinch, Midpoint, Pinch)**: 持续施压, 维持张力 +- **兑现组(SPP, Resolution)**: 收束故事, 主题兑现 + +**关键洞察**: +- 6 个里程碑是**位置**约束(硬约束), 不是内容约束 +- 每个里程碑的**功能**比**戏剧强度**重要——First Pinch 可以是"对话", 强度低但功能必须 +- 缺任何一个 = 故事功能缺失——没 Hook = 读者不读; 没 FPP = 故事没启动; 没 Midpoint = 主角没成长; 没 SPP = 高潮是"开挂" +- 多 1 个都不行——6 个里程碑各做 1 件事, 多 1 个 = 抢戏 + +**应用**: +- 诊断任何小说/剧本: 找这 6 个位置 +- 改稿: 移动里程碑到正确位置 +- 写新稿: 先定 6 个里程碑, 再展开 + +## 书中案例 + +### 案例 1: Thelma & Louise(《末路狂花》)的 6 里程碑 +- **Hook (0-5%)**: 两位主角无聊日常, 决定出去玩 +- **First Plot Point (25%, 31 分钟)**: 决定跑 +- **First Pinch Point (37%)**: 警察找到他们 +- **Midpoint (50%)**: 决定不停下来 +- **Second Pinch Point (62%)**: FBI 介入, 升级追捕 +- **Second Plot Point (75%)**: 警长给最后通牒 +- **Resolution**: 飞车冲下悬崖 +- **完美对齐 6 里程碑** + +### 案例 2: The Da Vinci Code(《达·芬奇密码》)的 6 里程碑 +- **Hook**: Langdon 被叫到卢浮宫(5 页) +- **FPP (25%)**: Saunière 留下神秘信息, Langdon 跑 +- **First Pinch**: 警察开始怀疑 Langdon +- **Midpoint**: Sophie 找到关键密码, Langdon 决定反击 +- **Second Pinch**: 神秘组织开始追 Langdon +- **SPP (75%)**: 找到"圣杯真相" + 知道 Silas 是谁 +- **Resolution**: 揭露阴谋 +- **每个里程碑都对位** + +### 案例 3: 反例——缺 Midpoint +- **问题**: 写作者写完, 故事"平"无转折 +- **方法论的使用**: 6 里程碑扫描, 发现 Midpoint 缺失 +- **结论**: 主角没有"从被动转主动", 整部平铺直叙 +- **结果**: 增补 Midpoint 场景后, 故事张力剧增 + +## 可执行步骤 + +1. **准备文本** + - 完成标准: 用户指定 1 个故事(自己的或现有的) + - 用页数或场景数标记位置 +2. **逐个找 6 里程碑** + - 完成标准: 6 个节点都有位置标注 + - 找不到 = 节点缺失 + - 位置偏离 25%±3% 太多 = 位置错位 +3. **验证每个节点的功能** + - 完成标准: 6 个节点都过功能检查 + - Hook: 1 句话吸引人? + - FPP: 主角接任务了? + - First Pinch: 对抗力量再次被想起? + - Midpoint: 主角从被动转主动? + - Second Pinch: 升级威胁? + - SPP: 给高潮充能? +4. **生成诊断报告** + - 完成标准: 1 张表, 列出"应有 vs 实际" + - 任何"无"或"错位"都是修改点 +5. **改稿** + - 完成标准: 列出至少 3 个具体修改动作 + +空白诊断表见 `../references/structure-checklists.md` 第 4 节"应有 vs 实际"诊断报告。 + +## 边界 + +### 不要在以下情况使用 + +- 写非叙事内容(本方法是叙事结构) +- 中短篇/单场景(6 里程碑不适用, 体裁判断见 `length-system.md`) +- 实验性叙事(非线性/多线并行)——需调整 + +### 作者警告的失败模式 + +- 把"事件密度高"当"里程碑多"——6 个, 不多不少 +- 把"主角做事"当"First Plot Point"——FPP 是"接任务", 不是"做任务" +- 把"高潮前紧张"当"Second Plot Point"——SPP 是"充能", 不是"紧张" + +### 作者盲点 + +- 6 里程碑假设单一 POV——多 POV 需对每个 POV 独立 +- 6 里程碑假设线性时间——非线性/倒叙需调整 +- 6 里程碑假设商业叙事——文学/实验小说可有意缺/移 + +### 易混方法论 + +- "Save the Cat 15 Beats"(Snyder)——是 6 里程碑的细化(15 个), 不替代 +- "Hero's Journey"(Campbell)——是原型, 不是 6 个固定位置 +- "7-Point Story Structure"(不同作家)——类似但有 1-2 节点差异 + +## 中文落地(中文适配) + +- 位置按字数比例换算:110 页剧本的比例(1、25、37、55、75、85、110 页)折成百分比后,对任何体量的中文长篇都适用;40 万字的小说,FPP ≈ 10 万字、Midpoint ≈ 20 万字、SPP ≈ 30 万字。 +- 网文连载的章末钩子密度高,容易把"事件密度"误当"里程碑多":章末小钩子不是里程碑,六个节点各做一件事的判据不变。 +- 章回体小说诊断时可按"回"标注位置(如 120 回制的第 30 回 ≈ 25%),与按字数换算结果互校。 diff --git a/framework/catalog/dsh/skills/story-structure/references/structure-checklists.md b/framework/catalog/dsh/skills/story-structure/references/structure-checklists.md new file mode 100644 index 0000000..453466a --- /dev/null +++ b/framework/catalog/dsh/skills/story-structure/references/structure-checklists.md @@ -0,0 +1,162 @@ +# 结构诊断清单(可执行工作表) + +> 把 references/ 里的判断标准汇成一套可逐项打勾的工作表。新稿搭骨架按"新稿顺序"走;改稿直接从第 4 项"应有 vs 实际"诊断报告开始。 +> 方法细节与案例以 references/ 对应文件为准;来源追溯见 references/_coverage.md。 + +## 0. 新稿搭骨架顺序 + +1. **定体制**:填第 1 节体制确认表;长篇才走完全套,短篇只取"触发事件 + 反常 + 豹尾"。 +2. **定两个锚点再动笔**:写出够用的第一句(进画面)和最后一句(降落画面);想不到第一句就跳过先写正文。→ `opening.md` +3. **切四箱**:用页数/字数/场景数标出 0-25%、25-50%、50-75%、75-100% 四段,一句话说出每段功能。→ `four-boxes.md` +4. **定点**:先定六个里程碑的位置,再往里填场景;写新稿的顺序是"先节点后展开"。→ `six-milestones.md` +5. **Setup 五件事逐项打勾**:见第 5 节;5 个 yes = 通过,4 个 = 补弱项,≤3 个 = 返工。→ `setup.md` +6. **FPP 验证**:见第 7 节;不要因为它"不够大"就重写一个更大的,强度不是标准。→ `first-plot-point.md` +7. **漫游者巡查**:见第 8 节。→ `part2-wanderer.md` +8. **中点确认**:见第 9 节。→ `midpoint.md` +9. **画加码楼梯**:见第 10 节;相邻两级"一样重"就是没升级,重新设计赌注维度。→ `inciting-incident.md` +10. **出诊断表(改稿用)**:见第 4 节"应有 vs 实际"表,任何"无"或"错位"转成至少 3 个具体修改动作。→ `six-milestones.md` + +## 1. 体制确认表 + +```yaml +我要写的: + 体裁:[短篇 / 中篇 / 长篇] + 核心人物数:[N] + 时间跨度:[N] + 核心技法:[冰山/铺垫/反常/性格发育/复调/命运] + 读者注意力预算:[X 小时] +``` + +对照硬规则: +- [ ] 短篇:人物 ≤3;场景 ≤5;时间 ≤24 小时或单一回溯;有 1 个反常事件;结尾有冲击(豹尾) +- [ ] 中篇:人物 3-10;有 1 个明确的性格转折;可分章节但节奏紧凑 +- [ ] 长篇:有人物命运的累积变化;短篇式精微已减少;复调/延宕有安排 +- [ ] 跨体裁转换:短→长已加人物/时间/命运(不是加长句子);长→短已做减法只留 1-2 核心场景;任何→短已检查反常点 + +## 2. 四箱切段表 + +| 段 | 应有位置 | 实际位置 | 功能检查 | 结果 | +|---|---|---|---|---| +| Setup | 0-25% | | 主角接任务了吗?(没 = 正确) | | +| Response | 25-50% | | 主角主动攻击了吗?(没 = 正确) | | +| Attack | 50-75% | | 主角主动进攻了吗?(是 = 正确) | | +| Resolution | 75-100% | | 故事收束了吗?(是 = 正确) | | + +错位记录(任何"过早/过晚"都列出,例:"主角在 20% 就接了任务"太早;"主角在 60% 还在 wanderer"太晚): + +- (空) + +## 3. 六里程碑定位表 + +| # | 里程碑 | 应有位置 | 实际位置 | 功能检查 | 结果(对位/缺失/错位) | +|---|---|---|---|---|---| +| 1 | Hook | 0-5% | | 1 句话吸引人? | | +| 2 | First Plot Point | ~25%(±3%) | | 主角接任务了? | | +| 3 | First Pinch Point | ~37% | | 对抗力量再次被想起? | | +| 4 | Midpoint | ~50%(±3%) | | 主角从被动转主动? | | +| 5 | Second Pinch Point | ~62% | | 升级威胁? | | +| 6 | Second Plot Point | ~75% | | 给高潮充能? | | +| 7 | Resolution | 95-100% | | 故事收束? | | + +规则提醒:六个不多不少;找不到 = 缺失;位置偏离太多 = 错位;功能比戏剧强度重要。 + +## 4. "应有 vs 实际"诊断报告 + +把第 3 节结果汇成一张表,任何"无"或"错位"都是修改点: + +| 里程碑 | 应有 | 实际 | 修改动作(至少 3 条) | +|---|---|---|---| +| | | | | + +## 5. Setup 五使命打勾表 + +Setup 段范围:0-25%(按页数/字数标出:____ 至 ____) + +| 使命 | 检查问句 | yes/no | +|---|---|---| +| Stakes 赌注 | 读者知道主角会失去什么吗? | | +| Empathy 共情 | 读者同情主角吗? | | +| Backstory 背景故事 | 读者知道主角为什么是现在这样吗? | | +| Inner Demons 内在恶魔 | 读者感觉到主角有更深的问题吗? | | +| Hook/Foreshadow 钩子+伏笔 | 读者被吸引 + 感觉到未来冲突吗? | | + +评分:5 全 yes = 通过;4 yes = 补弱项;≤3 yes = Setup 没完成,需改稿。 +补法:缺哪件 + 在合适位置加 1-3 段:____ + +篇幅检查:Setup 是否超过 30%(越界)?是/否 + +## 6. 开篇事件三问:inciting 还是 FPP + +开篇大事件:____(通常在 1-15%) + +| 三问 | 回答 | 判定 | +|---|---|---| +| 它赋予"任务/意义"吗? | yes / no | yes = FPP;no = inciting | +| 它在 25% 位置吗? | yes / no | yes = 可能是 FPP;no = inciting | +| 戏剧强度极高? | yes / no | yes = 倾向 inciting | + +后续处置: +- [ ] 只有 inciting 没有 FPP → 在 25% 处设计 FPP(主角的"决策/任务/意义"瞬间;可弱强度,必须明确意义) +- [ ] 只有 FPP 没有 inciting → 增补开篇钩子(Hook)或小事件 + +## 7. FPP 验证表 + +FPP 候选场景(主角接到新任务/新身份/新威胁的瞬间):____ + +| 检查 | 结果 | +|---|---| +| 对抗力量亮相了吗? | | +| 主角接任务了吗? | | +| 赌注明确了吗? | | +| 位置在 25%±3% 吗?(偏早 20% 前 = Setup 不足;偏晚 30% 后 = Response 被压缩) | | + +处置:3 问全 yes 且位置合格 = 通过;不要因"不够精彩"重写更大的——强度不是标准。改写方案(1-2 条):____ + +## 8. 漫游者巡查表 + +列出 25-50% 的 3-5 场关键戏,逐场检查: + +| 场景 | 主角动作 | 属于六类允许动作?(跑/躲/分析/观察/重算/计划招募) | 是否主动进攻(打怪/破案/解决冲突)? | 若主动,是否合法例外(极小主动/局部小障碍/为中点觉醒服务)? | 处置 | +|---|---|---|---|---|---| +| | | | | | | + +越界场景处置:移到 50% 之后,或改成局部小主动:____ + +## 9. 中点验证表 + +Midpoint 候选(主角变主动的瞬间):____ + +| 检查 | 结果 | +|---|---| +| 主角心态/行为转向了吗(从"被做"到"去做")? | | +| 有新信息/觉醒/承诺吗? | | +| 形式属于四种之一?(觉醒/承诺/新盟友/新赌注) | | +| 位置在 50%±3% 吗?(偏早 = Response 太短;偏晚 = Attack 太短) | | +| 排除三种假中点:反派大动作?主角小胜利?纯信息揭示(主角没拿它行动)? | | + +缺失处置:找 Part 2 结尾 + Part 3 开头的"主角觉醒"瞬间,增补 1 场戏。改写方案:____ + +## 10. 加码楼梯表与赌注自检 + +触发事件(一句话,具体到哪一天哪一秒哪个事件):____ +检验:它是否"radically upsets the balance of forces in the protagonist's life"(主角日常真的被打碎,前稳定/后被打破可对比)?是/否 +若写成了"主角渐渐觉醒"一类的状态变化 → 改写为具体动作(接到电话/推门发现/错过末班车):____ + +加码楼梯(按时间顺序,至少 5 级,每级一句"从 X 升级到 Y";可量化:影响范围/不可逆程度/时间压力/涉及角色数): + +| 级 | 从 X 升级到 Y | 赌注维度(个人→家庭→社群→公众→国家→文明) | +|---|---|---| +| 1 | | | +| 2 | | | +| 3 | | | +| 4 | | | +| 5 | | | +| 6(可加) | | | +| 7(可加) | | | + +检查:任何相邻两级"一样重"(第 3 级 = 第 2 级)= 赌注没升 → 重新设计赌注维度。 + +每 3-5 章自检(写完每 3-5 章做一次): +- [ ] 最近这段的赌注,比 3-5 章前更高吗? +- [ ] 如果删掉这段,故事会失去什么?(答"不影响"= 这段是中段塌陷的元凶,重写或删除) +- [ ] 全书是否只有"开篇 + 结尾"两次赌注?(是 = 中段塌陷典型结构,必须补 2-3 个中间加码点;可借助"be careful what you wish for"——新获得的东西变成新威胁) diff --git a/framework/catalog/dsh/skills/theme-and-stance/SKILL.md b/framework/catalog/dsh/skills/theme-and-stance/SKILL.md new file mode 100644 index 0000000..5468429 --- /dev/null +++ b/framework/catalog/dsh/skills/theme-and-stance/SKILL.md @@ -0,0 +1,96 @@ +--- +name: theme-and-stance +description: | + 中文小说的主题表达与作家立场的执行层:主题不由作者说出来,由人物在关键时刻的选择演示出来; + 立场不靠主题先行去安排,藏进环境与性格的碰撞里自然浮现;沉重题材不写成控诉、苦情或谩骂, + 用幽默建立与现实的关系;人物该受的苦,作者不能因为心软而放过。 + 激活场景:主题写成说教、立场太直白;人物像作者传声筒、情节被安排去服务主题; + 沉重题材写得压抑、愤怒、读着难受;作者舍不得人物受苦、写到关键处手抖。 + 关键 trigger:"主题说教" "主题太直白" "主题先行" "席勒化" "莎士比亚化" "主题怎么表达" + "show don't tell 主题" "演示主题" "手软" "舍不得" "手抖" "心慈手狠" "狠瞬间" + "黑色幽默" "沉重题材" "太沉重了" "批判但不说教" "读着压抑" "布尔加科夫" "卡夫卡式幽默"。 + 不适用于:非虚构/纪实/学术写作(主题表达方式不同);寓言、童话、儿童文学 + (可以明说主题,也可以心慈不手狠);纯喜剧写作(幽默本身就是目的); + 大屠杀、重大灾难等纯悲剧庄重题材(慎用幽默,会显得轻佻); + 主题尚未建立(先用 concept-design 做概念设计)。 + 与 show-and-omission 交接:标签换场景、冰山留白、视角穿帮归 show-and-omission;主题演示、立场与手软/幽默结构归本 Skill。 + 与 narration-pov 交接:外来者切入的荒诞/幽默距离与结构(含撒旦访莫斯科全文案例)归本 Skill;narration-pov 只保留 POV 侧外来者机制指针。 +--- + +# 主题与立场 + +主题不是作者说出来的道理,是读者自己看出来的东西;立场不是作者的表态,是环境、人物逻辑和命运重量共同逼出来的结论。本 skill 管四件事:主题怎么不说教(演示)、立场怎么不先行(莎士比亚化)、人物该受的苦怎么不放过(心慈手狠)、沉重题材怎么不被仇恨淹没(幽默作为结构)。 + +## 方法索引 + +### 定主题与查主题 + +- 主题是故事对现实照亮什么,必须具体到"关于 X 中的 Y";"关于人性"是模糊哲学,无法演示 → references/theme-demonstration.md +- 陈述的主题是被动的,演示的主题是主动的;角色说出主题就变成作者传声筒,读者立刻感到"被教" → references/theme-demonstration.md + +### 植入主题:演示而非说出 + +- 三种演示法:决策演示(关键场景选 A 还是 B,选什么就是主题立场)、结构演示(开头与结尾、失败与成功对照)、反讽演示(说一套做一套,落差即主题) → references/theme-demonstration.md +- Tell 扫描三类位置(角色对话陈述主题、叙述者点题、章节开头寓言式开篇),把"说"改成场景中"做",再补 1-2 个小决策演示场景 → references/theme-demonstration.md;references/theme-stance-checklist.md + +### 防主题先行:把立场翻译成环境与人物 + +- 席勒化是思想先行安排情节(作家当指挥家),莎士比亚化是让人物按小说内部逻辑自己走(作家是看不见的手) → references/stance-by-logic.md +- 操作方向:不写"批判 X、主角揭发 X",写一个具体的 X 场景加一个性格鲜明的当事人,让场景和性格碰撞,主题自然浮现 → references/stance-by-logic.md +- 性格碰撞推力链:A 的性格撞 B 的性格必然产生事件,事件改变环境,环境反作用于人物,每一环都要可推导、不能跳跃 → references/stance-by-logic.md + +### 作家沉默:三项检验 + +- 发言权检验:"如果我什么都不说,人物会自己走到这一步吗?" → references/stance-by-logic.md +- 必然性检验:删掉任何一个事件,故事完全垮掉才是必然的,不影响就是多余的 → references/stance-by-logic.md +- 终极检验:删掉全部作家发言(解释、议论、心理分析),读者还能读懂才算莎士比亚化 → references/stance-by-logic.md;references/theme-stance-checklist.md + +### 对人物的立场:心慈手狠 + +- 心慈是前提:不爱的人物写不好;手狠是诚实:不能因为爱就放过他——"手狠"不是恶意,是诚实地写出人物命运的必然 → references/mercy-ruth.md +- 每个主要人物要有 1-3 个"狠瞬间"(作家对他最残酷的瞬间);全是甜的是心慈手不狠,全是狠的是手狠心不慈 → references/mercy-ruth.md +- 三个手软信号:"舍不得""算了他不该这么惨""突然让他走运"——出现任何一个就回到性格加逻辑,把该给的代价给足 → references/mercy-ruth.md;references/theme-stance-checklist.md + +### 沉重题材的立场:幽默作为结构 + +- 面对无法改变的痛苦现实,除了妥协和对抗还有第三条路:幽默不是插科打诨,是整体的叙述结构和态度,让作者不被仇恨淹没、想象力开始茁壮成长 → references/humor-as-stance.md +- 幽默距离三档:近距人物在苦难中自嘲(余华式)、中距叙述者冷幽默(卡夫卡式)、远距引入荒诞元素制造间离(布尔加科夫式,让魔鬼访问莫斯科) → references/humor-as-stance.md +- 让荒诞自行呈现:不直接批判,写荒诞细节(翻箱倒柜找文件、永远找不到的负责人),全文至少 3 处"让人发笑但笑后不安"的细节;笑的对象是环境和制度,不是人物 → references/humor-as-stance.md;references/theme-stance-checklist.md + +### 边界与误诊 + +- 寓言、童话、儿童文学可以明说主题、可以心慈不手狠;魔幻现实主义只部分适合莎士比亚化(用环境逻辑替代日常逻辑) → references/boundaries-and-pitfalls.md +- 大屠杀、重大灾难等纯悲剧庄重题材慎用幽默;个人真实创伤书写先做情感宣泄,幽默的距离为时尚早 → references/boundaries-and-pitfalls.md +- 常见错误表(席勒化四错、心软五错)与易混方法(Show Don't Tell、契诃夫之枪、讽刺、喜剧 relief)→ references/boundaries-and-pitfalls.md + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|----------| +| references/theme-demonstration.md | 主题演示而非告诉:英文原段引文与白话转述;陈述主题 vs 演示主题;Show/Tell 在主题上的应用;Tell 失败三原因;三种演示法(决策/结构/反讽);案例三个(《苹果酒屋法则》Homer Wells 的选择与奥斯卡、《可爱的骨头》Susie 天上视角与 1000 万册、反例"主题演讲");四步执行流程(确认主题、扫描 Tell、改成 Show 含撤离船例子、补 1-2 个演示场景);触发场景与语言信号;中文落地与适配;《小说课》"主题自然浮现"跨书呼应 | +| references/stance-by-logic.md | 莎士比亚化 vs 席勒化:"思想性传递"原文引文;林冲"走"上梁山的错误写法与正确写法全链(白虎堂→野猪林→牢城营→草料场→雪→风→石头→听到阴谋→杀人→柴进指路→上山);五维对照表;案例四个(林冲风雪石头因果链、《促织》"为人迁讷"、《项链》改写版 vs 原文、王熙凤"毒设相思局");五步执行流程(主题翻译成环境、推力链、发言权检验、必然性检验、让作家沉默);触发场景五条;一句话总结 | +| references/mercy-ruth.md | 心慈手狠:"心慈手狠"与"手不能抖"原文引文;《项链》"发红的手"原文与毕飞宇解读;心慈与手狠的关系三种;案例五个(《项链》、《苔丝》、《促织》、鲁迅闰土与杨二嫂、王熙凤"哭向金陵");五步执行流程(检验心慈、检验手狠、找狠瞬间、避开心软诱惑、用心慈写手狠);触发场景五条;一句话总结 | +| references/humor-as-stance.md | 幽默作为结构:余华论布尔加科夫三段引文与"让魔鬼访问莫斯科"段;两种反应与第三条路;幽默作为结构四个核心;案例三个(布尔加科夫沃兰德访问 1930 年代莫斯科、卡夫卡《城堡》官僚细节、余华《许三观卖血记》卖血仪式);六步执行流程(识别沉重程度、选幽默距离、让荒诞自行呈现、保持人物尊严、控制叙述节奏、检查幽默是否成为结构,各含完成标准);触发场景与语言信号 | +| references/boundaries-and-pitfalls.md | 四家不适用场景汇总(非虚构、主题根本不存在、寓言童话儿童文学、纯悲剧庄重题材、纯喜剧、个人创伤、反派视角慎用);失败模式(主题模糊哲学、反讽用错、删 Tell 不补 Show、幽默变嘲笑、幽默消解批判);作者盲点(Brooks 三个、余华两个);常见错误表两张(席勒化四行、心软五行);易混方法(Show Don't Tell、契诃夫之枪、象征叙事、讽刺、喜剧 relief);相邻方法区分与跨域链接(concept/character/show-and-omission/foreshadow-payoff/narration-pov/narrative-momentum/prose-craft/character-presentation) | +| references/theme-stance-checklist.md | 修订与写作中检查清单:主题 Tell 扫描(搜"主题关键词+说出动词")、主题翻译成环境、推力链、发言权检验、必然性检验、作家沉默终极检验、心慈手狠五项检验、狠瞬间盘点、幽默距离与结构检验;快速排错表 | + +## 脚本 + +| 脚本 | 用途 | 来源 | +|------|------|------| +| references/theme-stance-checklist.md | 写前建碰撞、写中防手软、改稿五项检验的可执行清单,附症状→诊断→处方排错表 | 四个源单元 | + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/dsh/skills/theme-and-stance/references/_coverage.md b/framework/catalog/dsh/skills/theme-and-stance/references/_coverage.md new file mode 100644 index 0000000..03e087b --- /dev/null +++ b/framework/catalog/dsh/skills/theme-and-stance/references/_coverage.md @@ -0,0 +1,15 @@ +# theme-and-stance 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| bifeiyu-novel-skill/bifeiyu-mercy-ruth | references/mercy-ruth.md | +| bifeiyu-novel-skill/bifeiyu-mercy-ruth | references/boundaries-and-pitfalls.md | +| bifeiyu-novel-skill/bifeiyu-shakespeare | references/stance-by-logic.md | +| bifeiyu-novel-skill/bifeiyu-shakespeare | references/theme-demonstration.md | +| bifeiyu-novel-skill/bifeiyu-shakespeare | references/boundaries-and-pitfalls.md | +| story-engineering/theme-demonstrate-not-tell | references/theme-demonstration.md | +| story-engineering/theme-demonstrate-not-tell | references/boundaries-and-pitfalls.md | +| wo-neng-fou-xiang-xin-zi-ji/humor-as-structure | references/humor-as-stance.md | +| wo-neng-fou-xiang-xin-zi-ji/humor-as-structure | references/boundaries-and-pitfalls.md | diff --git a/framework/catalog/dsh/skills/theme-and-stance/references/boundaries-and-pitfalls.md b/framework/catalog/dsh/skills/theme-and-stance/references/boundaries-and-pitfalls.md new file mode 100644 index 0000000..d61323b --- /dev/null +++ b/framework/catalog/dsh/skills/theme-and-stance/references/boundaries-and-pitfalls.md @@ -0,0 +1,110 @@ +# 边界、常见误区与易混方法 + +> 汇总四个源单元的适用边界、失败模式、作者盲点、常见错误表、易混方法与相邻方法区分。每条标注来源。 +> 方法正文见:[theme-demonstration.md](theme-demonstration.md)、[stance-by-logic.md](stance-by-logic.md)、[mercy-ruth.md](mercy-ruth.md)、[humor-as-stance.md](humor-as-stance.md)。 + +## 一、不适用场景汇总 + +| 场景 | 原因 | 来源 | +|------|------|------| +| 非虚构 / 纪实 / 学术 | 主题表达方式不同 | /theme-demonstrate-not-tell | +| 主题根本不存在 | 需要先建主题(先做概念设计) | /theme-demonstrate-not-tell | +| 寓言、童话 | 寓言可以"说"主题,不在演示范围 | /theme-demonstrate-not-tell | +| 寓言、童话(立场层) | 它们恰恰需要席勒化 | /bifeiyu-shakespeare | +| 儿童文学、纯治愈系 | 它们恰恰要"心慈不手狠"(慎用) | /bifeiyu-mercy-ruth | +| 反派视角叙事 | 容易"手狠心不慈"(慎用) | /bifeiyu-mercy-ruth | +| 纯粹的悲剧 / 庄重题材(大屠杀、严重灾难) | 需要保持庄重,幽默会显得轻佻 | /humor-as-structure | +| 喜剧写作(情景喜剧等) | 幽默本身就是目的,不需要"幽默作为结构"——它就是全部 | /humor-as-structure | +| 个人创伤书写 | 处理自己的真实创伤可能需要先情感宣泄,幽默的距离可能为时尚早 | /humor-as-structure | + +适用面(正面): + +- 莎士比亚化**适合**现实主义小说、所有长篇、所有"严肃"叙事;**部分适合**魔幻现实主义(用环境逻辑替代日常逻辑)。(/bifeiyu-shakespeare) +- 心慈手狠**适合**所有虚构叙事,**特别适合**现实主义、批判现实主义。(/bifeiyu-mercy-ruth) + +## 二、失败模式(作者在书中警告的) + +**主题演示**(/theme-demonstrate-not-tell): + +- 主题是"模糊哲学"(如"关于人性")——必须具体到"关于 X 中的 Y" +- 反讽用错——让反派"说"主题让主角"做"反讽主题——容易混乱 +- 删除 Tell 后完全没有主题——应增加 Show 演示,不是简单删除 + +**幽默作为结构**(/humor-as-structure): + +- **幽默变成嘲笑**:幽默不是嘲笑人物的苦难,而是与苦难保持距离。如果读者感到作者在嘲笑人物,就失败了 +- **幽默消解了批判**:如果幽默过度,会让读者觉得"这也没什么大不了",失去批判力量。需要"控制得恰如其分" + +## 三、作者盲点 + +**Brooks**(/theme-demonstrate-not-tell): + +- 假设所有题材都不能 Tell——童话/寓言/儿童文学可以 Tell +- 假设"反讽" = 主题成功——反讽必须清晰,否则读者看不出 +- 假设"复杂主题"必须复杂演示——简单主题用 1 个场景就够 + +**余华**(/humor-as-structure): + +- 余华主要讨论极权/压迫环境下的幽默,没有讨论日常/普通题材中如何使用幽默作为结构 +- "幽默作为结构"是比较高级的技巧,需要相当的写作经验,初学者可能难以掌握 + +## 四、常见错误表 + +### 席勒化四类错误(/bifeiyu-shakespeare) + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 让人物"觉醒" | 突兀 | 觉醒前必须有"压垮骆驼的最后一根稻草"——具体的、可推导的 | +| 用"巧合"推情节 | 廉价 | 巧合要少用,且要"埋"——让读者读后才恍然 | +| 人物"被作者安排" | 假 | 让人物按性格走,作家只设环境 | +| 思想性太重 | 主题先行 | 把思想藏进环境 | + +### 心软五类错误(/bifeiyu-mercy-ruth) + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 心慈不手狠 | 烂好人作品 | 让人物承担他应承担的 | +| 手狠不心慈 | 虐待狂 | 检验你"爱不爱他" | +| 突然让命运变好 | 假 | 命运不可逆 | +| 让主角"轻飘飘"就过去 | 假 | 主角的命运必须有重量 | +| 写到关键处手抖 | 假 | 你手软了——回到性格 + 逻辑 | + +## 五、易混方法 + +**与主题演示易混**(/theme-demonstrate-not-tell): + +- "Show Don't Tell"(写作通用)——本 skill 的主题演示是它的主题特化版;句子与情绪层的展示方法在 `show-and-omission`(展示与留白) +- "Chekhov's Gun"(契诃夫之枪)——是"伏笔演示",不是"主题演示";见 `foreshadow-payoff`(伏笔与回收) +- "Symbolic Storytelling"(象征叙事)——是"通过象征演示",比主题演示宽 + +**与幽默结构易混**(/humor-as-structure): + +- **"讽刺"(satire)**:讽刺是用幽默批判具体对象,有明确的靶子。本方法是用幽默作为整体叙述态度,不一定有具体靶子——更接近"黑色幽默"而非"讽刺"。 +- **"喜剧 relief"**:喜剧 relief 是在沉重场景中插入搞笑段落缓解紧张,是局部技巧。本方法是全局结构——幽默贯穿全文,不是偶尔的调剂。 + +## 六、相邻方法区分与跨域链接 + +**主题演示与相邻 skill 的区分**(/theme-demonstrate-not-tell): + +- `concept-design`(概念与前提)的 concept-* 系列:是"找种子"(主题独立,不是 concept) +- `character-design`(人物设计)的 character-* 系列:是"建角色"(主题通过角色演示;源单元标注与 character-seven-variables 为 composes-with 关系) +- 本 skill:是"主题如何呈现"(执行层面) + +**幽默结构与相邻方法的区分**(/humor-as-structure): + +- 与 `narration-pov`(叙述与视角)的 skeptical-narration 的区别:本方法是用幽默的态度处理现实,skeptical-narration 是用怀疑的立场处理看法。两者经常配合——幽默中包含怀疑,怀疑中带有幽默。 +- 与 `show-and-omission`(展示与留白)的 imagination-to-fact 的区别:本方法关注叙述态度,imagination-to-fact 关注虚构内容的可信度。幽默的态度往往需要超现实的想象(如撒旦访问莫斯科),两者配合使用。 + +**莎士比亚化的跨域链接**(/bifeiyu-shakespeare): + +- 与 `show-and-omission`(展示与留白)的 bifeiyu-anti-logic 互补:莎士比亚化用逻辑,反逻辑是它的"另一面" +- 与 `character-presentation`(人物呈现)的 bifeiyu-character-fate 同源:性格即命运 = 性格 + 现实的逻辑推演 +- 与 `narrative-momentum`(叙事动力)的 bifeiyu-momentum 关联:莎士比亚化是"势"能产生的方法 +- 与本 skill 的 bifeiyu-mercy-ruth(心慈手狠)配对:作家要"手狠"才能让逻辑自己走——不能因心软去救人物 + +**心慈手狠的跨域链接**(/bifeiyu-mercy-ruth): + +- 与 `character-presentation`(人物呈现)的 bifeiyu-character-fate 配套:性格碰撞出来的命运 = 作家"手狠"的依据 +- 与本 skill 的 bifeiyu-shakespeare 同源:莎士比亚化要求作家"沉默",心慈手狠是前提 +- 与 `narrative-momentum`(叙事动力)的 bifeiyu-momentum 关联:势的累加 = 手狠——不能因心软去"减弱"势 +- 与 `prose-craft`(语言与修辞)的 bifeiyu-base-temp 关联:大师的温度是"冷中的热"——心慈手狠 = 冷温度下的热关怀 diff --git a/framework/catalog/dsh/skills/theme-and-stance/references/humor-as-stance.md b/framework/catalog/dsh/skills/theme-and-stance/references/humor-as-stance.md new file mode 100644 index 0000000..86987e7 --- /dev/null +++ b/framework/catalog/dsh/skills/theme-and-stance/references/humor-as-stance.md @@ -0,0 +1,125 @@ +# 幽默作为结构:沉重题材的第三条路 + +> 来源单元:《我能否相信自己》(余华)wo-neng-fou-xiang-xin-zi-ji/humor-as-structure,《布尔加科夫与〈大师和玛格丽特〉》(1996)。 +> 本文件管沉重题材的立场:既不向现实妥协,也不与现实对抗,用幽默建立第三种关系。主题为什么不能直接说出见 [theme-demonstration.md](theme-demonstration.md);"批判但不说教"的另一半(把批判藏进环境与性格碰撞)见 [stance-by-logic.md](stance-by-logic.md);边界与易混方法见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> "幽默成为了结构,成为了叙述中控制得恰如其分的态度,也就是说幽默使布尔加科夫找到了与世界打交道的最好方式。" + +> "他两者都放弃了,他做出的选择是一个优秀作家应有的选择,最后他与现实建立了幽默的关系。" + +> "正是这样的方式,使布尔加科夫在其最后的写作里,没有被自己的仇恨淹没,也没有被贫穷拖垮,更没有被现实欺骗。同时,他的想象力,他的洞察力,他写作的激情开始茁壮成长了。" + +——余华,《布尔加科夫与〈大师和玛格丽特〉》 + +(/humor-as-structure) + +## 方法核心 + +当作家面对无法改变的痛苦现实时,有两种常见反应: + +1. **与现实妥协**:失去力量,作品变成歌功颂德 +2. **与现实对抗**:变成谩骂和哭叫,作品被愤怒淹没 + +布尔加科夫选择了**第三种方式:幽默**。但这里的幽默不是修辞技巧(机智的讽刺、俏皮的对话),而是**整体的叙述结构和态度**——是作家与世界打交道的方式。 + +幽默作为结构的核心: + +- **不被仇恨淹没**:幽默让作家与痛苦保持距离,可以审视它而非被它吞噬 +- **解放想象力**:幽默的态度让荒诞的想象成为可能(撒旦访问莫斯科) +- **控制叙述**:幽默是"控制得恰如其分的态度",让叙述在沉重和轻松之间保持平衡 +- **与现实的关系**:既不妥协也不对抗,而是用幽默"与现实建立关系" + +布尔加科夫在斯大林时代作品被禁,他让魔鬼沃兰德访问莫斯科,用幽默的方式处理自己的仇恨和痛苦。"他让魔鬼访问莫斯科,作品一开始他就表明了自己的态度,那就是他要讲述的不是一个斤斤计较的故事,他要告诉我们的不是个人的恩怨,而是真正意义上的现实。" + +(/humor-as-structure) + +## 书中案例 + +### 案例 1:布尔加科夫《大师和玛格丽特》——撒旦访问莫斯科 + +- **问题**:布尔加科夫在斯大林时代作品被禁,生活贫困,朋友疏远,如何写这个时代而不变成谩骂? +- **方法论的使用**:他让撒旦(沃兰德)带着随从访问 1930 年代的莫斯科,用魔鬼的视角审视苏联社会的虚伪和荒诞。撒旦的游戏(让莫斯科人惊慌失措)既是对现实的批判,又充满幽默和想象力。布尔加科夫"没有被自己的仇恨淹没,也没有被贫穷拖垮,更没有被现实欺骗"。 +- **结论**:幽默成为结构,让沉重的题材变得可写且有力。 +- **结果**:《大师和玛格丽特》成为 20 世纪最伟大的小说之一,死后出版,影响深远。 + +### 案例 2:卡夫卡《城堡》——官僚制度的黑色幽默 + +- **问题**:如何描写一个荒诞而压迫的官僚制度而不变成控诉? +- **方法论的使用**:卡夫卡用幽默的细节呈现官僚制度的荒谬——村长家翻箱倒柜找文件,电话接通后听到无数声音(因为所有电话同时接通),克拉姆先生仿佛生活在传说中。这些细节让人发笑,但笑完后感到深深的不安。 +- **结论**:幽默不是为了搞笑,而是让荒诞自行呈现——制度的不合理性通过外来者 K 的不适应自然暴露。 +- **结果**:《城堡》成为表现主义文学的经典,官僚批判的巅峰之作。 + +### 案例 3:余华《许三观卖血记》——苦难中的幽默 + +- **问题**:写一个人靠卖血维持生活的苦难故事,如何不变成苦情戏? +- **方法论的使用**:余华用通篇对话和冷幽默处理许三观的苦难——许三观卖血前要多喝水,卖血后要吃炒猪肝喝黄酒,这些仪式化的细节既真实又带着黑色幽默。人物在苦难中仍然有尊严和笑声。 +- **结论**:幽默让苦难有了温度,读者不是同情而是共情。 +- **结果**:《许三观卖血记》成为余华最受欢迎的作品之一。 + +(以上案例均出自/humor-as-structure) + +## 执行步骤 + +1. **识别题材的沉重程度** + - 这个题材涉及哪些痛苦/压迫/荒诞? + - 如果直接写,会变成什么?(控诉?苦情?谩骂?) + - 完成标准:明确题材的沉重点和直接写法的风险 + +2. **选择幽默的距离** + - 决定幽默与痛苦的距离: + - 近距幽默:人物在苦难中自嘲(余华式) + - 中距幽默:叙述者用冷幽默评论(卡夫卡式) + - 远距幽默:引入荒诞元素制造间离(布尔加科夫式,撒旦访问莫斯科) + - 完成标准:明确幽默的距离和方式 + +3. **让荒诞自行呈现** + - 不直接批判,而是让荒诞的细节自己说话 + - 官僚制度:写翻箱倒柜找文件、电话接通后无数声音、永远找不到的负责人 + - 社会虚伪:让人物在荒诞场景中一本正经地行事 + - 完成标准:至少有 3 处"让人发笑但笑后不安"的细节 + +4. **保持人物的尊严** + - 幽默不是嘲笑人物,而是嘲笑环境/制度 + - 人物在苦难中仍然有尊严、有逻辑、有笑声 + - 完成标准:读者对人物是共情而非俯视 + +5. **控制叙述节奏** + - 幽默段落和沉重段落交替,不要全程搞笑也不要全程压抑 + - 幽默的"度":控制得恰如其分,不过度也不不足 + - 完成标准:叙述在沉重和轻松之间有平衡 + +6. **检查幽默是否成为结构** + - 幽默是贯穿全文的态度,还是偶尔的俏皮话? + - 如果只是偶尔的俏皮话,需要回到步骤 2,让幽默成为整体结构 + - 完成标准:幽默是全文的叙述态度,不只是修辞装饰 + +(/humor-as-structure) + +## 触发场景与语言信号 + +用户会在什么情境下需要这个方法(/humor-as-structure): + +1. 写沉重/痛苦/批判题材,作品变得压抑、愤怒,自己写着都难受 +2. 想写黑色幽默但不知道怎么操作 +3. 批判社会/人性时忍不住变成说教或谩骂 +4. 作品被反馈"太沉重了""读着压抑" +5. 想学习布尔加科夫/卡夫卡式的幽默 +6. 写荒诞题材但缺乏幽默感 + +语言信号: + +- "写得太压抑" "太沉重了" +- "黑色幽默怎么写" "dark humor" +- "批判但不说教" "不想变成谩骂" +- "荒诞题材" "幽默结构" +- "作品读着难受" "需要轻松一点" +- "布尔加科夫" "卡夫卡式幽默" + +## 与其他方法的关系 + +- 与 `narration-pov`(叙述与视角)的 skeptical-narration 配合:本方法是用幽默的态度处理现实,怀疑叙述是用怀疑的立场处理看法。两者经常配合——幽默中包含怀疑,怀疑中带有幽默。(完整区分见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)) +- 与 `show-and-omission`(展示与留白)的 imagination-to-fact 配合:本方法关注叙述态度,想象锚定关注虚构内容的可信度。幽默的态度往往需要超现实的想象(如撒旦访问莫斯科),两者配合使用——用想象-事实转化让荒诞可信。(完整区分见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)) + +(/humor-as-structure) diff --git a/framework/catalog/dsh/skills/theme-and-stance/references/mercy-ruth.md b/framework/catalog/dsh/skills/theme-and-stance/references/mercy-ruth.md new file mode 100644 index 0000000..097573b --- /dev/null +++ b/framework/catalog/dsh/skills/theme-and-stance/references/mercy-ruth.md @@ -0,0 +1,183 @@ +# 心慈手狠(Merciful Heart, Ruthless Hand):爱你的角色,但不要放过他 + +> 来源单元:《小说课》(毕飞宇)bifeiyu-novel-skill/bifeiyu-mercy-ruth,第 5 章(风格·态度)。 +> 本文件管作家对人物受苦的态度:心慈是前提,手狠是诚实。莎士比亚化要求作家"沉默",心慈手狠是它的前提,见 [stance-by-logic.md](stance-by-logic.md);边界与常见错误见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> 「我喜欢'心慈''手狠'的作家。鲁迅就是这样。'心慈'加'手狠'大概可以算作大师级作家的共同特征了。用李敬泽的说法,写到关键的地方,'作家的手不能抖'。」 + +(/bifeiyu-mercy-ruth) + +莫泊桑《项链》写马蒂尔德还了 10 年债之后: + +> "她已经变成一个粗壮耐劳的妇女了……她说话粗声大气……她提着脏衣服篮子……**她的手是发红的**。" + +**毕飞宇解读**: + +> "莫泊桑就'手狠'。'发红的手'就证明了莫泊桑的'手'有多'狠'。" + +- "心慈":莫泊桑同情马蒂尔德的虚荣 +- "手狠":莫泊桑没有放过她——给了她最残酷的结局 + +**"手狠"不是恶意——是诚实**。作家必须诚实地写出人物命运的必然。 + +(/bifeiyu-mercy-ruth) + +## 方法核心 + +**心慈 = 作家要爱自己的人物**。 + +**手狠 = 作家不能因为爱而放过人物**。 + +**两者的关系**: + +- 只心慈不手狠 = 烂好人作品(人物没真实命运) +- 只手狠不心慈 = 虐待狂作品(人物没灵魂) +- **心慈+手狠 = 大师作品(人物有真实命运)** + +(/bifeiyu-mercy-ruth) + +## 书中案例 + +### 案例 1:莫泊桑《项链》"发红的手" + +- 莫泊桑爱马蒂尔德吗?→ **爱**(她是人,有人的虚荣) +- 莫泊桑放过她吗?→ **没有**(她必须为虚荣付出代价) +- "发红的手"是莫泊桑的"狠"——**但这狠背后是爱** + +(同一作品《项链》在"莎士比亚化"单元里从逻辑自洽角度出现——人物性格 + 时代背景 → 自然借项链,见 [stance-by-logic.md](stance-by-logic.md) 案例 3。) + +### 案例 2:哈代《苔丝》 + +- 哈代爱苔丝吗?→ **深爱**(给她最纯粹的忠诚和痛苦) +- 哈代放过她吗?→ **没有**(杀了她) +- 哈代同情苔丝,但没放过她——**心慈手狠** + +### 案例 3:蒲松龄《促织》 + +- 蒲松龄爱成名一家吗?→ **爱**(同情他们的痛苦) +- 蒲松龄放过他们吗?→ **没有**(儿子变成蛐蛐、死亡、复活) +- 这是"心慈手狠"——**写了最残酷的故事** + +(同一作品《促织》在"莎士比亚化"单元里从性格碰撞角度出现——"为人迁讷"四个字然后小说自己跑,见 [stance-by-logic.md](stance-by-logic.md) 案例 2。) + +### 案例 4:鲁迅 + +- 鲁迅爱闰土吗?→ **爱**(年轻时是"自然关系") +- 鲁迅放过闰土吗?→ **没有**(让他叫"老爷"——揭示奴性) +- 鲁迅爱杨二嫂吗?→ **复杂**(批判但不蔑视) +- 鲁迅放过杨二嫂吗?→ **没有**(让她变成"圆规") + +### 案例 5:曹雪芹 + +- 曹雪芹爱王熙凤吗?→ **爱**(她是曹雪芹心中最精彩的人物) +- 曹雪芹放过王熙凤吗?→ **没有**(让她"哭向金陵事更哀") + +(同一人物王熙凤在"莎士比亚化"单元里从性格逻辑角度出现——管的性格 + 贾府复杂关系 → 必然"毒设相思局",见 [stance-by-logic.md](stance-by-logic.md) 案例 4。) + +(以上案例均出自/bifeiyu-mercy-ruth) + +## 执行步骤 + +### 步骤 1:检验"心慈" + +> "我爱我的主角吗?" + +- 爱 → 写下去 +- 不爱 / 蔑视 → 删掉或改写(你不爱的人物写不好) + +**心慈是基础**——你必须先爱人物,才能写他。 + +### 步骤 2:检验"手狠" + +> "我有没有因为我爱他就放过他?" + +- 放过他 → 你手软了——再狠一点 +- 没放过 → 你手狠 + +**检验问题**: + +- 你的主角有没有受够他应受的苦? +- 你的反派有没有得到他应得的报应? +- 你的悲剧够不够"悲"? + +### 步骤 3:找到"狠的瞬间" + +每个主要人物都应该有**1-3 个"狠"瞬间**——作家对他最残酷的瞬间: + +``` +成名:儿子自杀 +林冲:风雪山神庙,杀人 +马蒂尔德:发红的手 +苔丝:被处死 +闰土:叫"老爷" +王熙凤:哭向金陵 +``` + +**检验**:你的主要人物有"狠瞬间"吗? + +- 全是甜的 → 你心慈手不狠 +- 全是狠的 → 你手狠心不慈 +- **有甜有狠** → 心慈手狠 + +### 步骤 4:避免"心软的诱惑" + +**最常见的诱惑**:作家太爱人物,写到关键处"手抖"了: + +> "我舍不得她死……算了,让她活下去吧" + +**毕飞宇的解药**: + +> "作家是小说的上帝,但上帝不能滥用慈悲。" + +**检验**: + +- 你有没有"舍不得"过?→ 警惕 +- 你有没有"算了他不该这么惨"?→ 警惕 +- 你有没有"突然让他走运"?→ 警惕 + +### 步骤 5:用"心慈"写"手狠" + +**最难的技巧**——让读者感受到"作家爱他,但作家不能放过他": + +``` +莫泊桑的"发红的手": + 莫泊桑爱马蒂尔德(她美丽、虚荣、是人) + 莫泊桑写下"发红的手"(她必须付出代价) + 读者感受到的不是残忍——是诚实 + → 诚实 = 心慈 + 手狠 +``` + +**检验**:你的"狠"是不是带着"爱"? + +- 狠但带着爱 → 心慈手狠 +- 狠只是狠 → 虐待狂 +- 狠带着蔑视 → 失败 + +(/bifeiyu-mercy-ruth) + +## 触发场景 + +1. 你的人物"该受苦但你舍不得" → 你的手软了 +2. 你的悲剧"不够悲" → 你心慈但手不狠 +3. 你的人物"突然命运变好" → 你的手软了(不一定对,要看逻辑) +4. 你在写"坏人"但笔下留情 → 你可能太"心慈" +5. 你在写"主角"但不敢让他失败 → 你心慈手不狠 + +(/bifeiyu-mercy-ruth) + +## 一句话总结 + +> **"作家是小说的上帝,但上帝不能滥用慈悲"——爱你的角色,但不要放过他。** + +(/bifeiyu-mercy-ruth) + +## 与其他方法的关系 + +- 与 `character-presentation`(人物呈现)的 bifeiyu-character-fate 配套:性格碰撞出来的命运 = 作家"手狠"的依据 +- 与本 skill 的 bifeiyu-shakespeare 同源:莎士比亚化要求作家"沉默",心慈手狠是前提,见 [stance-by-logic.md](stance-by-logic.md) +- 与 `narrative-momentum`(叙事动力)的 bifeiyu-momentum 关联:势的累加 = 手狠——不能因心软去"减弱"势 +- 与 `prose-craft`(语言与修辞)的 bifeiyu-base-temp 关联:大师的温度是"冷中的热"——心慈手狠 = 冷温度下的热关怀 + +(/bifeiyu-mercy-ruth) diff --git a/framework/catalog/dsh/skills/theme-and-stance/references/stance-by-logic.md b/framework/catalog/dsh/skills/theme-and-stance/references/stance-by-logic.md new file mode 100644 index 0000000..81c4fea --- /dev/null +++ b/framework/catalog/dsh/skills/theme-and-stance/references/stance-by-logic.md @@ -0,0 +1,161 @@ +# 莎士比亚化(Shakespeare-ization):把主题翻译成环境,让人物自己走 + +> 来源单元:《小说课》(毕飞宇)bifeiyu-novel-skill/bifeiyu-shakespeare,第 6 章(结构·逻辑)。 +> 本文件管立场的植入方式:不做思想先行的"席勒化",把主题藏进环境与性格的碰撞里,让小说内部逻辑推着人物走。主题为什么必须演示见 [theme-demonstration.md](theme-demonstration.md);作家"手狠"才能让逻辑自己走,见 [mercy-ruth.md](mercy-ruth.md);边界与常见错误见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> 「思想性的传递需要作家的思想,其实更需要作家的艺术才能。在美学上,说空话有一个专业的名词,叫'席勒化',把思想性落实到艺术性上,也有一个专业名词,叫'莎士比亚化'。」 + +(/bifeiyu-shakespeare) + +林冲怎么"走"上梁山的? + +**错误的写法**(席勒化): + +- 作家想:林冲应该造反 +- 作家安排:林冲拍案而起、振臂高呼、被逼上梁山 + +**正确的写法**(莎士比亚化): + +- 白虎堂 → 野猪林 → 牢城营 → 草料场 → 雪 → 风 → 石头 → 听到阴谋 → 杀人 → 柴进指路 → 上山 + +**林冲的每一次"走"都是他自己不想"走"的**。但小说内部逻辑推动着他不得不走。 + +(/bifeiyu-shakespeare) + +## 方法核心 + +**莎士比亚化 = 让人物按小说内部逻辑自己"走"**。作家是"看不见的手",不是"指挥家"。 + +**席勒化** = 思想先行 → 安排情节。作家是"传声筒"。 + +| 维度 | 莎士比亚化 | 席勒化 | +|-----|----------|------| +| 起点 | 人物性格 + 现实环境 | 思想/主题 | +| 推力 | 小说内部逻辑 | 作家意图 | +| 人物 | 自主行动 | 被动执行 | +| 主题 | 自然浮现 | 强行表达 | +| 阅读感受 | "不得不这样" | "作家让我知道" | + +(/bifeiyu-shakespeare) + +## 书中案例 + +### 案例 1:施耐庵《水浒》林冲 + +- **雪**铺垫林冲烤火(性格是"好犯人")→ 林冲处理火(积极改造)→ 雪压塌房(被动改变) +- **风**阻止林冲关门 → 推动石头靠门 → 隔开陆谦等人 → 泄露阴谋 +- **每一步都是必然**——但林冲没想"我要造反" +- **结果**:林冲自己"走"上梁山,作家都"说不上话" + +### 案例 2:蒲松龄《促织》成名 + +- 不是"作者让成名倒霉" +- 是"迁讷的性格 + 猾黠的里胥" → 性格碰撞 → 必然命运 +- 蒲松龄只给了 4 个字"为人迁讷"——然后小说自己跑 + +### 案例 3:莫泊桑 改写版 + +- 改写版("王宝强张小芳")漏洞百出——因为它**席勒化**:想批判虚荣,安排了人物去借项链 +- 原文(路瓦赛夫妇)逻辑自洽——因为**莎士比亚化**:人物性格 + 时代背景 → 自然借项链 + +(同一作品《项链》在"心慈手狠"单元里从另一个角度出现——"发红的手"是作家的狠。角度不同,两个都保留,见 [mercy-ruth.md](mercy-ruth.md) 案例 1。) + +### 案例 4:曹雪芹《红楼梦》王熙凤 + +- 王熙凤的性格 → 决定了她会"管事" +- 管的性格 + 贾府复杂关系 → 必然形成"毒设相思局" +- 作家没有"派"她杀人——是她自己"走"到那一步 + +(同一人物王熙凤在"心慈手狠"单元里从命运重量角度出现——"哭向金陵事更哀",见 [mercy-ruth.md](mercy-ruth.md) 案例 5。) + +(以上案例均出自/bifeiyu-shakespeare) + +## 执行步骤 + +### 步骤 1:把"主题"翻译成"环境" + +错误: + +```yaml +主题:批判官僚主义 +情节:主角觉醒,揭发腐败 +→ 席勒化 +``` + +正确: + +```yaml +环境:一个具体的官僚场景(办事、推诿、签字) +人物:性格鲜明的当事人 +→ 让"官僚场景"和"人物性格"碰撞,主题自然浮现 +→ 莎士比亚化 +``` + +### 步骤 2:设计"性格 + 现实"的推力链 + +``` +人物 A 的性格 = X +人物 B 的性格 = Y +X 与 Y 碰撞 → 必然产生事件 Z +Z 引发环境 E 的变化 +E 反过来作用于 A 和 B +``` + +**关键**:每个环节都要可推导,不能跳跃。 + +### 步骤 3:检验"作家发言权" + +写完后问自己: + +> "如果我(作家)什么都不说,人物会自己走到这一步吗?" + +- 会的 → 莎士比亚化 +- 不会 → 你还在席勒化 + +### 步骤 4:检验"必然性" + +把小说里**任何一个事件**删掉,看故事: + +- [ ] 完全垮掉?→ 这个事件是必然的,留 +- [ ] 不影响?→ 这个事件是多余的,删 +- [ ] 换个别的事件也能承接?→ 你可能没找到真正必然的事件 + +林冲的雪、风、石头——**删一个故事就垮**。这就是必然性。 + +### 步骤 5:让作家"沉默" + +**终极检验**: + +> 写完之后,把所有"作家发言"删掉(解释、议论、心理分析),看读者能不能读懂。 + +- 能 → 莎士比亚化 +- 不能 → 你在替人物说话——回到席勒化 + +(/bifeiyu-shakespeare) + +## 触发场景 + +1. 你的人物"按你安排"行动 → ❌ 席勒化预警 +2. 你的情节"为了主题服务" → ❌ 思想先行 +3. 你的角色"在小说里变了"但你不知道为什么 → ✅ 莎士比亚化成功 +4. 你想表达"批判 X"但不知道怎么办 → 把 X 变成**环境/对手**,让主角去碰撞 +5. 你的人物有"觉醒"或"转变" → 必须有**环境/事件**的推动链 + +(/bifeiyu-shakespeare) + +## 一句话总结 + +> **作家越小,权力越大;作家越大,权力越小。** + +(/bifeiyu-shakespeare) + +## 与其他方法的关系 + +- 与 `show-and-omission`(展示与留白)的 bifeiyu-anti-logic 互补:莎士比亚化用逻辑,反逻辑是它的"另一面" +- 与 `character-presentation`(人物呈现)的 bifeiyu-character-fate 同源:性格即命运 = 性格 + 现实的逻辑推演 +- 与 `narrative-momentum`(叙事动力)的 bifeiyu-momentum 关联:莎士比亚化是"势"能产生的方法 +- 与本 skill 的 bifeiyu-mercy-ruth(心慈手狠)配对:作家要"手狠"才能让逻辑自己走——不能因心软去救人物,见 [mercy-ruth.md](mercy-ruth.md) + +(/bifeiyu-shakespeare) diff --git a/framework/catalog/dsh/skills/theme-and-stance/references/theme-demonstration.md b/framework/catalog/dsh/skills/theme-and-stance/references/theme-demonstration.md new file mode 100644 index 0000000..3f31c0d --- /dev/null +++ b/framework/catalog/dsh/skills/theme-and-stance/references/theme-demonstration.md @@ -0,0 +1,130 @@ +# 主题只能演示,不能说出 + +> 来源单元:《Story Engineering》(Larry Brooks)story-engineering/theme-demonstrate-not-tell,Part 4 · Implementing Theme。 +> 本文件管主题的呈现层:主题是什么、为什么不能说出、怎么演示。立场如何藏进环境与人物、从碰撞中自然浮现(防主题先行)见 [stance-by-logic.md](stance-by-logic.md);作者对人物受苦的态度见 [mercy-ruth.md](mercy-ruth.md);沉重题材用幽默立立场见 [humor-as-stance.md](humor-as-stance.md);边界与易混方法见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> "Theme is best implemented in your story when it is demonstrated by the story itself, and the characters in it, rather than when it is told by them... the difference between active voice and passive voice, almost. A demonstrated theme is active. A stated theme is passive." +> +> — Larry Brooks, *Story Engineering* (2011), Part 4 + +主题落地在你的故事里,最好的方式是故事本身和其中的人物把它**演示**出来,而不是由他们把它**说**出来……这差别几乎就像主动语态和被动语态的差别。被演示的主题是主动的。被陈述的主题是被动的。(/theme-demonstrate-not-tell,白话转述) + +## 方法核心 + +"主题"是故事对现实照亮什么。但主题不能被**说出**,只能被**演示**。读者必须自己"看出"主题,角色/作者替读者"说" = 失败。(/theme-demonstrate-not-tell) + +**核心规则**: + +- **陈述主题(Told Theme)**:角色说"我爱我的祖国" / 叙述者说"这是一个关于失去的故事" / 章节开头"寓言"——**失败** +- **演示主题(Demonstrated Theme)**:角色在关键时刻做选择,选择本身演示主题——**成功** + +**Show vs Tell 在主题上的应用**: + +- Show = 角色的**行为**演示主题(在关键决策中"做"什么) +- Tell = 角色的**台词**说主题(在对话中"讲"什么) +- 主题必须 Show,不要 Tell + +**为什么 Tell 失败**: + +- 角色一旦"说出"主题,角色就变成作者传声筒,失去主体性 +- 读者立刻出戏,因为感觉"被教" +- 主题的"由读者自己发现"乐趣消失 + +**演示主题的 3 种方法**: + +1. **决策演示**:关键场景里,角色在 A/B 中选,选什么 = 主题立场 +2. **结构演示**:故事整体结构(开头 vs 结尾,失败 vs 成功)演示主题 +3. **反讽演示**:角色"说"一套,"做"另一套,反讽 = 主题 + +(/theme-demonstrate-not-tell) + +## 跨书呼应:同一条原理的另外两种说法 + +"主题只能演示、不能说出"不止一本书这么说。毕飞宇把"说出主题"叫席勒化,把"演示主题"叫莎士比亚化(/bifeiyu-shakespeare): + +> 「思想性的传递需要作家的思想,其实更需要作家的艺术才能。在美学上,说空话有一个专业的名词,叫'席勒化',把思想性落实到艺术性上,也有一个专业名词,叫'莎士比亚化'。」 + +在他的对照表里,"主题"一栏正是两种写法的分水岭:莎士比亚化的主题**自然浮现**,席勒化的主题**强行表达**。完整对照表与操作方法(把主题翻译成环境、性格碰撞推力链、作家沉默)见 [stance-by-logic.md](stance-by-logic.md)。 + +余华讨论沉重题材时同样要求批判不沦为说教与谩骂——他给出的解法是幽默作为结构:用幽默的态度与现实建立关系,既不妥协也不对抗。见 [humor-as-stance.md](humor-as-stance.md)。 + +(/bifeiyu-shakespeare;/humor-as-structure) + +## 书中案例 + +### 案例 1:The Cider House Rules(《苹果酒屋法则》) + +- **问题**:John Irving 想"写一个关于堕胎的故事" +- **方法论的使用**:不让任何角色"谈论堕胎对不对"——通过 Homer Wells(主角)在"成为医生"和"留在孤儿院"之间的反复选择演示主题 +- **结论**:主题 = "选择 vs 强加"——通过 Homer 的选择,从不通过说教 +- **结果**:获奥斯卡最佳改编剧本 + +(/theme-demonstrate-not-tell) + +### 案例 2:The Lovely Bones(《可爱的骨头》) + +- **问题**:Alice Sebold 想"写一个关于失去与宽恕的故事" +- **方法论的使用**:不让 Susie's 天上独白"讲"宽恕——通过她看着家人如何处理悲痛、凶手如何生活来演示 +- **结论**:主题被"看"出来,不被"说"出来 +- **结果**:1000 万册 + +(/theme-demonstrate-not-tell) + +### 案例 3:反例——常见的"主题演讲" + +- **问题**:写作者写完一章,让角色在对话中说"我们这个社会..." +- **方法论的使用**:诊断 = 主题 Tell 化 +- **结论**:删掉这段对话,改成角色在关键场景做"那个社会议题"的选择 +- **结果**:改稿后不再"说教" + +(/theme-demonstrate-not-tell) + +## 执行步骤 + +1. **确认主题** + - 完成标准:1 句话说清"我的故事想照亮什么" + +2. **扫描全文:有没有 Tell?** + - 完成标准:列出 3 类"Tell"出现位置 + - 角色对话中的主题陈述 + - 叙述者/旁白的主题点明 + - 章节开头的"寓言式"开篇 + - 提示:搜"主题关键词 + 说出动词"(说/讲/道/谓/示) + +3. **改成 Show** + - 完成标准:每个 Tell 都有对应的 Show 改写 + - 方法:把"角色说"改成"角色在场景中做" + - 例:把"他说'我爱我的祖国'"改成"他在撤退时为救一个同胞兵,错过了撤离船" + +4. **增加 1-2 个"主题演示"场景** + - 完成标准:至少 1 个新场景,角色的"做"演示主题 + - 不必是大幅动作,小决策即可 + +(/theme-demonstrate-not-tell) + +## 触发场景与语言信号 + +用户会在什么情境下需要这个方法(/theme-demonstrate-not-tell): + +1. **主题植入**:"我故事主题是 X,怎么表达?" +2. **说教修复**:"我被反馈'说教味重',怎么改?" +3. **写作完成前自检**:"我主题被说出来过吗?" +4. **教学/讨论**:"主题怎么写才有艺术感?" + +语言信号: + +- "主题说教 / 主题直白 / 主题表达" +- "show don't tell / 演示 vs 告诉" +- "我的故事像在讲道理" +- "怎么表达主题" + +## 中文落地(中文适配) + +Brooks 的方法从英文小说中总结,落地中文时 Tell 信号与检索法如下(/theme-demonstrate-not-tell 源内已有中文检索法 + 中文适配补充): + +- Tell 扫描用中文动词检索:搜"主题关键词 + 说出动词"(说/讲/道/谓/示)。这是源单元自带的中文检索法。 +- 书中反例案例本就是中文语境:角色在对话中说"我们这个社会..."——这类"主题演讲"在中文小说里同样扎眼。 +- 三种演示法(决策/结构/反讽)不依赖语言特性,中文同样适用;书中的 Show 改写例子("他在撤退时为救一个同胞兵,错过了撤离船")已是中文表达。 +- 中文适配补充:中文古典小说的"陈述主题"形态特别多——说书人旁白、章首开篇词、章末总结诗、直接议论评点,改稿时都属于 Tell,按同一标准扫描(读者自己看出 vs 作者替读者说出)。判断标准不变,只是中文 Tell 的常见载体清单更长。 diff --git a/framework/catalog/dsh/skills/theme-and-stance/references/theme-stance-checklist.md b/framework/catalog/dsh/skills/theme-and-stance/references/theme-stance-checklist.md new file mode 100644 index 0000000..5163b74 --- /dev/null +++ b/framework/catalog/dsh/skills/theme-and-stance/references/theme-stance-checklist.md @@ -0,0 +1,114 @@ +# 主题与立场检查清单 + +> 汇总四个源单元的可执行检查项,按写作进程排列:写前(定主题、建碰撞)→ 写中(演示、防手软、幽默距离)→ 改稿(五项检验)。 +> 方法细节与案例见 references/ 各文件。 + +## 一、写前:定主题与建碰撞 + +**1. 主题确认**(/theme-demonstrate-not-tell): + +- [ ] 能用 1 句话说清"我的故事想照亮什么" +- [ ] 这句话具体到"关于 X 中的 Y",不是"关于人性""关于爱"这类模糊哲学 + +**2. 把主题翻译成环境**(/bifeiyu-shakespeare): + +- [ ] 没有写成"主题:批判 X → 情节:主角觉醒揭发 X"(这是席勒化) +- [ ] 写成了:环境 = 一个具体的 X 场景(如官僚场景:办事、推诿、签字);人物 = 性格鲜明的当事人 +- [ ] 想批判 X,就把 X 变成环境/对手,让主角去碰撞,主题自然浮现 + +**3. 设计推力链**(/bifeiyu-shakespeare): + +- [ ] 人物 A 的性格 = X,人物 B 的性格 = Y +- [ ] X 与 Y 碰撞 → 必然产生事件 Z +- [ ] Z 引发环境 E 的变化,E 反过来作用于 A 和 B +- [ ] 每个环节都可推导,没有跳跃 + +## 二、写中:演示主题、防手软、选幽默距离 + +**4. 主题用"做"演示,不用"说"**(/theme-demonstrate-not-tell): + +- [ ] 关键场景里让人物在 A/B 之间选,选什么 = 主题立场(决策演示) +- [ ] 整体结构(开头 vs 结尾,失败 vs 成功)能对照出主题(结构演示) +- [ ] 若用人物说一套做一套,反讽必须清晰,读者看得出来(反讽演示) +- [ ] 至少 1-2 个小决策场景,角色的"做"演示主题(不必大幅动作) + +**5. 防手软自查**(/bifeiyu-mercy-ruth): + +- [ ] 我写这个人物之前确认过"我爱他"(不爱/蔑视的人物删掉或改写) +- [ ] 写到关键处没有出现"我舍不得她死……算了,让她活下去吧" +- [ ] 没有"算了他不该这么惨" +- [ ] 没有"突然让他走运" +- [ ] 出现以上任何一个 → 回到性格 + 逻辑,把该给的代价给足("作家是小说的上帝,但上帝不能滥用慈悲") + +**6. 沉重题材选幽默距离**(/humor-as-structure): + +- [ ] 已明确题材的沉重点:涉及哪些痛苦/压迫/荒诞 +- [ ] 已判断直接写会变成什么:控诉?苦情?谩骂? +- [ ] 已选定幽默距离:近距(人物在苦难中自嘲,余华式)/ 中距(叙述者冷幽默,卡夫卡式)/ 远距(引入荒诞元素制造间离,布尔加科夫式,撒旦访问莫斯科) +- [ ] 让荒诞自行呈现:不直接批判,写荒诞细节(翻箱倒柜找文件、电话接通后无数声音、永远找不到的负责人;让人物在荒诞场景中一本正经地行事) +- [ ] 全文至少 3 处"让人发笑但笑后不安"的细节 +- [ ] 笑的对象是环境/制度,不是人物;人物在苦难中仍然有尊严、有逻辑、有笑声 +- [ ] 读者对人物是共情而非俯视 + +## 三、改稿:五项检验 + +**7. Tell 扫描**(/theme-demonstrate-not-tell): + +- [ ] 搜"主题关键词 + 说出动词"(说/讲/道/谓/示) +- [ ] 标出三类 Tell 位置:角色对话中的主题陈述;叙述者/旁白的主题点明;章节开头的"寓言式"开篇 +- [ ] 每个 Tell 都有对应的 Show 改写:把"角色说"改成"角色在场景中做"(例:把"他说'我爱我的祖国'"改成"他在撤退时为救一个同胞兵,错过了撤离船") +- [ ] 删掉 Tell 后补上了 Show(只删不补 = 没有主题) + +**8. 作家发言权检验**(/bifeiyu-shakespeare): + +- [ ] 问自己:"如果我(作家)什么都不说,人物会自己走到这一步吗?" +- [ ] 会的 → 莎士比亚化;不会 → 还在席勒化 + +**9. 必然性检验**(/bifeiyu-shakespeare): + +把小说里任何一个事件删掉,看故事: + +- [ ] 完全垮掉?→ 这个事件是必然的,留 +- [ ] 不影响?→ 这个事件是多余的,删 +- [ ] 换个别的事件也能承接?→ 可能没找到真正必然的事件(参照:林冲的雪、风、石头——删一个故事就垮) + +**10. 作家沉默终极检验**(/bifeiyu-shakespeare): + +- [ ] 把所有"作家发言"删掉(解释、议论、心理分析),读者还能读懂 +- [ ] 能 → 莎士比亚化;不能 → 在替人物说话,回到席勒化 + +**11. 手狠检验**(/bifeiyu-mercy-ruth): + +- [ ] 主角受够他应受的苦了吗? +- [ ] 反派得到他应得的报应了吗? +- [ ] 悲剧够不够"悲"? +- [ ] 每个主要人物有 1-3 个"狠瞬间"(参照:成名儿子自杀;林冲风雪山神庙杀人;马蒂尔德发红的手;苔丝被处死;闰土叫"老爷";王熙凤哭向金陵) +- [ ] 狠的成分检验:狠但带着爱 → 心慈手狠;狠只是狠 → 虐待狂;狠带着蔑视 → 失败 +- [ ] 有甜有狠(全是甜 = 心慈手不狠;全是狠 = 手狠心不慈) + +**12. 幽默结构检验**(/humor-as-structure): + +- [ ] 幽默是贯穿全文的态度,还是偶尔的俏皮话?是俏皮话就回到第 6 步重选距离,让幽默成为整体结构 +- [ ] 幽默段落和沉重段落交替:没有全程搞笑,也没有全程压抑 +- [ ] 幽默的"度"控制得恰如其分:不过度也不不足 +- [ ] 没有让读者感到作者在嘲笑人物(幽默变嘲笑 = 失败) +- [ ] 幽默没有消解批判力量(读者不会觉得"这也没什么大不了") + +## 四、快速排错表 + +| 症状 | 诊断 | 处方 | 来源 | +|------|------|------|------| +| 被反馈"说教味重" | 主题 Tell 化 | Tell 扫描,改成关键场景里的选择与行动 | /theme-demonstrate-not-tell | +| 人物"按你安排"行动 | 席勒化预警 | 把主题翻译成环境,让性格碰撞 | /bifeiyu-shakespeare | +| 情节"为了主题服务" | 思想先行 | 把思想藏进环境 | /bifeiyu-shakespeare | +| 想"批判 X"但不知怎么办 | 主题没有环境化 | 把 X 变成环境/对手,让主角去碰撞 | /bifeiyu-shakespeare | +| 人物"觉醒"很突兀 | 缺推动链 | 觉醒前补"压垮骆驼的最后一根稻草"——具体的、可推导的 | /bifeiyu-shakespeare | +| 该受苦但你舍不得 | 手软了 | 手狠检验;让人物承担他应承担的 | /bifeiyu-mercy-ruth | +| 悲剧"不够悲" | 心慈但手不狠 | 找到并写下"狠瞬间" | /bifeiyu-mercy-ruth | +| 人物命运突然变好 | 手软的痕迹(先看逻辑) | 命运不可逆 | /bifeiyu-mercy-ruth | +| 写"坏人"笔下留情 | 太心慈 | 检验"爱不爱他",爱就给足报应 | /bifeiyu-mercy-ruth | +| 主角不敢让他失败 | 心慈手不狠 | 主角的命运必须有重量 | /bifeiyu-mercy-ruth | +| 沉重题材写得压抑、愤怒 | 在与现实对抗(或妥协) | 选幽默距离,让荒诞自行呈现 | /humor-as-structure | +| 批判变成说教或谩骂 | 没有距离 | 远距幽默(引入荒诞元素制造间离) | /humor-as-structure | +| 被反馈"太沉重了""读着压抑" | 全程无轻松 | 幽默段落与沉重段落交替 | /humor-as-structure | +| 读者感到作者在嘲笑人物 | 幽默变嘲笑 | 笑的对象换成环境/制度,保住人物尊严 | /humor-as-structure | diff --git a/framework/catalog/generate_skill_projections.py b/framework/catalog/generate_skill_projections.py new file mode 100644 index 0000000..69661bf --- /dev/null +++ b/framework/catalog/generate_skill_projections.py @@ -0,0 +1,137 @@ +#!/usr/bin/env python3 +"""从 Muse manifest 生成 Pi/DSH 可发现的扁平 Skill 投影。""" + +from __future__ import annotations + +import hashlib +import json +import os +import re +import shutil +from pathlib import Path +from urllib.parse import unquote + +ROOT = next( + parent + for parent in (Path(__file__).resolve().parent, *Path(__file__).resolve().parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +MANIFEST = ROOT / "muse" / "lifecycle" / "quality" / "harness" / "manifests" / "skills.json" +CATALOG_ROOT = ROOT / "framework" / "catalog" +TARGETS = ("dsh", "pi") +_MARKDOWN_LINK = re.compile(r"\(([^)\s]+)") + + +def _sha256(text: str) -> str: + return "sha256:" + hashlib.sha256(text.encode("utf-8")).hexdigest() + + +def _rewrite_projected_reference_links( + text: str, + source_file: Path, + projected_file: Path, + source_to_projected: dict[Path, Path], +) -> str: + """把跨 Skill 的源相对链接改到扁平投影,保留源合同正文不变。""" + + def replace(match: re.Match[str]) -> str: + raw_target = match.group(1) + target, separator, fragment = raw_target.partition("#") + if not target or target.startswith(("#", "http://", "https://", "mailto:", "/")): + return match.group(0) + resolved_source = (source_file.parent / unquote(target)).resolve() + resolved_projected = source_to_projected.get(resolved_source) + if resolved_projected is None: + return match.group(0) + relative = Path( + os.path.relpath(resolved_projected, projected_file.parent) + ).as_posix() + return f"({relative}{separator}{fragment if separator else ''}" + + return _MARKDOWN_LINK.sub(replace, text) + + +def generate() -> dict[str, object]: + manifest = json.loads(MANIFEST.read_text(encoding="utf-8")) + entries = [ + entry for entry in manifest["skills"] if entry.get("invocation") == "model_routed" + ] + names = {entry["name"] for entry in entries} + source_to_projected: dict[str, dict[Path, Path]] = { + target: {} for target in TARGETS + } + for entry in entries: + references = (ROOT / entry["skill_path"]).parent / "references" + if not references.is_dir(): + continue + for source_file in references.rglob("*"): + if source_file.is_file(): + for target in TARGETS: + projected_file = ( + CATALOG_ROOT + / target + / "skills" + / entry["name"] + / "references" + / source_file.relative_to(references) + ) + source_to_projected[target][source_file.resolve()] = projected_file + catalog: dict[str, object] = { + "schemaVersion": "framework-skill-catalog-v1", + "sourceManifest": MANIFEST.relative_to(ROOT).as_posix(), + "invocation": "model_routed", + "skills": {}, + } + for entry in sorted(entries, key=lambda item: item["name"]): + name = entry["name"] + source = ROOT / entry["skill_path"] + if not source.is_file(): + raise FileNotFoundError(f"Skill 源不存在: {entry['skill_path']}") + text = source.read_text(encoding="utf-8") + digest = _sha256(text) + for target in TARGETS: + destination_dir = CATALOG_ROOT / target / "skills" / name + if destination_dir.exists(): + shutil.rmtree(destination_dir) + destination_dir.mkdir(parents=True, exist_ok=True) + (destination_dir / "SKILL.md").write_text(text, encoding="utf-8") + references = source.parent / "references" + if references.is_dir(): + shutil.copytree(references, destination_dir / "references") + catalog["skills"][name] = { + "source": entry["skill_path"], + "sha256": digest, + "pi": f"framework/catalog/pi/skills/{name}/SKILL.md", + "dsh": f"framework/catalog/dsh/skills/{name}/SKILL.md", + } + + for target in TARGETS: + root = CATALOG_ROOT / target / "skills" + for skill_file in root.glob("*/SKILL.md"): + if skill_file.parent.name not in names: + skill_file.unlink() + try: + skill_file.parent.rmdir() + except OSError: + pass + + for target in TARGETS: + for source_file, projected_file in source_to_projected[target].items(): + if projected_file.suffix.lower() != ".md": + continue + text = source_file.read_text(encoding="utf-8") + rewritten = _rewrite_projected_reference_links( + text, source_file, projected_file, source_to_projected[target] + ) + projected_file.write_text(rewritten, encoding="utf-8") + + (CATALOG_ROOT / "catalog.json").write_text( + json.dumps(catalog, ensure_ascii=False, indent=2, sort_keys=True) + "\n", + encoding="utf-8", + ) + return {"count": len(entries), "targets": list(TARGETS)} + + +if __name__ == "__main__": + result = generate() + print(json.dumps(result, ensure_ascii=False)) diff --git a/framework/catalog/pi/skills/character-design/SKILL.md b/framework/catalog/pi/skills/character-design/SKILL.md new file mode 100644 index 0000000..95e44dd --- /dev/null +++ b/framework/catalog/pi/skills/character-design/SKILL.md @@ -0,0 +1,102 @@ +--- +name: character-design +description: | + 小说写作的人物设计方法:用 7 变量全维度建角色,用表层/内层/深层三层信息让角色立体, + 用内在恶魔给角色驱动力和角色弧,用一句话测试给人物选扁平/圆形形态,把人物站在叙事原型上做反转。 + 激活场景:创建新角色(包括"AI 协作建角色,给我一份清单")、角色库管理(很多角色要系统化区分)、 + 角色不鲜明/脸谱化/一维、角色感觉飘或假、角色工具人没驱动力没弧、读者不关心主角、 + 两个角色撞型、群像分不清、配角和主角怎么分配深度、人物太单薄或太符号化、 + 想用原型/神话母题但不想俗套、网文主角类型设计、历史人物重写、主题象征想用但用力过猛。 + 关键 trigger:"角色设计 / 角色构建 / 角色要素 / character profile / 角色 sheet / 角色清单 / 角色怎么写 / + 角色背景 / 角色目标 / 角色动机 / 7 变量 / 角色旋钮 / 角色维度 / + 立体 / 角色深度 / 角色层次 / 表层 / 内层 / 深层 / 3 维角色 / 一维 / 主角是 1 维 / 怎么让角色活 / + 扁平 / 圆形 / flat / round / 一句话概括 / 人物太单薄 / 如何让人物丰满 / + 内在恶魔 / inner demon / 内在冲突 / 角色弧 / 工具人 / 角色是搬运工 / 没有驱动力 / 没有灵魂 / + 为什么读者不关心我的主角 / 原型 / archetype / 刻板印象 / stereotype / 人物塑造 / 主题象征 / symbol / + 中国小说原型 / 本土原型 / 东方母题 / father horst / 墙不只是墙 / 象征不必是钹 / + 如何用原型又不套路 / 用原型别让原型用你"。 + 不适用于:对真实人物的全面评价(道德问题,不是方法问题);无人物的纯信息文本; + 后现代解构作品故意反原型、反母题时(原型定位合法缺席)。 + 与 character-presentation 交接:7 变量/弧线/扁圆/原型归本 Skill;定型后的登场细节、关系网、 + 反常瞬间呈现归 character-presentation。 + 与 dialogue-craft / narration-pov 交接:正文对话声音与视角执行归后两者,本 Skill 不写对话课。 +--- + +# 人物设计 + +人物设计分五个动作:**建**(7 变量全维度配置)、**立体**(三层信息造维度)、**驱动**(内在恶魔造引擎)、**定形**(扁平/圆形选形态)、**打底**(原型定位做反转)。《Story Engineering》三个单元管建/立体/驱动,福斯特管定形,克拉克管打底。方法细节、案例、引文全部在 references 里,这里只给一句话和指针。 + +## 方法索引 + +按创作动作组织,不按书组织。 + +### 建:全维度配置角色 + +- 角色不是一个形容词、一个职业,是 7 个可独立调节的变量 → references/seven-variables.md +- 前 6 个变量是输入,行为是输出兼测试:前 6 一致则行为一致,前 6 矛盾则行为出 bug → references/seven-variables.md +- 每个变量拨 1-10 档,千万级组合不重样;群像撞型就逐项对比、把极端值推开 → references/seven-variables.md + +### 立体:三层信息让角色活起来 + +- 表层(面具)/ 内层(脱下面具的自己)/ 深层(连自己都不知道的核心),多数角色只被写出表层 → references/three-dimensions.md +- 戏剧来自错位:三层互相矛盾,关键场景里让错位暴露或转移;三层完全一致就是一维 → references/three-dimensions.md +- 深层就是内在恶魔——角色自己都未必意识到的驱动力,两本书在说同一件事 → references/three-dimensions.md、references/inner-demon.md + +### 驱动:内在恶魔是引擎 + +- 外部冲突 + 内在恶魔必须同时运作;只有外部冲突,角色是剧情的运输车辆,不是有意义的参与者 → references/inner-demon.md +- 恶魔是根本性的、有早期根源、是角色弧的引擎、是读者共鸣的来源 → references/inner-demon.md +- 共振检查:外部任务必须激活那个怕;内外平行不触碰,不是故事 → references/inner-demon.md +- 角色弧 = 故事结束时他对恶魔做了什么;克服/接受/失败/部分克服都行,但必须明确 → references/inner-demon.md + +### 定形:扁平还是圆形 + +- 一句话测试:说得清的大概率扁平,说不清的大概率圆形 → references/flat-vs-round.md +- 圆形公式 = 出人意料 × 仍然可信,缺一即伪圆形 → references/flat-vs-round.md +- 扁平不是缺陷:喜剧/群像优先扁平,严肃/悲剧必须圆形 → references/flat-vs-round.md +- 高级技巧:扁平人物在紧急时刻骤然鼓胀成圆形,之后又回到扁平(贝特伦夫人案例) → references/flat-vs-round.md + +### 打底:原型与反转 + +- 用原型,别让原型用你:站在母题上,在读者期待的位置反转、挫败、变形 → references/archetype-reversal.md +- 11 个西方叙事原型供参考;中文小说优先从章回、戏曲、神话、文言笔记、现代文学提取本土母题(中文适配) → references/archetype-reversal.md +- Father Horst 两条:墙不只是墙(显著元素承载象征),象征不必是钹(轻敲不宣告) → references/archetype-reversal.md +- 原型 ≠ 刻板印象:原型是可反转、有内部矛盾的母题,刻板印象是固化标签 → references/archetype-reversal.md + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|---------| +| references/seven-variables.md | 7 变量全表、输入输出关系、1-10 档组合、建/诊断/对比三用法、懦弱士兵完整表案例、执行步骤、失败模式与盲点 | +| references/three-dimensions.md | 三层信息(表层/内层/深层)、错位与戏剧、3 维 vs 1 维、深层=恶魔合并点、Walter White/Don Draper 案例、执行步骤、失败模式与盲点 | +| references/inner-demon.md | 两层冲突、恶魔四特征、操作问法、共振检查、弧的引擎与四种结局、完美英雄反例与《末路狂花》案例、执行步骤、失败模式与盲点 | +| references/flat-vs-round.md | 一句话测试、圆形公式、扁平功能分工、悲剧必须圆形、动态切换(圆盘鼓胀)、贝特伦夫人/摩尔·弗兰德斯/狄更斯案例、写作外应用场景、与 visible-private-life 的区分(形式层 vs 本体论层)、失败模式与盲点 | +| references/archetype-reversal.md | 11 个叙事原型、反转规则、Father Horst 两条、越南退伍兵与盖茨比绿光案例、本土原型库(中文适配)、失败模式与盲点 | +| references/_coverage.md | 五个源单元的覆盖对照表 | + +## 脚本 + +| 脚本 | 用途 | +|------|------| +| references/character-worksheet.md | 建角色台账:7 变量 → 3 维度 → 内在恶魔与共振 → 角色弧 → 定形 → 原型打底,一份填完,每节有过关线 | +| references/character-diagnosis.md | 成型角色按症状诊断:不鲜明/工具人/撞型/没弧/伪圆形/刻板印象/象征讲课,症状 → 检查 → 处方 | + +## 红线 + +- 只给当前创作阶段的建议,不越权改设定主权、不绕过检测链、不复制粘贴其它 Skill 的 owner 定义。 +- 无用户明确授权不得替用户定稿或提交 Git。 + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/pi/skills/character-design/references/_coverage.md b/framework/catalog/pi/skills/character-design/references/_coverage.md new file mode 100644 index 0000000..3be2794 --- /dev/null +++ b/framework/catalog/pi/skills/character-design/references/_coverage.md @@ -0,0 +1,11 @@ +# character-design 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| aspects-of-the-novel/flat-vs-round-character | references/flat-vs-round.md | +| story-engineering/character-inner-demon | references/inner-demon.md | +| story-engineering/character-seven-variables | references/seven-variables.md | +| story-engineering/character-three-dimensions | references/three-dimensions.md | +| writing-tools-clark/archetype-toolkit | references/archetype-reversal.md | diff --git a/framework/catalog/pi/skills/character-design/references/archetype-reversal.md b/framework/catalog/pi/skills/character-design/references/archetype-reversal.md new file mode 100644 index 0000000..faba094 --- /dev/null +++ b/framework/catalog/pi/skills/character-design/references/archetype-reversal.md @@ -0,0 +1,141 @@ +# 打底:原型工具箱——站在叙事原型上做反转 + +来源:(Roy Peter Clark,*Writing Tools: 55 Essential Strategies for Every Writer*,Tool 38 · Prefer archetypes to stereotypes) + +## 原文摘录 + +> Good writers strive for originality, and they can achieve it by standing on a foundation of narrative +> archetypes, a set of story expectations that can be manipulated, frustrated, or fulfilled in novel +> ways. Examples include: the journey there and back, winning the prize, winning or losing the loved +> one, loss and restoration, the blessing becomes the curse, overcoming obstacles, the wasteland +> restored, rising from the ashes, the ugly duckling, the emperor has no clothes, descent into the underworld. +> +> — Roy Peter Clark, *Writing Tools* (Tool 38) + +() + +## 方法规则 + +### 11 个西方叙事原型 + +Clark 提出 11 个西方叙事原型作为"工具箱": + +1. 去过-回来(Journey There and Back) +2. 赢得奖赏(Winning the Prize) +3. 赢得/失去爱人(Winning or Losing the Loved One) +4. 丧失与恢复(Loss and Restoration) +5. 祝福成诅咒(The Blessing Becomes the Curse) +6. 克服障碍(Overcoming Obstacles) +7. 荒原恢复(The Wasteland Restored) +8. 灰烬重生(Rising from the Ashes) +9. 丑小鸭(The Ugly Duckling) +10. 皇帝的新衣(The Emperor Has No Clothes) +11. 深入冥界(Descent into the Underworld) + +() + +### 核心规则:用原型,但不被原型用 + +**Use archetypes. Don't let them use you.**(用原型,但不被原型用。)站在这些"基础结构"上做反转、挫败、变形,让读者**既感到熟悉又感到惊讶**。() + +### Father Horst 的两条原则 + +Clark 配套 Father Horst 的两条原则: + +1. **"墙在故事中往往不只是墙"**——显著元素往往有象征意义。 +2. **"象征不必是钹"(A symbol need not be a cymbal)**——微妙为好,用细节的轻敲,不用宣言的重击。 + +这是**反转 + 微妙**的复合框架。() + +### 原型 ≠ 刻板印象,原型 ≠ 主题 + +- **与"刻板印象"的区别**:原型是"可反转的母题",刻板印象是"固化的标签"。原型有内部矛盾,刻板印象没有。 +- **与"主题"的区别**:原型是"叙事模式"(how),主题是"思想内容"(what)。《王子复仇记》是"深入冥界"原型 + "为父报仇"主题。 +- **术语澄清**:本单元的"原型"指克拉克的叙事母题原型;与 references/three-dimensions.md 易混节提到的 Christopher Vogler 12 角色原型、references/flat-vs-round.md 易混节提到的荣格"集体无意识"原型(英雄/智者/阴影)都不是一回事——后两者是人物类型分类,本单元是故事母题基础。 + +() + +## 案例全文 + +### 案例 1:John Pilger 越南退伍军人抗议(William Wyman) + +- **问题**:如何用原型处理"战争反思"主题? +- **方法论的使用**:19 岁双截肢退伍军人把奖章撕下扔到国会台阶——站在"去过-回来"原型上做反转:"去过战场 - 回来 - 不再相信国家赋予的意义"。"祝福变诅咒"原型的当代实例。 +- **结论**:原型的力量不在于"复制"而在于"反转"——把原型推到极致,然后让读者看见其内部裂缝。 +- **结果**:Clark 用来证"站在原型上做反转"的方法论。 + +() + +### 案例 2:Clark 引用 Fitzgerald《了不起的盖茨比》"绿光" + +- **问题**:西方原型(美国梦的破灭)如何在中国/东方语境下迁移? +- **方法论的使用**:Gatsby 的"绿光"原型 = "荒原恢复"+"灰烬重生"的扭曲版本——盖茨比相信"过去可以重造",但绿光最终是"不可挽回"。Clark 用此例说明:**站在原型上做反转,让原型从"希望"变成"反讽"**。 +- **结论**:原型 + 反转 = 西方文学的核心结构。 +- **结果**:成为了"用原型"的金标准案例——但是这个例子是西方文学,中文小说需要本地化原型库。 + +() + +## 操作步骤 + +1. **从 11 个原型中选 1-2 个作为基础** + - 完成标准:选定 1-2 个原型作为人物 / 主题的基础。 + - 判停条件:不强制选;但若不选,人物容易"无类型感"。中文小说可从 11 西方原型中选用,也可本地化(见下方中文适配节)。 +2. **找出"反转点"** + - 在原型流程中,标出"读者期待"的位置,然后让叙事在那个位置**反转 / 挫败 / 变形**。 + - 完成标准:反转点至少 1 个,且与人物 / 主题的核心冲突直接相关。 + - 判停条件:反转必须有意义;不是为了"反"而反。 +3. **Father Horst 检验** + - 检验 1:墙 / 树 / 水等显著元素是否"不只是物"?若有象征意义,保留。 + - 检验 2:象征是否"敲锣打鼓"?若是,改用"轻敲"——细节、动作、对话暗示,而不是作者直接宣告。 + - 完成标准:每个显著元素(墙、树、礼物、伤口)有 1 个轻敲的象征表达,无"宣告"段落。 + +() + +## 边界与失败模式 + +### 不要在以下情况使用 + +- **后现代解构作品**——故意"反原型 / 反母题",不需要工具箱。 +- **完全无类型的实验文本**——拒绝任何"模式"的作品。 +- **刻意反类型的反讽作品**——站在"反原型"上,本身也是一种原型。 +- **完全西化的中文小说**——中文小说更适合用本土原型(见下方中文适配节)。 + +() + +### 作者在书中警告的失败模式 + +- **"墙上挂墙"过度象征**:失败模式是每个元素都被作者宣告"这是象征"。信号:读者读完后觉得"作者在讲课"。机制:把 Father Horst 原则 1 推到极端,忽略原则 2(微妙)。预警:每段都有"作者旁白"或"主题宣告"。 +- **"刻板印象"代替原型**:失败模式是"亚裔女性就温顺 / 退伍军人就暴力"等固定搭配。信号:人物被简化成标签。机制:把"原型"误用为"刻板印象",失去"反转"空间。预警:人物没有内部矛盾。 +- **"反转无意义"**:失败模式是"为反而反"——原型走到一半突然反转,但反转与主题无关。信号:读者觉得"莫名其妙"。机制:作者想要"原创"但没找到真正属于自己的反转。预警:反转点无法用一句话解释"为什么这里反转"。 + +() + +## 中文适配:本土原型库(源单元本地化核心,全量保留) + +**Clark 的 11 个原型是西方的**。中文小说作者需要**本地化补全**: + +- **章回原型**:忠义两难(《水浒》)、冤冤相报(《三国》)、因果轮回(《西游记》)、才子佳人(《红楼》)。 +- **戏曲原型**:生旦净末丑的角色配置(主角、配角、反派、师爷、媒婆等);折子戏的"高潮单折"(类似西方"incident")。 +- **神话原型**:嫦娥奔月 / 牛郎织女 / 愚公移山 / 哪吒闹海 / 八仙过海 / 白蛇传——这些是中国小说的母题来源。 +- **文言笔记**:《聊斋》的人狐之恋 / 《阅微》的因果报应——是短篇小说的原型库。 +- **现代汉语新文学**:鲁迅的"看客"、张爱玲的"倾城之恋"、莫言的"丰乳肥臀"母题——百年新文学已有自己的"现代化原型"。 + +**这一条是 cangjie 蒸馏的本地化核心**——Clark 的西方原型不能直接套用,必须**从中国 / 东亚叙事传统中提取本土原型**,并配 Father Horst 的"微妙"原则。 + +本地化提示(源单元审计注记保留):Clark 的 11 个原型仅作"参考",中文写作者应优先从章回、戏曲、神话、文言笔记中提取本土原型。 + +() + +## 中文落地 + +- 网文主角类型设计(战神归来、灰烬重生、丑小鸭逆袭)是原型反转最直接的用武之地:读者对母题预期极熟,"又是这个"的抱怨就是没做反转;反转点必须挂在全书核心冲突上。 +- 历史人物重写(如诸葛亮、林黛玉):先问"他/她站在哪个原型上",再决定在哪里反转。 +- 中文诗学"象外之象""不着一字,尽得风流"的传统与"象征不必是钹"天然同路;落地方法就是操作步骤里的 Father Horst 检验:显著元素各给一个细节轻敲,删掉一切宣告段落。 + +## 与其他方法的关系 + +- **mosaic-of-detail**(综合 skill character-presentation):那个是"用具体物显示人物"(细节拼贴),这个是"用原型定位人物"(母题基础)。前者是物品语言,后者是叙事母题。 +- **back-off-show-off**(综合 skill prose-craft):那个是"修辞密度校准"(反比主题),这个是"原型选择 + 微妙处理"(主题母题层)。前者管"如何说",后者管"说什么"。 +- **story-engine**(综合 skill concept-design):那个是"贯穿全书的核心问题"(问题),这个是"贯穿叙事的母题"(意象)。前者是叙事骨架,后者是叙事意象。 +- **voice-equalizer**(综合 skill prose-craft):母题的语言表达。 +- **本包内部**:原型反转通常落在人物弧与恶魔上——反转点常是角色深层(恶魔)浮出水面的位置 → references/inner-demon.md、references/three-dimensions.md;圆形人物的"出人意料"也常由原型反转给出 → references/flat-vs-round.md diff --git a/framework/catalog/pi/skills/character-design/references/character-diagnosis.md b/framework/catalog/pi/skills/character-design/references/character-diagnosis.md new file mode 100644 index 0000000..daff234 --- /dev/null +++ b/framework/catalog/pi/skills/character-design/references/character-diagnosis.md @@ -0,0 +1,96 @@ +# 角色诊断流程(角色已成型) + +用法:角色已经在稿子里(写了一半或写完了),按症状查。每条症状:检查 → 判定 → 处方。处方指向本包 references/ 落点;方法细节、案例见落点文件。 + +--- + +## 症状 1:角色不鲜明、一维、脸谱化 + +检查: + +1. 用一句话概括这个角色,说得清吗? +2. 表层/内层/深层各有没有具体内容? +3. 三层之间有没有矛盾? + +判定:一句话说清 + 无错位 = 一维(扁平)。 + +处方: + +- 先问扁平是不是刻意的:喜剧/群像的扁平合法,严肃/悲剧必须圆形 → references/flat-vs-round.md +- 要补立体:补内层和深层,造错位 → references/three-dimensions.md +- 检查世界观(变量 5)是否写成了哲学标签,改成他具体信什么 → references/seven-variables.md + +## 症状 2:工具人、没驱动力、读者不关心主角 + +检查: + +1. 恶魔是不是 0?(只有打怪任务,没有"他为什么做不到") +2. 恶魔是不是太社会议题("害怕贫穷")或太流行病("他抑郁")? +3. 外部任务激活恶魔吗?共振一句话写得出吗? + +判定:恶魔 = 0 或内外平行,就是"剧情的运输车辆,不是有意义的参与者",拒稿常见原因。 + +处方: + +- 补恶魔:问"他最怕什么",追到童年/早期根源 → references/inner-demon.md +- 不共振:改外部任务或改恶魔,让任务正好触碰那个怕 → references/inner-demon.md +- 完美英雄反例为戒:外部冲突再强,恶魔 = 0 读者也不关心 → references/inner-demon.md + +## 症状 3:两个角色撞型、群像分不清 + +检查:两个角色逐项对比 7 变量,列出相同的项。 + +处方: + +- 把其中一方的 2-3 个变量推到极端(如 Backstory 1 vs 9、Goal 5 vs 9)→ references/seven-variables.md +- 群像按 1+7 多份填表逐个处理,不批量 → references/seven-variables.md + +## 症状 4:没弧、没成长 + +检查: + +1. 故事开始和结束时的角色差异,列得出 3 个吗? +2. 角色有没有要克服的恶魔? + +处方: + +- 没差异 = 弧缺失,用恶魔找他要克服什么 → references/inner-demon.md +- 弧的结局:克服/接受/失败(悲剧)/部分克服都行,但必须明确 → references/inner-demon.md +- 深层浮出水面的场景安排成关键节拍 → references/three-dimensions.md + +## 症状 5:伪圆形——反转了但不可信 + +检查:角色的"出人意料"之举,事后能让读者觉得"对,这才是他"吗? + +判定:只意外不可信 = 硬充圆形("暗黑角色"强行反转的常见病);只可信不意外 = 扁平装圆。 + +处方: + +- 给反转行为补三层依据(深层动机),让意外落到可信上 → references/three-dimensions.md +- 补不出来就退回扁平形态,放到喜剧/群像位置 → references/flat-vs-round.md + +## 症状 6:人物刻板印象、标签化 + +检查:人物有内部矛盾吗?他的行为可以被反转吗? + +判定:无矛盾、无反转空间 = 刻板印象,不是原型("亚裔女性就温顺/退伍军人就暴力"这类固定搭配)。 + +处方: + +- 把他放到一个原型上(西方 11 原型或本土母题),在读者期待的位置留反转点 → references/archetype-reversal.md + +## 症状 7:象征讲课、主题宣告 + +检查:显著元素(墙、树、伤口、礼物)是不是靠作者旁白宣告"这是象征"?读者读完觉得"作者在讲课"? + +处方: + +- 宣告改轻敲:用细节、动作、对话暗示;每个显著元素一个轻敲,删掉宣告段落 → references/archetype-reversal.md(Father Horst 检验) + +## 交稿前总检 + +- [ ] 一句话测试做过,形态与主题匹配(严肃/悲剧必须圆形) +- [ ] 主角恶魔在场,内外共振一句话写得出来 +- [ ] 弧的结局明确(克服/接受/失败/部分克服四选一) +- [ ] 群像逐项对比过变量,无撞型 +- [ ] 无"这是象征"式宣告段落,无刻板印象式人物 diff --git a/framework/catalog/pi/skills/character-design/references/character-worksheet.md b/framework/catalog/pi/skills/character-design/references/character-worksheet.md new file mode 100644 index 0000000..19ab2b1 --- /dev/null +++ b/framework/catalog/pi/skills/character-design/references/character-worksheet.md @@ -0,0 +1,91 @@ +# 建角色台账 + +用法:新角色从 0 到 7 顺着填。每节有"过关线",达标进下一节,不达标按标注回退。判断标准全部来自本包 references/ 各文件,这里只是填写骨架;方法细节与案例见各节标注的落点。 + +--- + +## 0. 角色定位 + +角色一句话定位:____ +在故事中的分量:□ 主角 □ 反派 □ 重要配角 □ 小配角 + +- 小配角:填完第 1 节(只填 1-2 个变量)+ 第 5 节定形即可收工,不必全填。 +- 群像:每个主角各填一份台账,不批量处理。 + +## 1. 7 变量(→ references/seven-variables.md) + +| 变量 | 档位(1-10) | 具体内容(3-5 句,不抄变量名) | +|------|------|------| +| 1 表层人格 | | | +| 2 背景故事 | | | +| 3 角色弧 | | | +| 4 内在恶魔 | | | +| 5 世界观 | | | +| 6 目标与动机 | | | +| 7 决策/行动/行为 | | | + +- 至少 2-3 个变量取极端(1-3 或 8-10),全在 4-5 档 = 没特色 □ +- 一致性:第 7 项行为能从前 6 项推出 □;矛盾时改前 6 中的一项,不直接改行为 □ +- 世界观写的是他具体信什么,不是哲学标签 □ + +过关线:7 项都有具体内容,行为与前 6 一致。小配角到此为止。 + +## 2. 3 维度(→ references/three-dimensions.md) + +表层(别人眼中的他):____ +内层(独处时的他):____ +深层(连他自己都不知道的驱动):____ + +- 没把表层复制进内层 □ +- 深层不是修辞("她是个追寻自由的人"不通过),也不是内层的延伸 □ +- 错位清单:表层 vs 内层的矛盾____;内层 vs 深层的矛盾____ +- 3 维都会露馅的关键场景(≥2 个):在____场景露馅;在____场景深层浮出水面 + +过关线:3 维各有具体内容且彼此矛盾。3 维一样 = 角色还在 1 维,回第 1 节补变量。 + +## 3. 内在恶魔与共振(→ references/inner-demon.md) + +- 外部冲突(他在故事里要完成什么):____ +- 恶魔(他最怕什么):____ +- 早期根源(为什么怕,追到童年/早期):____ +- 关键问:如果他成功了,他会失去什么?____ +- 共振一句话:外部任务____正好激活恶魔____ + +过关线:共振一句话写得出来。内外平行不触碰 → 改恶魔或改外部任务,直到咬合。恶魔别写成社会议题("害怕贫穷"太大)或流行病("他抑郁"太泛)。 + +## 4. 角色弧(→ references/inner-demon.md) + +- 故事开始时的他:____ +- 故事结束时的他:____ +- 3 个变化:1.____ 2.____ 3.____ +- 结局时对恶魔做了什么:□ 克服 □ 接受 □ 失败(悲剧) □ 部分克服 + +过关线:列得出 3 个变化;四种弧结局都行,但必须明确选一个。没变化 = 弧缺失,回第 3 节找恶魔。 + +## 5. 定形(→ references/flat-vs-round.md) + +一句话测试:"____" + +- 能一句话说清吗?□ 能(偏扁平) □ 不能(偏圆形) +- 这个形态是刻意选的吗?主题类型:□ 喜剧/群像(扁平合法) □ 严肃/悲剧(必须圆形) +- 圆形公式检查(圆形角色填):出人意料的点____□;事后仍然可信□;缺一 = 伪圆形,回第 2 节补深层或退回扁平 +- 动态切换机会(可选高级项):他在____场景从扁平鼓胀成圆形,用____(一句否定句/一个反常动作)呈现 + +过关线:形态与主题匹配。给修改建议要具体到场景和话,不写"让人物更立体"这类空话。 + +## 6. 原型打底(→ references/archetype-reversal.md) + +- 基础原型(1-2 个,西方 11 原型或本土母题):____ +- 读者期待的位置:____ +- 反转点(≥1,挂在核心冲突上):____ +- 为什么在这里反转(一句话,答不出 = 为反而反):____ +- Father Horst 检验:显著元素____"不只是物"□;象征呈现用细节/动作/对话轻敲,无"这是象征"宣告段落□ +- 人物无内部矛盾 = 刻板印象不是原型 □ + +过关线:反转点一句话说得清;象征靠轻敲不靠宣告。刻意反原型的解构作品跳过本节。 + +## 7. 总评 + +- 角色一句话:____ +- 判定:□ 通过 □ 弱项补救清单:____ □ 回炉 +- 下一步:场景内呈现(见综合 skill character-presentation)/结构规划(见综合 skill story-structure) diff --git a/framework/catalog/pi/skills/character-design/references/flat-vs-round.md b/framework/catalog/pi/skills/character-design/references/flat-vs-round.md new file mode 100644 index 0000000..f999077 --- /dev/null +++ b/framework/catalog/pi/skills/character-design/references/flat-vs-round.md @@ -0,0 +1,141 @@ +# 定形:扁平人物与圆形人物 + +## 原文摘录 + +> "我们可以把人物分为'扁平的'和'圆形的'两种。扁平人物在 17 世纪被称为'幽默性的', 有时指代类型, 有时指夸张的手法。最纯粹的扁平人物只围绕单一的理念或性格特质构建 …… 真正的扁平人物可以只用一句话表达。" + +> "圆形人物拥有自身的无尽生命力 …… 考验一个人物是否算得上圆形人物, 标准在于他能否出人意料, 并同时做到令人信服。" + +> "我们必须承认, 扁平人物本身无法达成圆形人物那样的成就, 而且他们的最佳状态仅存在于喜剧人物中。严肃或悲剧性的扁平人物很容易变得乏味。" + +> — E. M. 福斯特, 《小说面面观》第三讲 / 第四讲 + +## 方法规则 + +### 一句话测试 + +任何人物,试着写一句话概括他(例:"米考伯太太永远不会背弃米考伯先生","贝特伦夫人性子很好,但千万别把她惹急了")。如果一句话能说清,大概率是扁平;如果一句话说不清,大概率是圆形。 + +合并点:布鲁克斯说的"1 维角色:一个形容词就能概括"(references/three-dimensions.md)与本测试是同一把尺子,互相对应。 + +### 圆形公式 = 出人意料 × 仍然可信 + +圆形人物的公式:出人意料(作者给我们"没想到")× 仍然可信(事后觉得"对,这才是他")。两者缺一就不算真圆形。 + +### 扁平人物不是缺陷 + +在喜剧 / 群像 / 节奏中,扁平人物是必要的"轮盘",容易辨认,不会随环境变化,让读者快速进入场景。狄更斯笔下几乎全是扁平人物,但他仍是"最伟大的作家之一"。 + +### 圆形人物是严肃/悲剧的必要条件 + +福斯特明示:"任何时间维度内的悲剧都只能通过圆形人物加以呈现"。严肃/悲剧的扁平人物"很容易变得乏味"。 + +### 扁平 ↔ 圆形可动态切换 + +福斯特举贝特伦夫人为例:平时是扁平("我性子很好,但千万别把我惹急了"),紧急时刻鼓胀成圆形("她完全明白眼下发生的事情有多严重,并不试图劝说自己看轻其中的罪恶与耻辱"),之后又回到扁平。**奥斯汀的"圆盘骤然鼓胀"是写作的高级技巧**。 + +### 关键认识 + +扁平与圆形不是"好 vs 坏",是"功能不同"。严肃主题优先圆形;喜剧/群像优先扁平;复杂主题可以混用——让扁平与圆形的反差冲突比纯写实更尖锐。 + +## 案例全文 + +### 案例 1:简·奥斯汀《曼斯菲尔德庄园》贝特伦夫人——扁平到圆形的动态切换 + +- **问题**:贝特伦夫人平时是扁平人物,紧急时刻能圆形吗? +- **方法论的使用**:福斯特分析她"两个女儿遭遇人生的惨败"时的反应——"她完全明白眼下发生的事情有多严重,并不试图劝说自己看轻其中的罪恶与耻辱,也不向范妮寻求建议" +- **结论**:圆盘骤然鼓胀,现了球形——这是奥斯汀的高级技巧,一段否定句就让扁平 → 圆形 +- **结果**:借此福斯特说"简·奥斯汀是多么会写啊"——圆形人物的"鼓胀"是写作的标志 + +### 案例 2:笛福《摩尔·弗兰德斯》对比简·奥斯汀《爱玛》贝茨小姐 + +- **问题**:同样是人物,摩尔·弗兰德斯能单独成立,贝茨小姐不能单独成立 +- **方法论的使用**:福斯特比较——摩尔像"空地上唯一的树",兀然独立,"我们忍不住要问自己,如果在生活中遇到,我们能不能把她给认出来";贝茨小姐"与海伯里有着千丝万缕的联系",不能与简·费尔法克斯、弗兰克·丘吉尔分开 +- **结论**:摩尔 = 极端的圆形(孤树型);贝茨小姐 = 圆形 + 复杂关系网 +- **结果**:借此说明,圆形的"成立方式"可以是孤树型(笛福)也可以是关系网型(奥斯汀) + +### 案例 3:狄更斯笔下的扁平人物群 + +- **问题**:狄更斯的人物几乎全是扁平,凭什么他是"最伟大的作家之一"? +- **方法论的使用**:福斯特诊断——狄更斯"善于运用类型化和夸张的笔法,让我们能够在人物再次出现时立刻认出他们,同时又能够确保所呈现的效果不流于机械化的套路,对人性的观察也不流于肤浅" +- **结论**:狄更斯的扁平人物群不是缺陷,是"扁平之中蕴含的东西远比严肃的批评家们所认可的更丰富" +- **结果**:借此反驳诺曼·道格拉斯的"小说家的笔法是对现实的篡改"——扁平人物在喜剧/群像中是合法的 + +## 操作步骤 + +1. **对每个人物做"一句话测试"** + - 完成标准:至少为 3 个人物写出"一句话概括",标出哪些能一句话说清,哪些不能 + - 判停条件:如果全部能一句话说清,人物都是扁平;如果全部不能,人物都是圆形 +2. **应用圆形公式** + - 完成标准:对至少 1 个被识别为圆形的人物,检查"出人意料" + "仍然可信"两个条件是否都满足 + - 不满足:标为"硬充圆形的扁平人物"(只意外不可信,或只可信不意外) +3. **诊断主题-类型的匹配** + - 完成标准:判断当前主题是喜剧/群像(→ 优先扁平)还是严肃/悲剧(→ 必须圆形) + - 不匹配:严肃主题用了扁平 → 危险,可能变得乏味 +4. **评估"扁平-圆形动态切换"的可能** + - 完成标准:至少 1 个人物是否有"扁平→圆形→扁平"的可能?如有,这是写作的高级机会 + - 福斯特举贝特伦夫人(奥斯汀)的紧急时刻"鼓胀"为例 +5. **给出修改建议** + - 完成标准:至少 1 条具体修改(如"给配角 X 加一个'鼓胀'瞬间,让他在 Y 场景中说出 Z 的话,显示他平时掩盖的一面") + - 不要空话(如"让人物更立体")——给可操作修改 + +## 应用场景(写作之外) + +其他适用场景,作为方法延伸保留: + +- **角色设计(产品/品牌)**——品牌人格是单一理念(扁平)还是多面性(圆形)? +- **人物评论(读后感/影评/产品评测)**——评估人物"丰满度"和"可信度" +- **面试候选人评估**——候选人是否能"出人意料又令人信服"? +- **历史人物/公众人物评估**——简化叙事 vs 多面性叙事的取舍 +- **教学/培训人物塑造**——教学生"如何让人物丰满" + +注意:对真实人的全面评价不是方法应用,见下方边界。 + +## 边界与失败模式 + +### 不要在以下情况使用 + +- **真实人的全面评价**——这是道德问题,不是方法论;"X 是个圆形人物"在真实人身上可能不公平 +- **纯信息传递(没有人物)**——如新闻报道,不需要人物分类 +- **必须用单一标签的场景**——如数据库标记,扁/圆是写作概念,不是标签 +- **道德评价**——"X 是扁平人物"不等于"X 不好" + +### 作者在书中警告的失败模式 + +- **严肃/悲剧用了扁平人物**——"我永远不会背弃米考伯先生"在喜剧中成立,在悲剧中变成口号(ce07: 司各特式"会讲故事"的单维胜利;ce02: 文学是天才崇拜) +- **追求"绝对写实"反对扁平**——道格拉斯式"非黑即白"的人物观,福斯特批为过激(ce06) +- **过度扁平**——把人物简化为标签,失去"人之为生灵所做出的努力"(ce10: 哈代式命运凌驾) +- **硬充圆形**——出人意料但不可信,是"伪圆形"(如某些"暗黑角色"强行反转) + +### 作者的盲点 / 时代局限 + +- **西方文学中心的视角**——引用的几乎全是英美欧陆小说;非西方叙事传统(如中国章回小说的"扁平人物群")未被充分讨论 +- **现代主义巅峰期的视角**——1927 年;当时还没有"人物弧(Character Arc)"等现代叙事学术语,但"出人意料又令人信服"已经是这个意思 +- **对女性人物的特殊性**——福斯特分析奥斯汀、勃朗特时,似乎把女性人物的"鼓胀"当成特殊现象,没有正面讨论"女性气质"在人物塑造中的作用 + +## 易混方法论 + +- **vs MBTI / 16Personalities**——MBTI 是"性格类型",扁/圆是"作者对人物的呈现方式";X 是 INTJ 不等于 X 是圆形人物 +- **vs 大五人格(Big Five)**——同上,是科学心理学,不是写作方法论 +- **vs 人物原型(Archetype,Jung)**——原型是"集体模式",扁/圆是"呈现方式";X 是英雄原型不等于 X 是圆形。本包 references/archetype-reversal.md 的"原型"是叙事母题原型,三者都要区分开 + +## 冲突标注:扁平是缺陷还是功能? + +- 布鲁克斯(references/three-dimensions.md):一维/扁平 = 缺陷,要补层修复。 +- 福斯特(本文):扁平 = 合法功能,放对位置(喜剧/群像/节奏)就是好人物;只有严肃/悲剧里用扁平才危险。 +- 两条规则都保留,合起来的判断顺序:先问形态是否刻意(喜剧/群像的扁平合法),再看主题是否严肃(严肃/悲剧必须圆形)。 + +## 中文适配 + +- **章回小说的扁平人物群**是福斯特盲点里点名没讨论的传统,正好是中文写作者的现成资源:《水浒》一百零八将多数一人一个鲜明特征(一句话测试天然适用),说书传统和章回体靠"容易辨认、不随环境变化"的扁平人物维持群像节奏。写中文群像,可以理直气壮地用扁平。 +- **戏曲行当**(生旦净末丑)本质是类型化配置,和狄更斯的"类型化和夸张的笔法"同路:观众要的就是再次出现时立刻认出。 +- 圆形公式"出人意料 × 仍然可信"在中文语境完全适用:《红楼梦》主要人物是圆形的范本(宝钗的冷与热、王熙凤的狠与谑都能出人意料又令人信服)。 +- 动态切换的"鼓胀"技巧对应中文写法:平时一句话立住的配角,在家破人亡、生死抉择一场戏里突然说出/做出超出自身定式的事,一段否定句或一个反常动作就够,不必铺垫整章。 + +## 与其他方法的关系 + +- **建**:配角原则四书一致——扁平形态 + 1-2 个变量即可 → references/seven-variables.md +- **立体**:3 维无错位的一维角色 = 一句话扁平 → references/three-dimensions.md +- **打底**:圆形人物的"出人意料"常靠站在原型上反转实现 → references/archetype-reversal.md +- **与 visible-private-life(隐秘生活可见性,框架本体归综合 skill character-presentation)的区别**:扁/圆是**人物形式层**的分类——一句话测试问的是人物的呈现方式(单一特质还是多面、能否出人意料);可见性是**人物本体论层**的框架——问的是作者是否对人物了如指掌、小说是否提供了"隐秘的内在人生是可见的"这种现实给不了的可见性。扁/圆管"这个人物是什么形态",可见性管"人物的内在是否可知",一个分类人物,一个划分小说与现实人,是两个独立的问题,不要混用。 +- **跨域指针**(不展开):圆形人物的"出人意料"需要作者对人物了如指掌,呈现层技法(可见的私生活)见综合 skill character-presentation;"出人意料"是蒙蔽读者的高级形式,蒙蔽技法见综合 skill scene-craft(mystification);扁/圆管单个人物分类,多个人物 vs 情节的拉锯见综合 skill novel-diagnosis(plot-character-tug) diff --git a/framework/catalog/pi/skills/character-design/references/inner-demon.md b/framework/catalog/pi/skills/character-design/references/inner-demon.md new file mode 100644 index 0000000..4ac428d --- /dev/null +++ b/framework/catalog/pi/skills/character-design/references/inner-demon.md @@ -0,0 +1,114 @@ +# 驱动:角色冲突来自内在恶魔 + +## 原文摘录 + +> "Exterior conflict is the conflict of the plot—something in the story world that opposes the hero's quest. Interior conflict is the conflict of the character, the inner demon... Both must be present. If only the external conflict is present, the character is a vehicle for the plot rather than a meaningful player in it." +> +> — Larry Brooks, *Story Engineering* (2011), Part 3 + +## 方法规则 + +### 两层冲突必须同时运作 + +角色必须有**外部冲突**和**内部冲突**同时运作。只有外部冲突,角色是工具人;只有内部冲突,角色是无剧情的独白。 + +**冲突的 2 层**: + +- **外部冲突(Exterior Conflict)**:剧情对手、社会、自然、敌人——他"做什么"会失败 +- **内部冲突(Interior Conflict / Inner Demon)**:内在恐惧、创伤、信念——他"为什么做不到" + +### Inner Demon 的四个关键特征 + +- 是**根本性**的,不是表面的(不是"他爱迟到",是"他害怕被拒绝所以迟到") +- 通常来自**童年/早期创伤** +- 是**驱动**角色弧的引擎——角色弧就是"克服 Inner Demon"的过程 +- **读者共鸣**来自 Inner Demon——读者在角色身上看到自己 + +### 操作问法 + +拿到一个角色,问"他最怕什么?"——不只是怕失败,是怕"如果我成功,我爸会怎么说"这种根深层的怕。 + +### 深度与呈现的分寸 + +**Inner Demon 越深,角色越活**。但太深(如严重心理疾病)需要谨慎呈现,避免负面示范。 + +### 深层 = 恶魔(合并点) + +本文的恶魔即 references/three-dimensions.md 的"深层":角色自己都未必意识到的驱动力。两个入口,同一件事:三层信息把它当最底层的事实,本文把它当冲突与弧的引擎。 + +## 案例全文 + +### 案例 1:反例——完美英雄,没 Inner Demon + +- **问题**:写作者写了"完美英雄",外部冲突强(打怪),但读者不关心 +- **方法论的使用**:诊断发现:Inner Demon = 0。角色没有"为什么做不到" +- **结论**:只有 External Conflict,角色是 vehicle for plot, not meaningful player +- **结果**:拒稿常见原因 + +### 案例 2:作者 5 部小说主角(恶魔角度) + +- **问题**:5 部小说主角都让出版商买,为什么? +- **方法论的使用**:每个主角都有清晰的 Inner Demon(孤儿之痛 / 父亲失败之痛 / 战火童年 / 等等) +- **结论**:5 个不同 Inner Demon = 5 个不同角色 +- **结果**:全部出版 + +> 同一案例在 references/seven-variables.md(角度:变量差异化)和 references/three-dimensions.md(角度:按 3 维建设)再次出现。角度不同,三处都保留。 + +> 结构里程碑中的 Thelma & Louise 案例 owner:`story-structure`([four-boxes.md](../../story-structure/references/four-boxes.md) 等)。Inner Demon 角度摘要:Thelma 长期被控制渴望自由;Louise 早年创伤与内疚——两恶魔撑起共情。 + +## 操作步骤 + +1. **选 1 个角色** + - 完成标准:用户指定 1 个 +2. **列出外部冲突** + - 完成标准:1 段说清"他在故事里要完成什么" + - 提示:这通常用户已经知道,5 分钟内能写 +3. **找 Inner Demon** + - 完成标准:1-2 段说清"他最怕什么" + "为什么怕"(找童年/早期根源) + - 关键问:"如果他成功了,他会失去什么?"(答:他会面对他最怕的) +4. **诊断:内外冲突共振了吗?** + - 完成标准:1 段说清"外部任务怎么激活/触碰他的 Inner Demon" + - 例:主角要公开发表演讲(外部)+ 他害怕被关注(内部)= 共振 + - 没共振 = 内外两层平行,不是故事 +5. **角色弧 = Inner Demon 的克服** + - 完成标准:1 段说清"故事结束时,他对自己的 Inner Demon 做了什么" + - 克服 / 接受 / 失败(悲剧)/ 部分克服 = 都行,但必须明确 + +## 边界与失败模式 + +### 不要在以下情况使用 + +- 角色不打算成为主角(配角可以没有完整 Inner Demon) +- 写群像/POV 切换——每个 POV 主角各做 1 次 +- 写非现实角色(动物/AI/外星人)——需调整 Inner Demon 的概念 + +### 作者警告的失败模式 + +- Inner Demon 太"社会议题"(如"他害怕贫穷")——缺乏个人化 +- Inner Demon 太"流行病"(如"他抑郁")——缺乏具体性 +- Inner Demon 没有"对外部任务的阻挡"——内外的连接是核心 + +### 作者盲点 + +- 默认 Inner Demon 是"心理疾病"——实际上更多是"信念/恐惧/习惯" +- 默认 Inner Demon 必须被克服——接受/失败的弧也有效 +- 默认 1 个 Inner Demon——多个 Inner Demon 互相矛盾也常见,但需控制 + +## 易混方法论 + +- "Character Wound"(Lisa Cron)——类似,但更聚焦"故事前发生的事件" +- "Ghost / Wound / Need"(Story Grid)——三层结构,不同于本 skill 的 1 个核心 +- "Lie the Character Believes"(K.M. Weiland)——接近,但更窄(信念 vs 恐惧) + +## 中文落地 + +- 中文读者对"家庭之痛"的共鸣最直接:恶魔的早期根源常落在家庭(被比较、被抛弃、被期待压垮)。写法上不贴诊断名词,落到那件具体的事、那句没说出口的话。 +- 网文类型(复仇流、升级流、无敌流)外部冲突普遍很强,最容易出恶魔 = 0 的工具人问题;主角至少要有一个"为什么做不到/不敢",类型爽感才不会变成流水账。 +- "他抑郁"这类写法在中文里同样是失败模式:诊断词不是恶魔,要写这个抑郁具体长什么样、挡住了外部任务的哪一步。 + +## 与其他方法的关系 + +- **建**:恶魔是 7 变量中的变量 4 → references/seven-variables.md +- **立体**:恶魔 = 三层信息的深层 → references/three-dimensions.md +- **结构衔接**:恶魔被激活、深层浮出水面的节拍常放在故事中点附近,中点的结构定位见综合 skill story-structure +- **定形**:带完整恶魔的角色几乎不可能一句话说清,天然偏圆形 → references/flat-vs-round.md diff --git a/framework/catalog/pi/skills/character-design/references/seven-variables.md b/framework/catalog/pi/skills/character-design/references/seven-variables.md new file mode 100644 index 0000000..748992e --- /dev/null +++ b/framework/catalog/pi/skills/character-design/references/seven-variables.md @@ -0,0 +1,117 @@ +# 建角色:角色 7 大变量 + +## 原文摘录 + +> "Surface affectations and personality... Backstory... Character arc... Inner demons and conflicts... Worldview... Goals and motivations... Decisions, actions, and behaviors... seven major categories of character possibility... With seven knobs on the control panel, there are no less than ten million totally unique settings for any character you can dream up." +> +> — Larry Brooks, *Story Engineering* (2011), Part 3 + +## 方法规则 + +### 角色不是一个形容词,也不是一个职业 + +角色由 7 个独立变量组成。每个变量可以独立调 1-10 档。7 变量 × 10 档 = 1000 万+ 唯一组合,不会重样。 + +### 7 个变量 + +1. **表层人格(Surface Affectations)**:外人眼中的形象,包括外貌、口头禅、怪癖 +2. **背景故事(Backstory)**:故事开始前发生的事,决定他现在是谁 +3. **角色弧(Character Arc)**:故事中角色的成长/改变路径 +4. **内在恶魔(Inner Demons)**:角色内心最深处的恐惧/创伤/伤痕(专论见 references/inner-demon.md) +5. **世界观(Worldview)**:角色对世界/道德/他人的根本信念 +6. **目标与动机(Goals and Motivations)**:角色想要什么,为什么想要 +7. **决策/行动/行为(Decisions, Actions, Behaviors)**:角色实际做了什么 + +### 输入与输出:行为是前 6 个变量的测试 + +- 前 6 个变量是"输入",第 7 个是"输出" +- 第 7 个(行为)是其余 6 个的"测试"——前 6 设定一致,第 7 自然一致;前 6 矛盾,第 7 就矛盾(这是写作的 bug 来源) +- 每个变量可以独立调,1-10 档;但一个变量的极端值(如背景故事 9,但角色弧 2)可能产生不一致 + +### 三种用法 + +- **创建角色**:7 变量全部设定 +- **诊断角色**:缺哪个变量 = 角色缺哪个维度 +- **对比角色**:两个角色哪些变量不同 → 区分度 + +## 案例全文 + +### 案例 1:一个"懦弱的士兵"角色 7 变量完整版 + +- **问题**:写作者想写"懦弱士兵"但脸谱化 +- **方法论的使用**: + 1. 表层:沉默寡言,总是低头 + 2. 背景:父亲是越战英雄,他无法复制父亲的勇气 + 3. 角色弧:学会做自己(而非做父亲) + 4. 内在恶魔:害怕重复父亲的命运 + 5. 世界观:"英雄主义是神话,普通人活下去就是英雄" + 6. 目标:让队友活着回家 + 7. 行为:关键时刻违抗命令救孩子,自己受重伤 +- **结论**:7 变量设定后,角色自然立体 +- **结果**:演示"7 变量填满 = 角色立住" + +> 中文落地:越战背景不是要点,换成中文语境里任何"父辈荣耀压力"的设定(父亲是战斗英雄、劳模、世家从军)结构都成立;世界观那句"英雄主义是神话,普通人活下去就是英雄"照原文保留即可,不需要翻译腔处理。 + +### 案例 2:作者 5 部小说主角(变量差异化角度) + +- **问题**:5 部小说 = 5 个主角,怎么不重样? +- **方法论的使用**:每个主角只调 2-3 个变量的极端值(如 Backstory 1 vs Backstory 9,Goal 5 vs Goal 9) +- **结论**:7 变量差异化 = 5 个完全不同主角 +- **结果**:全出版,0 重样 + +> 同一案例在 references/three-dimensions.md(角度:每个主角按 3 维建设,一本获 *Publishers Weekly* 年度最佳)和 references/inner-demon.md(角度:每个主角各有一个清晰的内在恶魔)再次出现。角度不同,三处都保留。 + +## 操作步骤 + +1. **选 1 个角色** + - 完成标准:用户指定 1 个 +2. **逐变量填(7 个)** + - 完成标准:7 段,每段 3-5 句具体描述 + - 提示:不要照抄变量名,写具体内容 + - 例:不要"角色有背景故事",要"她 12 岁目睹父亲车祸,之后 5 年不说话" +3. **一致性检查** + - 完成标准:验证 7 变量彼此一致 + - 检查:"他害怕亲密"(5)+ "他主动追求每个人"(7)= 矛盾 + - 如果矛盾:修一个变量,不要修全部 +4. **角色弧检查(变量 3)** + - 完成标准:故事开始时的角色 vs 故事结束时的角色,列出 3 个变化 + - 没有变化 = 角色弧缺失,用 references/inner-demon.md 找冲突 + +## 边界与失败模式 + +### 不要在以下情况使用 + +- 角色已成型,想检查特定维度(用 references/three-dimensions.md 或 references/inner-demon.md) +- 写 1 个角色 vs 群像的对比(用 references/three-dimensions.md 区分) +- 写非常配角(1-2 变量就够,7 变量过度) + +### 作者警告的失败模式 + +- 7 变量都"中庸"(4-5 档)= 没特色——至少 2-3 个变量在极端 +- 第 7(行为)跟前 6 不一致——必须先改前 6,不要直接改行为 +- 把变量 5(世界观)当成"哲学标签"——必须是角色具体信什么 + +### 作者盲点 + +- 7 变量假设 1 个主角——群像需要 1+7(1 主角 + 7 配角)的多份填表 +- 默认 7 变量在故事中不变——变量 3(角色弧)必然变,其他也可能变 +- 默认所有角色都该填 7 变量——反派/小配角可以少填 + +## 易混方法论 + +- "Character Bible"(影视行业)——类似但更宽,含外貌/关系图等 +- "16 Personalities"(MBTI)——是性格类型,不是 7 变量全维度 +- "Enneagram"(九型人格)——是 9 种类型,不是变量组合 + +## 中文落地 + +- 7 变量本身语言中立。中文填写时别把英文心理学词汇直接抄成标签——"他有信任问题"是哲学标签,要写成他具体信什么、做什么。 +- 世界观变量在中文小说里最容易写成套话:不写"他相信正义",写他会说出口的那句具体判断("过日子就是熬")。 +- 群像 1+7 多份填表法对章回体、家族群像式中文小说同样适用:每个角色一张表,逐个填,不批量。 + +## 与其他方法的关系 + +- **立体**:表层人格即三层信息的表层;7 变量填完后再查三层是否错位 → references/three-dimensions.md +- **驱动**:变量 4 内在恶魔是角色弧的引擎,专论 → references/inner-demon.md +- **定形**:7 变量填满的角色若仍能一句话说清,检查扁平形态是否刻意为之 → references/flat-vs-round.md +- **打底**:角色弧与世界观可挂到叙事原型上做反转 → references/archetype-reversal.md diff --git a/framework/catalog/pi/skills/character-design/references/three-dimensions.md b/framework/catalog/pi/skills/character-design/references/three-dimensions.md new file mode 100644 index 0000000..76a95d9 --- /dev/null +++ b/framework/catalog/pi/skills/character-design/references/three-dimensions.md @@ -0,0 +1,123 @@ +# 立体化:角色 3 维度(表层/内层/深层) + +## 原文摘录 + +> "Three very separate and compelling layers—dimensions, in this context—that are carefully crafted to bring your story alive with resonant emotional depth. The first dimension is who the world sees. The second dimension is who the character is in private. The third dimension is who the character truly is, in spite of how she or he may present in either of the first two dimensions." +> +> — Larry Brooks, *Story Engineering* (2011), Part 3 + +## 方法规则 + +### 一个角色至少有 3 层独立的信息维度 + +大多数角色只写到 1 维(扁平),极少数写到 3 维(立体)。 + +**3 维度**: + +1. **表层(Surface Affectations)**:别人眼中的角色——外貌、口头禅、社会身份、第一印象 + - 例:严肃的律师,总是穿西装,不开玩笑 +2. **内层(Private Self)**:角色独处时的真实状态——内心挣扎、恐惧、爱好、矛盾 + - 例:独处时写诗,听 80 年代摇滚,害怕死亡 +3. **深层(True Self)**:角色自己都不知道的核心——驱动一生的根本信念/创伤/欲望 + - 例:童年被父亲抛弃,一生渴望被认可但永不表达 + +### 3 维的关系 + +- 表层是面具,内层是脱下面具的自己,深层是面具下连自己都不知道的核心 +- 大多数角色 3 维是**错位**的——表层严肃但内层温柔,深层害怕被爱 +- **戏剧来自错位**——关键场景里,3 维的错位会暴露/转移 +- 写作者必须能**列出 3 维的具体内容**,否则角色还在 1 维 + +### 3 维 vs 1 维 + +- 1 维角色:一个形容词就能概括(勇敢/聪明/坏) +- 3 维角色:需要 3 个以上不同维度的形容词,且彼此矛盾 + +### 深层 = 内在恶魔(合并点) + +本文的"深层"(角色自己都未必意识到的驱动力)与 references/inner-demon.md 的"内在恶魔"是同一件事。两处都保留:本文从信息分层角度说"它是角色最底下的一层",references/inner-demon.md 从冲突与弧的角度说"它是驱动角色弧的引擎"。 + +## 案例全文 + +### 案例 1:Walter White(《Breaking Bad》) + +- **问题**:一个中学化学老师变成毒枭,怎么让读者又恨又爱? +- **方法论的使用**: + - 表层:中学老师,收入低,被老婆看不起 + - 内层:孤独,害怕平庸一辈子,渴望证明自己 + - 深层:童年时父亲(科学家)早逝,一生想完成父亲的"伟大事业" +- **结论**:3 维的错位让观众持续 5 季 +- **结果**:史上最成功的反英雄之一 + +### 案例 2:作者 5 部小说主角(3 维建设角度) + +- **问题**:5 部小说主角怎么都不脸谱化? +- **方法论的使用**:每个主角都按 3 维建——表层职业身份,内层矛盾,深层创伤 +- **结论**:3 维 + 7 变量 = 1000 万+ 角色组合,不会重样 +- **结果**:5 部全出版,1 本获 *Publishers Weekly* 年度最佳 + +> 同一案例在 references/seven-variables.md(角度:变量差异化)和 references/inner-demon.md(角度:各带不同恶魔)再次出现。角度不同,三处都保留。 + +### 案例 3:Don Draper(《Mad Men》,作为反例背景) + +- **问题**:60 年代广告公司主管,为什么观众 7 季都爱看? +- **方法论的使用**:表层(成功主管)+ 内层(酗酒、外遇)+ 深层(童年在妓院长大,假身份) +- **结论**:3 维错位撑起 7 季 +- **结果**:经典反英雄 + +## 操作步骤 + +1. **选定 1 个角色** + - 完成标准:用户指定 1 个角色(主角/反派/配角) +2. **分别写出 3 维** + - 完成标准:3 个独立段落,每段 3-5 句 + - 提示:不要复制表层到内层,不要把深层当"我小时候如何" + - 深层 = 角色自己都未必意识到的驱动力 +3. **验证 3 维错位** + - 完成标准:列出 3 维之间的矛盾 + - 关键检查:"如果 3 维一样,角色是 1 维" +4. **找出 3 维都会"现身"的关键场景** + - 完成标准:至少 2 个场景,角色在场景里表层/内层/深层都"露馅"瞬间 + - 深层在关键时刻"浮出水面" = 角色弧的关键节拍 + +## 边界与失败模式 + +### 不要在以下情况使用 + +- 群像管理(≥ 3 个主角)——给每个主角分别用 1 次,不要批量 +- 写反派需要更具体的"动机"(用 references/seven-variables.md 找 Inner Demons) +- 写配角(用 references/seven-variables.md 的 1-2 个旋钮即可) + +### 作者警告的失败模式 + +- 深层写得太"哲学"——"她是个追寻自由的人"不是深层,是修辞 +- 深层只是内层的延伸——"表层严肃,内层不严肃,深层想严肃" = 错位失败 +- 3 维都用相同词汇——必须各有具体内容 + +### 作者盲点 + +- 3 维假设"角色有内省能力"——某些角色(例如小孩、动物、严重心理障碍)不适用 +- 默认 3 维都"善"——反派 3 维可以全是"自我",这也是有效的 +- 默认 3 维稳定——3 维在故事中可能演化(character arc),不是固定 + +## 易混方法论 + +- 心理学的"人格面具"(Persona / Shadow,Jung)——哲学源头相似,但应用不同 +- 写作的"角色原型"(Christopher Vogler 12 archetype)——那是类型,不是维度;本包 references/archetype-reversal.md 说的"原型"是克拉克的叙事母题原型,与 Vogler 的角色类型原型也不是一回事 + +## 冲突标注:一维是缺陷,还是合法形态? + +- 布鲁克斯(本文):1 维 = 缺陷,要补内层和深层修复。 +- 福斯特(references/flat-vs-round.md):扁平(≈ 一维)是合法功能,喜剧/群像优先,不必人人写圆;但严肃/悲剧必须圆形。 +- 两条规则都保留:先问"这个角色的形态是不是刻意选的"。配角、喜剧角色可以刻意一维;主角、严肃/悲剧角色一维就是缺陷。 + +## 中文落地 + +- 3 维法在中文网文里尤其值得用:网文主角常被写成"职业 + 金手指"的 1 维配置,补内层(独处时的真实状态)和深层(连自己都不说的渴望)是最快的去脸谱化手段。 +- 深层例"童年被父亲抛弃,一生渴望被认可但永不表达"是通用句式;中文语境可换成本土创伤源(重男轻女家庭、留守经历、父辈污点),但必须落到具体事件和动作,不能只写一个标签。 + +## 与其他方法的关系 + +- **建**:表层即 7 变量的表层人格,深层往往要靠背景故事(变量 2)供出 → references/seven-variables.md +- **驱动**:深层 = 内在恶魔;深层"浮出水面"的关键节拍常与故事中点配合(中点的结构定位见综合 skill story-structure) → references/inner-demon.md +- **定形**:3 维无错位 = 1 维 = 一句话能说清的扁平,形态该不该改由主题定 → references/flat-vs-round.md diff --git a/framework/catalog/pi/skills/character-presentation/SKILL.md b/framework/catalog/pi/skills/character-presentation/SKILL.md new file mode 100644 index 0000000..b2c723d --- /dev/null +++ b/framework/catalog/pi/skills/character-presentation/SKILL.md @@ -0,0 +1,110 @@ +--- +name: character-presentation +description: | + 写小说时要把人物呈现给读者看,而不是讲给读者听,遇到这些情况激活:人物登场段读起来像 + 性格形容词清单,用了勇敢、热情、冷酷等抽象词但读起来假;人物扁平、脸谱化、群像分不清; + 次要人物只有 200 字登场空间不知道怎么让人记住;情节靠巧合推动,主角无故倒霉;人物没戏、 + 该转变但读者看不到转变;想知道"如何显示人物"而不是"告诉"。 + 关键 trigger:"细节马赛克 / mosaic of detail / 人物立体 / 人物脸谱化 / 登场段 / + 性格形容词 / show not tell / status details / Tom Wolfe / 网文主角人设 / + 性格碰撞 / 性格即命运 / 反常即戏 / 反常瞬间 / 关系网 / 隐藏关系 / 人物很立体 / + 比现实更真实 / 人物让我看到了看不到的东西 / 过程发现 / 人物自己说话了"。 + 不适用于:人物变量设计、人物弧线与原型定位、扁圆人物一句话测试(归 character-design); + 纯意识流、极简主义与人物作为思想载体的抽象哲学小说;真实人物之间的理解问题(那是心理学 + 不是文学);非虚构写作(纪实作品人物的话必须基于事实)。 + 与 dialogue-craft 交接:说话方式、句长、口头禅、同一声音诊断、遮住名字测试归 dialogue-craft; + 本 Skill 只管登场呈现、关系网、反常瞬间与"过程发现"叙事。 + 与 character-design 交接:建角变量与弧线归后者;定型后的场景内呈现归本 Skill。 +--- + +# 人物呈现(character-presentation) + +解决一件事:让人物被读者自己看见,而不是被作者讲给读者——用细节装配登场,让隐秘内在可见,用关系网显性格,用性格碰撞出命运,用反常瞬间翻转身份,让人物发出自己的声音。 + +## 方法索引 + +按创作动作组织;方法细节、案例、引文都在 references 里,这里只给一句话和指针。 + +### 用具体物装配登场 + +- 把"身份细节"扩展成细节马赛克:从 10+ 维度里精心挑 5-9 个具体到感官的细节,让读者自己合成完整的人 → references/detail-mosaic.md +- 每个细节是一个反推钩子(背头→爱面子,踝部枪→危险职业);反推不出任何东西的细节换掉;穷举 10 维度是糟糕写作 → references/detail-mosaic.md +- 抽象性格形容词是"失败的告诉",全部换成 1-2 个具体细节;Clark 检验:删一个细节人物变轻才必要 → references/detail-mosaic.md +- 中文适配:补家当与身份标志、服饰面料、玉石材质、茶酒待客等本地维度 → references/detail-mosaic.md + +### 让隐秘的内在可见 + +- 人物"真实"的标准不是像现实中的某个人,而是作者对其了如指掌 → references/visible-private-life.md +- 人物有两面:历史的一面(可观察行为)和虚构的一面(感情、幻想、没说出口的话),好小说必须写后一面 → references/visible-private-life.md +- 可见性分层:基础层是这个人物被写透了,更高一层是人物代表的人性可见 → references/visible-private-life.md + +### 用关系网显性格 + +- "他是谁"不能问他自己,要问他的关系网;给人物至少三重关系,五个关系就是人物的五张面孔 → references/relationship-web.md +- 关系要对比:同一个人在不同关系里反应不同才算设计到位,全是同一种反应等于没设计 → references/relationship-web.md +- 关系必须推动情节,装饰关系删掉或改;隐藏关系(读者知道人物不知道)是戏的来源 → references/relationship-web.md +- 群像区分:每个主要人物的关系网要独特,把两人的关系网互换还能用就是没设计好 → references/relationship-web.md + +### 用性格碰撞出命运 + +- 不让主人公倒霉,让他遇到另一个人:单个性格不产生命运,性格遇上性格才产生命运 → references/character-collision.md +- 把巧合翻译成性格碰撞:删掉这个巧合,主人公凭性格照样会遇到这件事,翻译才算成功 → references/character-collision.md +- 每个主要人物用 3-5 个性格词定位(删一词不像、加一词模糊),设计性格链和"判断瞬间";反派也要有性格,否则是工具人 → references/character-collision.md + +### 用反常瞬间翻转身份 + +- 人物的戏藏在"应该这样但没这样、不该这样却这样了"的瞬间;反常是人物身份变化的开始 → references/abnormal-moment.md +- 三种反常:行为反常、关系反常、时间反常;反常必须落实成一个具体动作或一句对话,不用形容词概括 → references/abnormal-moment.md +- 设计 3-5 个排成递进链;好的反常不事后解释:"原来如此"是成,"莫名其妙"是败,"早猜到了"是太露 → references/abnormal-moment.md + +### 让人物发出自己的声音 + +- 写足够久,人物会说出作者没计划的话;作者从发号施令的控制者转为感同身受的记录者 → references/voice-discovery-process.md +- 什么人说什么话、遮住名字测试、同一声音诊断 → `dialogue-craft` 的 [character-voice.md](../dialogue-craft/references/character-voice.md) + +### 总原则:不宣告,让读者反推 + +- 两本书三个源单元做同一件事:不宣告、不自夸、不自我介绍,用细节、关系、动作、对话替换形容词和标签;三个源单元的视角与引文见 references/detail-mosaic.md"多书合并点"节。 + +### 张力标注 + +- 外在细节装配(Clark)vs 内在可见(福斯特):分工是登场层 vs 深度层,细节堆得多 ≠ 人物被写透,见 references/visible-private-life.md"张力标注"节。 +- 事前设计(关系网、性格词)vs 声音的过程发现(余华):分工是骨架 vs 血肉,见 references/voice-discovery-process.md 张力标注节。 + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|---------| +| references/detail-mosaic.md | status details→细节马赛克、10+ 维度、5-9 个感官细节核心规则、反推钩子、Clark 检验、O'Neill 登场与 Belva Kent 胶带案例、替换抽象形容词四步、三大失败模式、中文本地化维度(中文适配)、多书合并点"不宣告让读者反推"、与 show-don't-tell/archetype-toolkit/dialogue-as-action/voice-equalizer 的区分 | +| references/visible-private-life.md | 小说与现实人的本体论差异、"真实=作者了如指掌"判断标准、小说比历史更真实、阿兰两面性、摩尔·弗兰德斯/维多利亚女王/海蒂 vs 米嘉案例、可见性分层、五步操作、四大失败模式、盲点与说书人可见(中文适配)、与代入感/心理现实主义/神入的区分 | +| references/relationship-web.md | 人物性格在关系里不在自我描述里、王熙凤与秦可卿三层关系、四条核心原则、王熙凤/林冲/《杀手》/《苔丝》四案例、六步操作(含 ❌✅ 王熙凤原句)、隐藏关系、群像互换检验、常见错误表 | +| references/character-collision.md | "性格从来就不是命运"题旨引文、命运=性格碰撞、错误命运 vs 正确命运、《促织》成名+里胥/林冲+高俅/王熙凤+贾瑞/苔丝四案例、巧合翻译表、性格速写 3-5 词、性格链、判断瞬间、常见错误表 | +| references/abnormal-moment.md | 沃滋沃斯两个反常、三种反常类型、沃滋沃斯芒果/小促织跳袖口/王熙凤骂街原句/《项链》四案例、列常态→找反常→具体化→递进链→不解释五步、常见错误表 | +| references/voice-discovery-process.md | 控制阶段→记录阶段、余华三案例、过程发现六步、传声筒失败模式、事前设计 vs 过程发现张力标注 | +| references/_coverage.md | 六个源单元的覆盖对照表与跨域指针(说话方式正文见 dialogue-craft/references/character-voice.md) | + +## 脚本 + +| 脚本 | 用途 | +|------|------| +| references/presentation-checklist.md | 人物呈现自查台账:登场细节装配、内在可见、关系网、碰撞设计、反常设计、声音检查、总判断标准,一份填完 | + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 红线 + +- 只给当前创作阶段的建议,不越权改设定主权、不绕过检测链、不复制粘贴其它 Skill 的 owner 定义。 +- 无用户明确授权不得替用户定稿或提交 Git。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/pi/skills/character-presentation/references/_coverage.md b/framework/catalog/pi/skills/character-presentation/references/_coverage.md new file mode 100644 index 0000000..d5388cd --- /dev/null +++ b/framework/catalog/pi/skills/character-presentation/references/_coverage.md @@ -0,0 +1,13 @@ +# character-presentation 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| aspects-of-the-novel/visible-private-life | references/visible-private-life.md | +| bifeiyu-novel-skill/bifeiyu-anti-norm | references/abnormal-moment.md | +| bifeiyu-novel-skill/bifeiyu-character-fate | references/character-collision.md | +| bifeiyu-novel-skill/bifeiyu-relationship | references/relationship-web.md | +| bifeiyu-novel-skill/bifeiyu-relationship | references/detail-mosaic.md | +| wo-neng-fou-xiang-xin-zi-ji/character-voice-discovery | references/voice-discovery-process.md(过程发现);说话方式技术 → dialogue-craft/references/character-voice.md | +| writing-tools-clark/mosaic-of-detail | references/detail-mosaic.md | diff --git a/framework/catalog/pi/skills/character-presentation/references/abnormal-moment.md b/framework/catalog/pi/skills/character-presentation/references/abnormal-moment.md new file mode 100644 index 0000000..3a95639 --- /dev/null +++ b/framework/catalog/pi/skills/character-presentation/references/abnormal-moment.md @@ -0,0 +1,178 @@ +# 反常即戏:找到"不该这样但这样了"的瞬间 + +来源:(毕飞宇《小说课》第 4 讲,案例取自《布莱克·沃滋沃斯》"等待"反常 + 整本书) + +> 「沃滋沃斯这个乞丐特殊了,他牺牲了他宝贵的谋生时间,一直在那里等待'我'。……不要小瞧了这个反常,从这个反常开始,沃滋沃斯的身份开始变化了。」 + +() + +## 原文摘录 + +《布莱克·沃滋沃斯》第五个乞丐出场前,奈保尔写了一段"反常": + +> 一个乞丐(沃滋沃斯),**不乞讨**——他在路边**等待**一个人(孩子)。 +> 一个乞丐(沃滋沃斯),**不讨饭**——他**请**孩子吃芒果。 + +**两个反常**: + +- 乞丐不去讨饭 → 失去"乞丐身份" → 显露"孤独者身份" +- 乞丐请人吃东西 → 关系反转 → 显出"爱"和"分享" + +**反常是人物身份变化的开始**。() + +## 方法规则 + +**反常即戏** = 找到"应该这样但没有这样"或"不应该这样但这样了"的瞬间。 + +**反常的三种类型**: + +1. **行为反常**:做了不该做的事 / 不做该做的事 +2. **关系反常**:用了不该用的关系 / 不用该用的关系 +3. **时间反常**:在该出现时没出现 / 在不该出现时出现 + +**反常是小说里最重要的"戏"**——它让人物"从 A 变成 B"。() + +## 案例全文 + +### 案例 1:奈保尔 沃滋沃斯请孩子吃芒果 + +- 乞丐请人吃 → 反常 +- 反常 → 他是"孤独者"不是"乞丐" +- 反常 → 他需要孩子 +- **整个小说从这里开始反转** + +### 案例 2:蒲松龄《促织》小促织跳到成名袖口 + +- 虫怕人 → 正常 +- 虫主动跳到人身上 → **反常** +- 反常 → 它是孩子变的 +- 反常 → 父亲不认识儿子,儿子认得父亲 +- **整个悲剧的"温度"在这里反转** + +### 案例 3:曹雪芹 王熙凤三句"骂街" + +> "别放你娘的屁了。再不带我看看,给你一顿好嘴巴。" + +- 贵族妇女在亲人面前骂街 → 反常 +- 反常 → 她和贾蓉的关系不正常 +- **揭示了隐藏关系** + +### 案例 4:莫泊桑《项链》路瓦赛太太决定买钻石项链还 + +- 一条假项链 → 不需要买真的还 +- 买真的还 → 花了 10 年 +- **反常但合理**——因为她诚实 / 因为她不知道是假的 +- 反常支撑了 10 年的故事 + +(以上四案例均出自) + +## 触发场景 + +1. 你的人物"没什么戏" → 找他的反常瞬间 +2. 你的情节"太平"了 → 加一个反常点 +3. 你想"揭示秘密" → 用反常代替直接说明 +4. 你的人物"该变了"但读者看不到变化 → 设计反常触发变化 +5. 你的"高潮"不够高潮 → 那个瞬间够反常吗? + +() + +## 操作步骤 + +### 步骤 1:列出"应该的常态" + +为你的主角 / 对手 / 关键人物,列出他**应该**有的行为模式: + +```yaml +人物:成名 +应该的常态: + - 父亲被责 → 想办法 + - 儿子惹祸 → 责罚儿子 + - 抓到促织 → 养好交差 + - 虫子跳来跳去 → 抓住它 +``` + +### 步骤 2:找出"反常瞬间" + +在常态列表中找**反例**: + +```yaml +反常: + - 儿子惹祸 → 儿子自杀(他没想父亲会这样) + - 抓到促织 → 促织主动跳上他(虫子不该这样做) + - 虫子 → 跳上袖口(虫子怕人才对) +``` + +**检验**:这个反常是**人物选择的反常**,还是**情境 / 情节的反常**? + +- 人物选择的反常 → 揭示性格 +- 情境的反常 → 推动情节 + +**两者都好**。 + +### 步骤 3:写"反常动作" + +把反常**具体化**为一个动作或对话: + +``` +❌ "沃滋沃斯很孤独"(形容词) +✅ 沃滋沃斯在路边等孩子,请孩子吃芒果(具体动作) +``` + +### 步骤 4:连锁反常 + +**一个反常通常不够**——要设计**3-5 个反常**形成链条: + +``` +反常 1:乞丐等孩子 +反常 2:乞丐请孩子吃芒果 +反常 3:乞丐讲"少年诗人和女诗人的故事" +反常 4:乞丐临死时告诉孩子"故事是假的" +``` + +每个反常都比上一个更"反常"——形成递进。 + +### 步骤 5:反常的"事后解释" + +**好的反常不解释**——读者读后能自己想通。 + +**检验**: + +- 读者读完后会"啊原来如此" → 好的反常 +- 读者读完后"莫名其妙" → 反常没设计好 +- 读者读完后"早猜到了" → 反常太明显 + +(以上步骤均出自) + +## 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 反常太多 | 假 | 短篇 1-2 个,递进式 | +| 反常没暗示 | 突兀 | 反常前要有"常态铺垫" | +| 反常变巧合 | 廉价 | 反常是"性格驱动",巧合是"作者安排" | +| 反常没后果 | 浪费 | 每个反常都要改变人物 / 情节 / 关系 | + +() + +## 适用边界 + +- **适合**:所有虚构叙事 +- **短篇必需**:短篇的"戏"几乎全靠反常 +- **慎用**:纯写实 / 纯纪录(它们恰恰要常态) + +() + +## 一句话总结 + +> **人物"应该这样"是常态;"不该这样但这样了"是戏——所有好小说的关键瞬间都藏在这里。** + +() + +## 跨 skill 链接 + +- 与 `bifeiyu-character-fate` 互补:反常是"性格即命运"的爆发点。(同在本包,见 references/character-collision.md) +- 与 `bifeiyu-iceberg` 配合:反常必有"水下"内容——一个反常的 7/8 在水下。(bifeiyu-iceberg 归综合 skill show-and-omission) +- 与 `bifeiyu-foreshadowing` 配合:反常前要有常态铺垫。(bifeiyu-foreshadowing 归综合 skill foreshadow-payoff) +- 与 `bifeiyu-momentum` 关联:反常是"势"的转折点。(bifeiyu-momentum 归综合 skill narrative-momentum) + +(;综合 skill 归属标注为本次合并所加) diff --git a/framework/catalog/pi/skills/character-presentation/references/character-collision.md b/framework/catalog/pi/skills/character-presentation/references/character-collision.md new file mode 100644 index 0000000..edbeebf --- /dev/null +++ b/framework/catalog/pi/skills/character-presentation/references/character-collision.md @@ -0,0 +1,200 @@ +# 性格即命运:设计碰撞而非制造巧合 + +来源:(毕飞宇《小说课》第 7 讲,案例取自《促织》"迁讷遇猾黠" + 整本书) + +> 「蒲松龄只给了他四个字,'为人迁讷'。'为人迁讷'能说明什么呢?什么都说明不了。没听说'为人迁讷'就必须倒霉,性格从来就不是命运。问题出就出在《促织》开头的那个'里胥'身上,'里胥猾黠'。当'迁讷'遇见了'猾黠',性格就必须是命运。」 + +() + +## 方法规则 + +### 命运不是性格单独决定的——是性格 + 性格碰撞出来的 + +- 迁讷 + 猾黠 = 必然被欺负 +- 林冲(忍)+ 高俅(恶)= 必然被逼上梁山 +- 哈代式的苔丝(纯)+ 失贞 = 必然悲剧 + +**单个性格不产生命运,碰撞才产生命运。**() + +### 核心洞察 + +不要让你的主人公"倒霉",让你的主人公"遇到另一个人"。 + +"一个人遇到另一个人"——这是小说最深的结构。() + +**错误的"命运"**: + +- 主人公生来就惨 +- 主人公被随机事件压垮 +- 主人公被作者安排"该轮到你了" + +**正确的"命运"**: + +- 主人公的特定性格 +- 遇上另一个特定性格的对手 +- 碰撞产生必然结果 + +() + +## 案例全文 + +### 案例 1:蒲松龄《促织》成名 + 里胥 + +``` +成名 = 迁讷(老实、不会说话) +里胥 = 猾黠(狡猾、贪婪) +碰撞:迁讷遇上猾黠,必然被欺压 +``` + +**升级链条**: + +- 里胥报成名做里正 → 成名不敢反抗 +- 促织征收 → 成名不敢敛户口 +- 抓到差促织 → 成名被打得不能行走 +- 儿子自杀 → 成名只能继续"用儿子换促织" + +**每一步都是性格的必然**。 + +### 案例 2:施耐庵《水浒》林冲 + 高俅集团 + +``` +林冲 = 技术好、心稳、想留在体制内 +高俅 = 权贵、霸凌、不讲理 +碰撞:林冲越想体面,高俅越不让 +``` + +### 案例 3:曹雪芹《红楼梦》王熙凤 + 贾瑞 + +``` +王熙凤 = 毒辣、聪明、好玩弄人 +贾瑞 = 痴情、自以为是 +碰撞:王熙凤"毒设相思局",贾瑞必死 +``` + +### 案例 4:哈代《苔丝》苔丝 + 失贞的阶级 + +``` +苔丝 = 纯真、忠诚 +亚雷 = 资产阶级恶少 +碰撞:失贞后无法在丈夫面前自处 +``` + +(以上四案例均出自) + +## 触发场景 + +1. 你的人物"该倒霉"但没有具体原因 → 加一个对手 +2. 你的情节靠"巧合"推动 → 把巧合换成"性格碰撞" +3. 你的主角"觉醒"了但没说服力 → 他的对手是什么性格?那个性格决定了他的觉醒路径 +4. 你的悲剧"不悲" → 看看读者是否同情——同情的关键是"性格可识别" +5. 你写"反派人"但他像工具人 → 反派也要有"性格",碰撞才立体 + +() + +## 操作步骤 + +### 步骤 1:定义"主要碰撞" + +列出主角和**最重要的对手 / 环境**: + +```yaml +主角性格:A、B、C 三个特征 +对手性格:X、Y、Z 三个特征 +必然碰撞:主角的 [A] 遇上对手的 [X] → 必然 [事件] +``` + +### 步骤 2:把"巧合"翻译成"性格碰撞" + +| ❌ 巧合 | ✅ 性格碰撞 | +|-------|----------| +| 主角出门撞见坏人在做坏事 | 主角的好奇心(性格)→ 必然去查看 | +| 仇人正好路过 | 主角的某种执念 → 必然相遇 | +| 突然生病 | 主角的某种弱点 → 加上对手的某种利用 | +| 错认了人 | 主角的某种误解倾向(性格)+ 对方的某种特征 | + +**检验**:把这个巧合删掉,主角还会遇到这件事吗? + +- 会的(因为性格)→ 巧合换得好 +- 不会 → 你还有巧合没换 + +### 步骤 3:写"性格速写" + +每个主要人物用 **3-5 个性格词**定义: + +``` +成名:迁讷、善良、无能、坚韧(妻子替他想办法) +里胥:猾黠、贪婪、霸凌 +``` + +**检验**: + +- 删掉一个性格词 → 人物会"不像" → 这个词是关键 +- 加一个性格词 → 人物会"模糊" → 加多了 + +(注意:这 3-5 个性格词是给作者定位用的设计工具,不是写进正文的标签——"性格要通过动作显现,不是形容词",见本条所属常见错误表,以及与 的合并说明 references/detail-mosaic.md"多书合并点"节。) + +### 步骤 4:设计"性格链" + +不是一次碰撞——是**连串碰撞**: + +``` +性格 A 遇性格 X → 事件 1 +事件 1 改变 → 性格 A 暴露新侧面 +新侧面 + 性格 Y → 事件 2 +事件 2 → 性格 A 再暴露 +... +``` + +**林冲的链**: + +- 忍(性格)+ 高俅霸道 → 被陷害 +- 忍 + 路上被欺 → 咬牙忍 +- 忍 + 草料场 → 还在忍 +- 忍 + 听到阴谋 → **忍不了**——爆发 +- 爆发 + 柴进 → 上山 + +### 步骤 5:写"性格判断" + +每个主要人物应该有**一个"判断瞬间"**——读者看到他做这一个动作 / 选择,就能识别他: + +- 成名:听到"迁讷" → 立刻知道这是什么样的人 +- 林冲:被陷害后第一反应是"忍" → 立刻知道 +- 哈代苔丝:失贞后依然要"诚实" → 立刻知道 + +**检验**:你的主角有这样一个"判断瞬间"吗? + +(以上步骤均出自) + +## 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 性格太"模糊"(既 A 又 B 又 C) | 读者抓不住 | 3-5 个核心性格,且要有"主要矛盾" | +| 反派性格太"扁平" | 假 | 反派也要有"性格即命运" | +| 性格没碰撞只"遭遇" | 假 | 强调"碰撞"——是性格之间的化学反应 | +| 把"性格"等于"标签" | 假 | 性格要通过动作显现,不是形容词 | + +() + +## 适用边界 + +- **适合**:所有虚构叙事(小说、剧本、电影) +- **慎用**:群像小说(需要多对碰撞) +- **不适用**:纯意识流、纯抒情(它们靠情绪,不靠碰撞) + +() + +## 一句话总结 + +> **不要让你的主人公"倒霉",让他的"特定性格"遇到"另一个特定性格"——命运自己会来。** + +() + +## 跨 skill 链接 + +- 与 `bifeiyu-shakespeare` 同源:性格 + 现实的逻辑推演。(bifeiyu-shakespeare 归综合 skill theme-and-stance) +- 与 `bifeiyu-anti-norm` 关联:反常动作是"性格即命运"的爆发点。(同在本包,见 references/abnormal-moment.md) +- 与 `bifeiyu-base-temp` 配合:性格的"基础体温"是性格的色彩。(bifeiyu-base-temp 归综合 skill prose-craft) +- 与 `bifeiyu-mercy-ruth` 配合:作家要"心慈手狠"才能让性格碰撞产生必然命运——不能因心软去救人物。(bifeiyu-mercy-ruth 归综合 skill theme-and-stance) + +(;综合 skill 归属标注为本次合并所加) diff --git a/framework/catalog/pi/skills/character-presentation/references/detail-mosaic.md b/framework/catalog/pi/skills/character-presentation/references/detail-mosaic.md new file mode 100644 index 0000000..2c4a096 --- /dev/null +++ b/framework/catalog/pi/skills/character-presentation/references/detail-mosaic.md @@ -0,0 +1,139 @@ +# 细节马赛克:用具体物装配人物 + +## 原文摘录 + +> Hairstyle: slicked-back. Facial features: winking black eyes, big round jaw. Speech patterns: +> tough talk in a New Jersey accent. Mannerisms: buffed nails. Habits: gun strapped to ankle. +> Tastes: scotch and water with a twist... Brand labels: Chivas Regal. Jewelry: thick pinky ring. +> +> — Roy Peter Clark, *Writing Tools* (Tool 54, 引用 Lawrence Wright《The Looming Tower》) + +这是 Clark 引用的标杆登场段:FBI 反恐主管 John O'Neill 完全由一组物质细节拼成,全程没有一个性格形容词。 + +## 方法规则 + +### 把 Tom Wolfe 的"身份细节"扩展成"细节马赛克" + +Clark 把 Tom Wolfe 的 **status details**(身份细节)概念**扩展**为**细节马赛克**:把人物当作**一组可枚举的细节类别**来搭建。 + +### 10+ 维度 + +- 发型 / 面部 / 口音 +- 姿态 / 习惯 / 口味 +- 品牌 / 首饰 / 服饰 / 鞋履 +- 步态 / 视线 / 与孩子 / 仆人的互动方式 + +### 核心规则 + +**精心选择 5-9 个具体到感官的细节,让读者自己合成"完整的人"。** + +判断标准:这一组细节是"反推"出人物性格(读者主动建构),还是"宣告"出人物性格(作者直接告知)? + +### 关键洞见 + +- **不是穷举——是"挑选"**。Clark 警告:把所有细节都写下来是糟糕的写作。**挑最揭示内在张力的 5-9 个**。 +- **替代抽象形容词**("勇敢"、"热情"、"冷酷")——这些是"失败的告诉"。 +- **每个细节都是 1 个"反推钩子"**——读者从"slicked-back 发型"反推"爱面子",从"踝部枪"反推"危险职业"。 +- **配合 Tool 27**——配合"不要用性格形容词"使用。(show-don't-tell 的原则本体归综合 skill show-and-omission,此处只取它落到人物细节上的操作。) + +这是**装配框架**:把人物当作有清单的待建物体来搭建。 + +## 案例全文 + +### 案例 1:Lawrence Wright《The Looming Tower》— John O'Neill 登场 + +- **问题**:写 FBI 反恐主管 O'Neill 登场,如何让读者 200 字内"看见"他? +- **方法论的使用**:Wright 用 9 个物质细节类别(发型 / 面容 / 口音 / 姿态 / 习惯 / 品味 / 品牌 / 首饰)搭建 O'Neill——slicked-back 发型,wink 黑眼睛,NJ 口音,磨光指甲,踝部枪,芝华士 + 柠檬,厚粉红戒指。 +- **结论**:**没有任何"勇敢""果断"等性格形容词**——读者从细节"反推"出"这是一个警觉、危险、有品味"的人。 +- **结果**:成为了"细节马赛克"的标杆案例;展示了"少形容词 + 多具体物"的力量。 + +### 案例 2:Christopher Scanlan 报道 Belva Kent 家门口的电灯开关 + +- **问题**:写谋杀案受害者家庭,如何"显示"悲伤而不直说? +- **方法论的使用**:Scanlan 在采访中,发现 Belva Kent 门口电灯开关上贴了一条胶带——"Deb never came home"。一条胶带 = 11 年的等待 = 全家的悲伤。 +- **结论**:**一个具体物件 > 一吨形容词**。Clark 的"狗的名字"工具的金案例:**好奇心(不是想象力)**发现了伟大细节。 +- **结果**:成为了 Poynter Institute 教学经典案例;证明"具体物件的揭示力"。 + +## 操作步骤 + +1. **列出 10 维度清单** + - 完成标准:从 10 维度(发型、面容、口音、姿态、习惯、口味、品牌、首饰、服饰、步态)中挑出 5-9 个。 + - 判停条件:不要 10 维度都写;Clark 警告穷举 = 糟糕写作。 +2. **每个细节问"反推什么"** + - 对每个细节,问"读者能反推出什么性格 / 阶层 / 心理?" + - 完成标准:每个细节对应 1 个具体的"反推结果"。 + - 判停条件:如果反推不出,换细节。 +3. **替换抽象形容词** + - 在人物段落中,把所有抽象性格形容词(勇敢、热情、冷酷、聪明等)替换为 1-2 个具体细节。 + - 完成标准:人物段落中,抽象性格形容词 ≤ 2 个,且有具体细节支撑。 +4. **(可选)Clark 检验:删去一个细节,看是否人物变轻** + - 检验"每个细节是否必要"。Clark 配套 Chekhov 之枪的反向——若删去后人物"变轻" = 必要;若删去后无感 = 删掉。 + +## 多书合并点:不宣告,让读者反推 + +"不宣告人物性格,让读者自己反推"是多本书里同一个方法点,落地层面不同,各家视角都保留: + +- **细节马赛克**:词句层面的操作——把所有抽象性格形容词(勇敢、热情、冷酷、聪明)替换为 1-2 个具体细节;抽象形容词是"失败的告诉"。 +- **关系网**:场景层面的操作——不写"他是个 X 的人",写他和另一个人的关系;人物怎么说话 > 人物自己说"我是 X 的人"。 + + > ❌ 错误写法:"王熙凤是个精明能干的女人。" + > ✅ 正确写法:"王熙凤笑道:'你们请我来做什么?有什么好东西孝敬我,就快供上来,我还有事呢。'" + +- **性格即命运**:设计层面的纪律——把"性格"等于"标签"是常见错误,"性格要通过动作显现,不是形容词"。 + +分工:Clark 管段落里形容词的替换;毕飞宇管用关系、对话、动作替换自我介绍;"性格即命运"的"3-5 个性格词"是给作者定位用的设计工具(见 references/character-collision.md),不是写进正文的标签。(本节为合并整合说明。) + +## 失败模式(作者警告) + +- **"完整清单"陷阱**:失败模式是写"完整 10 维度"——发型 + 面部 + 口音 + 姿态 + 习惯 + 口味 + 品牌 + 首饰 + 服饰 + 步态全部。信号:人物登场段像表格。机制:作者误把"装配框架"当"穷举清单"。预警:超过 9 个细节,停下来精选。 +- **"宣告式形容词"反扑**:失败模式是用了 5 个具体细节,但还在最后说"他是个勇敢的人"。信号:"形容词 + 细节"组合。机制:作者"不放心"读者反推,想再补一刀。预警:Clark 的核心——删掉所有抽象形容词,只留具体细节。 +- **"细节无张力"**:失败模式是选了 9 个细节但全是"中性"的——白衬衫、棕发、白鞋。信号:读者读完不知道"这是谁"。机制:作者没挑"最揭示内在张力"的细节,挑了"最容易观察"的。预警:Clark 检验——"删去一个细节,看人物是否变轻"——若变轻,必要;若不变,换掉。 + +## 边界:不要在以下情况使用 + +- **心理独白为主的小说**——如意识流 / 内心独白,人物通过"想法"而非"细节"显示。 +- **极简主义文学**——故意少细节(海明威冰山理论),过度装配反而破坏。 +- **抽象哲学小说**——人物是"思想载体",不需要物质细节。 +- **儿童文学的某些情况**——儿童角色可能不需要 status details。 + +## 中文适配 + +Clark 的 10 维度基于英语社会,中文写作者需要**本地化调整**: + +- **发型**:中文小说需要关注"发型 + 头面 + 头饰"(如头簪、刘海、长辫等) +- **服饰**:中文需要"上衣 / 下装 / 鞋履"区分,以及"面料"(丝绸 / 棉布 / 麻) +- **首饰**:中文有"玉 / 银 / 翡翠 / 木"等独特材质 +- **品牌**:中文社会"品牌"概念在 1980 年代后才普及;传统小说用"家当"或"身份标志"(官服 / 长衫 / 中山装) +- **行为细节**:中文"用餐 / 茶 / 酒 / 待客"是阶层显示的关键 + +中文写作补充的本地维度一句话版:**家当与身份标志、服饰面料、玉石材质、茶酒待客**。(中文适配) + +**时代局限**:Clark 写于 2006 年(英文版),网文 / 直播 / 短视频时代的"人物设定"需要新维度(如"人设标签 / 表情包 / 流行语")。(中文适配) + +### 中文落地说明 + +方法本身可直接搬到中文:反推钩子靠的是读者的社会认知,中文读者对"家当、官服、面料、待客方式"的反推习惯比对品牌更熟练。选细节时优先选中文读者能立刻反推的文化符号(什么品级的官服、什么面料、怎么斟茶让座),而不是堆没翻译的外国品牌。网文主角人设可以借用"人设标签"新维度,但落地时仍要走反推检验:标签本身是宣告,标签背后的具体行为细节才是马赛克。 + +## 激活场景与语言信号 + +用户会在什么情境下需要这个方法: + +1. 写完人物登场段后觉得"读起来像'性格形容词清单'"——用了勇敢、热情、冷酷、聪明等抽象词。 +2. 网文主角第一章登场,但读者记不住他长什么样、什么气质。 +3. 写次要人物只有 200 字登场空间,不知道怎么让读者记住。 +4. 写群像 / 阶层 / 权力场景,需要快速"定位"每个人的社会位置。 +5. 写人物对话但人物之间没有差异——读完分不清谁在说话。 + +语言信号:"细节马赛克" / "mosaic of detail";"人物立体" / "人物脸谱化";"如何显示人物" / "show not tell";"性格形容词" / "形容词清单";"status details" / "Tom Wolfe";"网文主角人设" / "登场段";"次要人物怎么写";"群像怎么写" / "阶层怎么显示"。 + +## 与邻近方法的区分 + +- 与 **"show, don't tell"(Tool 27)** 的区别:那个是更大的原则(用动作和细节显示而非直说),这个是具体的"细节装配"操作。show-don't-tell 是 what,细节马赛克是 how。(show-don't-tell 本体归综合 skill show-and-omission。) +- 与 `archetype-toolkit` 的区别:那个是"叙事母题层"(原型),这个是"叙事内容层"(具体物)。原型是骨架,细节是肉。(archetype-toolkit 归综合 skill character-design。) +- 与 `dialogue-as-action` 的区别:那个是"用对话显示人物"(声音语言),这个是"用物品显示人物"(物品语言)。前者是动词,后者是名词。(dialogue-as-action 归综合 skill dialogue-craft。) +- 与 `voice-equalizer` 的区别:那个是"作者声音的杠杆"(宏观),这个是"人物声音的细节"(微观)。前者是叙述者,后者是被叙述者。(voice-equalizer 归综合 skill prose-craft。) +- 组合关系:`dialogue-as-action`(物品语言 + 声音语言),`voice-equalizer`(细节的语言风格统一)——细节马赛克与对话动作配合,物品语言加声音语言合成完整的人物呈现;细节的语言风格统一则与声音均衡器配合完成。 + +## 张力标注:外在细节 vs 内在可见 + +细节马赛克用外在物质细节解决"人物显示";福斯特从另一面提醒:外在细节丰富 ≠ 人物被写透,误把"细节多"当"作者了然"是"小楼误为大廈"的失败模式。两者分工不冲突:细节马赛克管登场层和读者的第一层反推,隐秘生活可见性管深度层。见 references/visible-private-life.md"张力标注"节。(本节为合并整合说明。) diff --git a/framework/catalog/pi/skills/character-presentation/references/presentation-checklist.md b/framework/catalog/pi/skills/character-presentation/references/presentation-checklist.md new file mode 100644 index 0000000..035f879 --- /dev/null +++ b/framework/catalog/pi/skills/character-presentation/references/presentation-checklist.md @@ -0,0 +1,124 @@ +# 人物呈现自查台账 + +用法:设计或修改一个人物时从 1 到 7 顺着填。每节有"过关线",达标进下一节,不达标按标注回退。判断标准全部来自本包 references/ 各文件,这里只是填写骨架;方法细节、案例与引文见各节标注的落点。 + +--- + +## 1. 登场细节装配(→ references/detail-mosaic.md) + +人物:____ 登场可用篇幅:____ 字 + +候选细节(先从 10 维度 + 中文本地维度列 9-12 个,再精选到 5-9 个;中文本地维度:家当与身份标志、服饰面料、玉石材质、茶酒待客): + +| # | 细节 | 所属维度 | 读者反推出什么(性格/阶层/心理) | 留/删 | +|---|------|---------|------------------------------|------| +| 1 | | | | | +| 2 | | | | | +| 3 | | | | | +| 4 | | | | | +| 5 | | | | | +| 6 | | | | | +| 7 | | | | | +| 8 | | | | | +| 9 | | | | | + +段落里的抽象性格形容词清单(勇敢、冷酷、精明能干……):____,每个换成 1-2 个具体细节:____ + +Clark 检验:逐个删一遍,删掉后人物变轻的留下,无感的删掉。 + +过关线:最终 5-9 个细节;每个都反推得出东西;抽象性格形容词 ≤ 2 个且有细节支撑;登场段不像表格。超过 9 个细节 = 回退精选。反推不出的细节 = 换掉。 + +## 2. 内在可见自查(→ references/visible-private-life.md) + +- 人物历史的一面(可观察行为)够吗:□ 够 □ 不够 +- 人物虚构的一面写了哪样(感情 / 幻想 / 喜悦悲伤 / 出于礼貌或羞愧没说出口的话):____ +- 我对这个人物了如指掌吗(说不出口的心里话、独处时的样子,我答得上来吗):□ 答得上 □ 答不上 → 先补人物功课 +- 指出至少一段让读者看到隐秘生活的段落:第____章第____段 + +过关线:能指出一段"现实中看不到的清晰"。只见外部细节堆叠 = 小楼误为大廈,回退补虚构的一面。可见性若走向预言式"我和所有人"的神异,转 novel-diagnosis 的 fantasy-prophecy-twin 测试。 + +## 3. 关系网台账(→ references/relationship-web.md) + +人物:____ + +| 关系 | 对方 | 关系类型 | 显示人物什么侧面 | 推动什么情节 | +|-----|------|---------|----------------|------------| +| 1 | | | | | +| 2 | | | | | +| 3 | | | | | +| 4 | | | | | +| 5 | | | | | + +三项检查: + +- 至少列得出 3 重?□ 是 □ 否 → 人物不立体,先设计关系再动笔 +- 同一人物在每重关系里反应不同(对比)?□ 是 □ 都是同一种反应 = 关系没设计 +- 每重关系都推动情节?□ 是 □ 有装饰关系 → 删或改 + +隐藏关系:有没有一条"读者知道但人物不知道"的关系?□ 有:____ □ 没有 → 加一条,并提前留"飞白"暗示。 + +群像互换检验(群像才填):把两个主要人物的关系网对调还能用吗?□ 不能(到位) □ 能(没设计好) + +## 4. 碰撞设计(→ references/character-collision.md) + +主角性格词(3-5 个):____;删掉一个词人物还像吗?□ 不像(词关键) □ 还像(删) +对手性格词(3-5 个):____ + +必然碰撞公式:主角的 [____] 遇上对手的 [____] → 必然 [____] + +巧合逐条翻译: + +| 原稿里的巧合 | 翻译成性格碰撞 | 删掉巧合后凭性格还会遇到吗 | +|------------|--------------|------------------------| +| | | □ 会(换得好)□ 不会(还有巧合没换) | +| | | □ 会 □ 不会 | + +性格链:性格 A 遇性格 X → 事件 1 → 暴露新侧面 → 新侧面遇性格 Y → 事件 2 → …… → 爆发 + +判断瞬间:读者看到主角做哪一个动作 / 选择就能认出他:____(写不出 = 回第 3 步) + +过关线:反派也有性格词(没有 = 工具人,碰撞立不住)。 + +## 5. 反常设计(→ references/abnormal-moment.md) + +人物按身份该有的常态: + +1. ____ +2. ____ +3. ____ + +反常清单(短篇 1-2 个,长篇排递进链 3-5 个,每个标驱动源): + +| # | 反常瞬间 | 驱动源(人物选择的反常→揭示性格 / 情境的反常→推动情节) | 落实的具体动作或对话(禁形容词) | 改变了人物/情节/关系的什么 | +|---|---------|--------------------------------------------------|------------------------------|--------------------------| +| 1 | | | | | +| 2 | | | | | +| 3 | | | | | + +事后解释检验(不写解释,只验读者反应预期):□ 原来如此(成) □ 莫名其妙(没设计好) □ 早猜到了(太露) + +过关线:每个反常前都有常态铺垫;每个反常都有后果;反常是性格驱动不是作者安排。 + +## 6. 声音检查(过程发现 → references/voice-discovery-process.md;技术修法 → dialogue-craft) + +1. 遮住名字读对话,分得出谁在说话吗?□ 分得出 □ 分不出 → 交 `dialogue-craft`(句长/口头禅/同一声音诊断) +2. 大声朗读,听着自然吗?□ 自然 □ 别扭 +3. 拿不准人物会不会说这句话?□ 拿得准 □ 拿不准 = 还不够了解人物 → 补人物小传 / 对话练习,或继续写、与人物相处足够久(过程发现) +4. 长篇里人物开始说计划外的话:先记录再取舍,不硬拉回大纲。□ +5. 通篇对话的长篇才查:每段对话是否同时承担人物发言 + 叙述推进?有没有节奏感和旋律感(对话成为叙述、叙述成为对话)?□ → 技术侧见 `dialogue-craft` + +老农民检验:身份最低的人物开口,腔调对吗?(老农民不能说大学教授的话)→ 不合格则交 `dialogue-craft` + +## 7. 总判断标准 + +| 标准 | 过关信号 | 出处 | +|------|---------|------| +| 真实 | 作者对人物了如指掌,而不是人物像现实某人 | references/visible-private-life.md | +| 细节必要 | 删掉一个,人物变轻 | references/detail-mosaic.md | +| 性格词准确 | 删一词不像,加一词模糊 | references/character-collision.md | +| 碰撞成立 | 删掉巧合,凭性格照样遇到 | references/character-collision.md | +| 关系立体 | 至少三重关系,反应各不同,都推动情节 | references/relationship-web.md | +| 反常有戏 | 常态铺垫 + 具体动作 + 有后果 + 不解释 | references/abnormal-moment.md | +| 声音区分 | 遮住名字也分得出谁在说话 | dialogue-craft/references/character-voice.md | + +全部过关 = 人物能被读者自己看见。任何一项不过,回对应小节。 diff --git a/framework/catalog/pi/skills/character-presentation/references/relationship-web.md b/framework/catalog/pi/skills/character-presentation/references/relationship-web.md new file mode 100644 index 0000000..6f365e3 --- /dev/null +++ b/framework/catalog/pi/skills/character-presentation/references/relationship-web.md @@ -0,0 +1,228 @@ +# 关系即人物:通过关系网显性格 + +来源:(毕飞宇《小说课》第 6 讲,案例取自《红楼梦》王熙凤和秦可卿 / 整本书) + +> 「人物性格不在人物的自我描述里,在人物与人物的关系里。」 + +## 原文摘录 + +《红楼梦》里王熙凤和秦可卿的关系: + +- 字面:闺蜜 +- 字面下:和王熙凤和贾蓉的暧昧有关 +- 反逻辑:秦可卿死后,王熙凤和贾蓉都"消失"了 + +**王熙凤的全部复杂性**——通过她和**5 个人**的关系显出来: + +``` +王熙凤 - 贾瑞:被调戏 → 毒设相思局 → 杀 +王熙凤 - 秦可卿:闺蜜 → 但有隐藏关系 +王熙凤 - 贾蓉:暧昧 → 隐藏 +王熙凤 - 尤氏:嫂子 → 但互相嘲讽 +王熙凤 - 贾宝玉:嬉笑怒骂 → 玩伴 +``` + +**每一个关系都是王熙凤的一个侧面**。**5 个关系 = 5 个王熙凤**。 + +() + +## 方法规则 + +**人物不在"自我介绍"里,在"他和别人的关系"里。** + +> "他是谁?"这个问题,**不能问他自己,要问他的"关系网"**。 + +**核心原则**: + +1. **不写"他是个 X 的人"——写他和另一个人的关系** +2. **每个人的性格在他和不同人的关系中显示不同侧面** +3. **关系越复杂,人物越立体** +4. **隐藏关系 = 戏的来源** + +() + +## 案例全文 + +### 案例 1:曹雪芹 王熙凤的 5 重关系 + +- 闺蜜关系(秦可卿) +- 暧昧关系(贾蓉) +- 嫂子关系(尤氏) +- 玩伴关系(贾宝玉) +- 上下关系(贾瑞) + +**5 个关系 = 5 个王熙凤 = 立体人物**。 + +### 案例 2:施耐庵 林冲的 5 重关系 + +- 夫妻(林娘子) +- 同事 / 技术关系(高俅) +- 兄弟(鲁智深) +- 仇人(高衙内、陆谦) +- 同志(柴进) + +**5 个关系 = 5 个林冲 = 立体人物**。 + +### 案例 3:海明威《杀手》5 个男人 + +- 阿尔 + 马克斯(同事杀手) +- 阿尔 / 马克斯 + 乔治(压迫者 vs 服务员) +- 阿尔 / 马克斯 + 尼克(威胁者 vs 旁观者) +- 阿尔 / 马克斯 + 萨姆(威胁者 vs 后厨) + +**5 个关系网 = 5 个性格的碰撞 = 整个故事的势**。 + +### 案例 4:哈代《苔丝》3 重关系 + +- 苔丝 + 亚雷(阶级关系 / 失贞) +- 苔丝 + 克莱尔(爱情 / 真相) +- 苔丝 + 家庭(生存压力) + +**3 个关系 = 3 个苔丝 = 立体悲剧**。 + +(以上四案例均出自) + +## 操作步骤 + +### 步骤 1:列"人物关系网" + +```yaml +人物:[主角] +关系 1:[关系类型] - [对方人物] - [显示什么性格] +关系 2:[关系类型] - [对方人物] - [显示什么性格] +关系 3:[关系类型] - [对方人物] - [显示什么性格] +``` + +**检验**: + +- 列得出 3 个关系吗?→ 人物可写 +- 列不出 → 人物不立体,需要先设计关系 + +### 步骤 2:关系要"对比" + +**不同关系显示不同侧面**: + +```yaml +林冲 - 林娘子:温柔(家) +林冲 - 高俅:忍(职场) +林冲 - 鲁智深:义(兄弟) +林冲 - 陆谦:仇(仇人) +``` + +**检验**:你的主角在不同关系中是不是"不同的人"? + +- 都是同一种反应 → 关系没设计 +- 不同反应 → 关系到位 + +### 步骤 3:关系要"推动" + +**关系要推动情节**——不只是"展示": + +```yaml +林冲 - 高俅(仇)→ 推动:被陷害 +林冲 - 鲁智深(义)→ 推动:救他 +林冲 - 柴进(同志)→ 推动:上梁山 +``` + +**检验**: + +- 列出的关系都推动了情节?→ 关系到位 +- 有些关系只是"装饰"?→ 删或改 + +### 步骤 4:用"关系"代替"自我介绍" + +**❌ 错误写法**: + +> "王熙凤是个精明能干的女人。" + +**✅ 正确写法**: + +> "王熙凤笑道:'你们请我来做什么?有什么好东西孝敬我,就快供上来,我还有事呢。'" + +**人物怎么说话 > 人物自己说"我是 X 的人"**。 + +**检验**: + +- 你的主角有没有"自我介绍"?→ ❌ 删 +- 用对话 / 动作 / 关系显示 → ✅ 留 + +(本步骤与 的"替换抽象形容词"、 的"性格不是标签"是同一方法点,两本书三个源单元合并见 references/detail-mosaic.md"多书合并点"节,此处原文全量保留。) + +### 步骤 5:设计"隐藏关系" + +**戏的来源 = 隐藏关系**: + +```yaml +表面:闺蜜 +实际:和王熙凤和贾蓉的暧昧相关 +→ 戏:秦可卿死后的反逻辑 +``` + +**检验**:你的小说里有没有一个"读者知道但人物不知道"的隐藏关系? + +- 有 → 戏足 +- 没有 → 加一个 + +### 步骤 6:群像的"关系区分" + +每个主要人物的关系网要**独特**: + +``` +林冲:家-职场-江湖 +鲁智深:佛-江湖-兄弟 +武松:兄-官-江湖 +``` + +**3 个人的关系网几乎不重叠** = 群像立体。 + +**检验**:把两个主要人物的关系网互换——还能用吗? + +- 能 → 没设计好 +- 不能 → 设计到位 + +(以上步骤均出自) + +## 触发场景 + +1. 你的人物"自我描述太多" → 改用关系显性格 +2. 你的人物"平面" → 加多重关系 +3. 你想"藏秘密" → 隐藏关系是最好方式 +4. 你想"立体人物" → 给他至少 3 重关系 +5. 你的群像"区分不开" → 每个人物的关系网要独特 + +() + +## 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 自我描述太多 | 假 | 用对话 / 动作 / 关系显示 | +| 关系太单一 | 平面 | 至少 3 重关系 | +| 关系没推动 | 装饰 | 每个关系都要推动情节 | +| 关系太相似 | 群像不分 | 每个人物关系网独特 | +| 隐藏关系没暗示 | 突兀 | 隐藏关系要有"飞白" | + +(;"飞白"的展开归综合 skill show-and-omission 的 bifeiyu-anti-logic,此处只留原话。) + +## 适用边界 + +- **适合**:所有虚构叙事 +- **特别适合**长篇 / 多线叙事 +- **慎用**:独角戏(人物少到 1-2 个,关系网要"纵向深挖") + +() + +## 一句话总结 + +> **人物不在"我是 X 的人"里,在"我和 Y 的关系"里。** + +() + +## 跨 skill 链接 + +- 与 `bifeiyu-character-fate` 同源:关系 = 性格碰撞的载体。(同在本包,见 references/character-collision.md) +- 与 `bifeiyu-anti-logic` 配合:隐藏关系 = 反逻辑的来源。(bifeiyu-anti-logic 归综合 skill show-and-omission) +- 与 `bifeiyu-perspective` 配合:多视角看同一关系 = 立体人物。(bifeiyu-perspective 归综合 skill narration-pov) +- 与 `bifeiyu-system` 配合:短篇人物少,关系要"集中";长篇人物多,关系要"网状"。(bifeiyu-system 归综合 skill story-structure) + +(;综合 skill 归属标注为本次合并所加) diff --git a/framework/catalog/pi/skills/character-presentation/references/visible-private-life.md b/framework/catalog/pi/skills/character-presentation/references/visible-private-life.md new file mode 100644 index 0000000..4d3d356 --- /dev/null +++ b/framework/catalog/pi/skills/character-presentation/references/visible-private-life.md @@ -0,0 +1,143 @@ +# 隐秘生活可见性:人物的"真实"是作者对其了如指掌 + +## 原文摘录 + +> "一旦剥离人际往来的社会属性, 单纯审视其本身, 事情就会变得好像幽魂缠身一般。我们无法彼此理解, 除非接受那种约定俗成而又粗略含糊的方式 …… 我们所谓'完美的认知'不过是幻象。小说中则不同, 我们不但可以彻底了解他人, 还可以 …… 找到各自生活的补偿。就这一点而言, 小说比历史更加真实, 因为它超越了对证据的需索。" + +> "小说能够抚慰人心, 哪怕主角是恶人也不例外, 原因就在这里: 它们暗示了一种更易于理解, 甚而更加有序、更加可控的人类的存在, 它们为我们打造了有关洞察力与力量的幻象。" + +> — E. M. 福斯特, 《小说面面观》第三讲 人物 + +## 方法规则 + +### 小说与现实人的本体论差异 + +现实人彼此的内心"不可见"(我们只能通过外在行为推测,"我们永远不可能完全了解其他人");小说人物"隐秘的内在人生是可见的",是叙述者与创造者合二为一的世界。() + +### 核心操作五条 + +1. **承认"我们无法彼此完全理解"**——现实人之间,即使最亲密的关系,也存在"我们永远不可能完全了解其他人"的本体论限制。我们的认知是"约定俗成而又粗略含糊的","完美的认知不过是幻象"。 +2. **小说 / 虚构给予"可见性"特权**——小说人物"隐秘的内在人生是可见的",因为作者对人物"了如指掌"。**判断"真实"不是"像我们",而是"作者对其了如指掌"**。 +3. **小说比历史更真实**——不是因为虚构,是因为"它超越了对证据的需索"。在小说里,我们可以"彻底了解他人",而在现实里,我们只能"约定俗成地"了解。 +4. **"可见性"是小说抚慰人心的原因**——小说"暗示了一种更易于理解,甚而更加有序、更加可控的人类的存在","为我们打造了有关洞察力与力量的幻象"。这是虚构 / 想象的合法理由,不是缺陷。 +5. **阿兰的"两面性"作为延伸**——人物 = 历史的一面(可观察行为)+ 虚构 / 浪漫的一面(纯粹的感情、幻想、喜悦、悲伤,还有出于礼貌或羞愧而没能启齿的心里话)。优秀小说必须深入"那一面"——"小说中没有天意,在这里,一切都能归结于人性"。 + +### 判断标准 + +判断"真实"不是"像我们",而是"作者对其了如指掌"。当我们说"X 写的人物真实",我们不是说"X 的人物像我",我们是说"X 的人物让我看到了一种现实给不了的可见性"。 + +**关键认识**:小说人物的"可见性"是**对真实人的渴望**的补偿,不是对真实人的**模仿**。() + +## 案例全文 + +### 案例 1:摩尔·弗兰德斯——圆形的极端(孤树型) + +- **问题**:摩尔·弗兰德斯"方方面面"都"合乎日常生活",但"我们还是无法在现实中找到这样一个完整的人物" +- **方法论的使用**:福斯特诊断——这是因为摩尔"在小说里"是**作者了然于心的存在**,而现实中的人不可能"被作者了然" +- **结论**:摩尔比真实人更"真实"(在福斯特的意义上),因为她的"隐秘生活可见" +- **结果**:借此福斯特给出"真实"的反直觉定义——"作者对其了如指掌"才是真实 + +### 案例 2:维多利亚女王——真实人物的"消解" + +- **问题**:如果维多利亚女王一模一样地进了小说,她就不再是维多利亚女王了 +- **方法论的使用**:福斯特诊断——"如果一个小说角色和维多利亚女王一模一样——不是多多少少有些像,而是一模一样——那么,她就是维多利亚女王本人了,这部小说,以及与这个角色相关的一切就变成了人物传记"。小说与传记 / 历史不同 +- **结论**:小说人物不模仿现实,小说人物"提供可见性" +- **结果**:借此福斯特划出"小说" vs "传记" vs "历史"的本体论边界 + +### 案例 3:海蒂 vs 米嘉(《卡拉马佐夫兄弟》) + +- **问题**:海蒂和米嘉都"忏悔自己的罪行",但为什么米嘉更深? +- **方法论的使用**:福斯特诊断——海蒂"只靠她自己便已足够成立",米嘉"单靠他自身是不足以成立的"。米嘉是"预言之中的幻象,也是小说家的造物",他代表了"某种半切身的感觉,就像沉入一个半透明的球体里,眼看着我们的经历远远地漂浮在我们头顶的球体表面上" +- **结论**:米嘉的"隐秘生活可见"是另一种——他代表了我们所有人的可能,是"圆形 + 预言"的极限 +- **结果**:借此福斯特说明,小说可见性有不同的"层次"——人物可见 vs 人物代表的人性可见 + +## 可见性的层次(判断标准延伸) + +- **基础层:人物可见**——这个人物被写透了(摩尔·弗兰德斯):人物真实但限于自己。 +- **更高层:人物代表的人性可见**——人物代表更广的可能性(米嘉):人物代表了我们所有人的可能。 + +## 操作步骤 + +1. **承认"我们无法彼此完全理解"** + - 完成标准:明确说出"现实中的人彼此不可见,我们只能'约定俗成'地了解" +2. **诊断虚构 / 想象的可见性** + - 完成标准:评估"X 是否提供了一种现实给不了但人渴望的可见性" + - 至少 1 个具体征兆:"X 在 Y 段落中让我看到了人物的内在,我在现实中看不到这种清晰" +3. **判断可见性的"层次"** + - 完成标准:区分"人物可见"(摩尔·弗兰德斯)vs"人物代表的人性可见"(米嘉) + - 前者:人物真实但限于自己;后者:人物代表更广的可能性 +4. **评估可见性的边界** + - 完成标准:明确说"X 提供的可见性是否会变成'神异'(如预言式的'我和所有人')",如果是,走 `fantasy-prophecy-twin` 测试(归综合 skill novel-diagnosis) + - 不要混用:可见性(作者了然)vs 神异(作者召唤) +5. **给出诊断 / 修改建议** + - 完成标准:至少 1 条具体修改(如"在 X 段加入人物的内在独白,让读者看到他们的隐秘生活"或"承认'我们其实看不见对方',不要假装小说可以替代心理学") + - 不要空话(如"让人物更立体")——给可操作修改 + +## 失败模式(作者警告) + +- **"模仿真实人"的错误**——把维多利亚女王硬塞进小说,真实人物消解虚构(ce04) +- **"小楼"误为大廈**——误把"细节丰富"当"作者了然"(c04:四本"小楼"小说 vs 托尔斯泰"大廈") +- **以可见性为借口逃避证据**——把"作者了然"当成"作者全能",失去对真实的尊重 +- **预设作者 / 读者的特权立场**——假设"我能'看到'你",是侵犯性的 + +## 作者的盲点 / 时代局限 + +- **1927 年的视角**——没看到 60 年代后的"不可靠叙述者"(Unreliable Narrator,纳博科夫《洛丽塔》、品钦)对"作者了然"的颠覆 +- **对"作者了然"过于乐观**——现代叙事学认为"作者"也是建构的,不可靠叙述者本身就说明"作者不一定比读者更了然" +- **西方文学中心的视角**——中国评书传统中"说书人可见"是合法手法,西方小说中不一定;福斯特未充分讨论跨文化差异 + +## 中文适配 + +- 福斯特中译本可直接用于中文小说评估;"作者对其了如指掌"这个标准不依赖语言,中文写作同样适用。 +- **说书人可见**(中文适配):福斯特的"可见性"以 19 世纪西方现实主义全知视角为背景;中国评书与话本传统里,说书人直接点评人物内心("看官听说")也是合法的可见性实现方式。用"可见性"评中文小说时,不必要求可见性一律通过展示实现,说书人式的全知介入同样算"作者了然"的供给,但要检查介入是否给了读者现实给不了的洞察,而不是只给了说教。 +- 中文写作落地:给主要人物补"虚构的一面"时,中文小说可用的手段包括内在独白、梦境、未说出口的话("欲言又止")、独处时的失态;判断标准不变——读者是否看到了现实中看不到的清晰。 + +## 激活场景与语言信号 + +用户会在什么情境下需要这个方法: + +1. **评估小说 / 电影 / 游戏 / 电视剧的"代入感"**——诊断"代入感"是来自人物真实(可见性)还是情节刺激 +2. **评估"品牌人格"**——品牌是否"提供了一种可见性"——让用户感到"被理解" +3. **评估"虚构"在产品 / 服务 / 制度中的作用**——为什么有些虚构(如品牌故事、用户画像)让人感到真实? +4. **评估一个产品 / 服务是否"触及人渴望的洞察力"**——不只是"功能满足",而是"洞察提供" +5. **设计 / 写作时**——检查"我的人物 / 角色是否对'隐秘生活'有可见性的提供" +6. **教学 / 讲课时**——解释"为什么小说比历史更真实"给学生 + +(本包主用途是第 1、5、6 条:评估与写作中的人物可见性;2-4 条为源单元原有的延伸应用,照录保留。) + +语言信号: + +- "X 让我看到了我自己看不到的" +- "X 比现实更真实" +- "X 的人物很立体 / 很丰满" +- "X 给了我洞察" +- "X 让我感到被理解" +- "X 让我知道了我不知道的我" +- "X 写的人 / 设计的角色 / 做的产品,让我觉得'对,就是这样'" +- "X 解释了我说不清楚的东西" +- "X 让我有了'啊哈'的瞬间" + +## 容易混淆的邻近概念 + +- **vs 代入感(Immersion)**——代入感是"我感到我在那里",可见性是"我能看到人物的内在";前者是空间 / 感官,后者是认知 / 洞察 +- **vs 心理现实主义(Psychological Realism)**——心理现实主义是文学流派,可见性是小说 / 虚构的本体论特征 +- **vs 神入(Theory of Mind)**——神入是心理学 / AI 概念,可见性是文学 / 哲学概念 + +## 边界:不要在以下情况使用 + +- **真实人之间的理解**——这是道德和心理学问题,不是文学方法论;"你应该理解我"不是这个方法能解决的 +- **纯信息 / 无人物的产物**——如新闻、菜谱,不需要"人物可见性" +- **科学论文 / 技术文档**——透明性优先,可见性反而是缺陷 +- **法律 / 合同**——文本优先,不要"让我看到你的内在" + +## 与邻近方法的区分 + +- 与 `flat-vs-round-character` 的区别:可见性是**本体论**(作者了然),扁 / 圆是**形式层**(一句话测试)。(flat-vs-round-character 归综合 skill character-design,圆形人物的"出人意料"建立在可见性之上。) +- 与 `fantasy-prophecy-twin` 的区别:可见性是**对真实人的补偿**,幻想 / 预言是**对真实人的超越**。(fantasy-prophecy-twin 归综合 skill novel-diagnosis。) +- 与"同理心(Empathy)"的区别:同理心是"我能理解你",可见性是"我能'看到'你的内在";前者是姿态,后者是特权。 + +(;综合 skill 归属标注为本次合并所加) + +## 张力标注:外在细节堆得多 ≠ 人物被写透 + +细节马赛克(→ references/detail-mosaic.md)用外在物质细节装配人物;福斯特警告的"小楼误为大廈"正是把"细节丰富"误当"作者了然"。两者分工不冲突:细节马赛克管登场层和读者的第一层反推;可见性管深度层——作者了然的内容包括细节列不出的虚构一面(感情、幻想、没说出口的话)。外在细节挑得准,加上内在可见,人物才真正立体。(本节为合并整合说明。) diff --git a/framework/catalog/pi/skills/character-presentation/references/voice-discovery-process.md b/framework/catalog/pi/skills/character-presentation/references/voice-discovery-process.md new file mode 100644 index 0000000..46562b1 --- /dev/null +++ b/framework/catalog/pi/skills/character-presentation/references/voice-discovery-process.md @@ -0,0 +1,67 @@ +# 人物声音发现法:从控制到记录 + +> 说话方式的技术 owner 是 `dialogue-craft` 的 [character-voice.md](../../dialogue-craft/references/character-voice.md)(句长、口头禅、区分诊断)。 +> 本文件只保留**呈现侧**的过程发现:写作者何时从发号施令转为记录人物自己的声音。 + +来源:(余华,《我能否相信自己》(1998) / 演讲 (2014)) + +## 原文摘录 + +> "我写着写着突然发现人物有他们自己的声音, 这是令我惊喜的发现, 而且是在写作过程中发现的。在此之前我不认为人物有自己的声音, 我粗暴地认为人物都是作者意图的符号, 当我发现人物自己的声音以后, 我就不再是一个发号施令的叙述者, 我成为了一个感同身受的记录者, 这样的写作十分美好, 因为我时常能够听到人物自身的发言, 他们自己说出来的话比我要让他们说的更加确切和美妙。" +> +> — 余华, 《我能否相信自己》 + +## 方法规则 + +### 写作者与人物的关系有两个阶段 + +1. **控制阶段**:写作者认为人物是"作者意图的符号",发号施令地让人物说什么、做什么。此时人物僵硬,像传声筒,所有人物一个腔调。 +2. **记录阶段**:写着写着,人物突然有了自己的声音——他们会说写作者没想到的话,会做写作者没计划的事。此时写作者从"发号施令的叙述者"转变为"感同身受的记录者",尊重并记录人物自己的声音。 + +这个转变**发生在写作过程中**,不是预先设计的。通常需要与人物相处足够久(长篇写作中自然发生),人物才会自发产生声音。 + +### 与 dialogue-craft 的分工 + +- **本文件**:过程发现、传声筒诊断、事前设计 vs 过程发现的张力标注。 +- **`dialogue-craft/character-voice.md`**:什么人说什么话、句长/口头禅/遮住名字测试、对话双重功能的技术修法。 + +## 案例全文 + +### 案例 1:余华《在细雨中呼喊》——首次发现人物声音 + +- **问题**:余华早期(八十年代)认为人物是作者意图的符号,粗暴地控制人物。 +- **方法论的使用**:写《在细雨中呼喊》时,写着写着突然发现人物开始出现自己的声音。余华"有些惊奇",但他选择尊重这些声音,而不是强行拉回自己的计划。 +- **结论**:"我尊重他们的声音,结果证明我做对了。" +- **结果**:这是余华从先锋文学转向平易近人叙述的关键转折。 + +### 案例 2:余华《活着》——跨越更高门槛 + +- **问题**:如何写一个没文化的老农民讲述自己的故事? +- **方法论的使用**:《活着》以福贵(老农民)的第一人称讲述,余华在写作过程中与福贵相处足够久,福贵的声音自然产生——一个没文化但经历了一切的老老人的语言。余华不再控制,而是记录。 +- **结论**:"一个没有什么文化的老农民讲述自己的故事,这个写作过程让我跨过了更高的门槛。" +- **结果**:《活着》成为余华最著名的作品,福贵的声音成为其标志性特征。 + +### 案例 3:余华《许三观卖血记》——通篇对话的极致 + +- **问题**:如何写一部通篇用对话完成的长篇小说? +- **方法论的使用**:余华年轻时读乔伊斯《一个青年艺术家的画像》,就有写通篇对话长篇的愿望。写《许三观卖血记》时,开头恰好由对话组成,"机会来了"。他意识到通篇对话的困难:对话有双重功能(人物发言 + 叙述推进),必须有叙述的节奏感和旋律感。他从越剧唱词和台词的关系中得到启发——台词往唱词靠,唱词往台词靠,观众不会觉得别扭。 +- **结论**:"写对话的时候一定要有叙述中的节奏感和旋律感,如何让对话部分和叙述部分融为一体,简单地说如何让对话成为叙述,又让叙述成为对话。" +- **结果**:《许三观卖血记》成为通篇对话长篇的经典,余华"对于写对话不再担心了,想写就写,不想写可以不写"。 + +## 操作步骤 + +1. **评估当前人物状态**:人物是否有自己的语言习惯?不同人物是否可区分?完成标准:明确问题所在。 +2. **放弃控制,进入记录状态**:改为"如果这个人物在这里,他会说什么?"完成标准:写作时倾听而非预设台词。 +3. **与人物相处足够久**:长篇中自然产生;短篇可先做人物小传/对话练习。完成标准:对人物语言模式有直觉。 +4. **执行"什么人说什么话"**:教育/地域/职业/性格决定用词与句长。完成标准:遮住名字也能分辨是谁在说话(技术清单见 `dialogue-craft`)。 +5. **(长篇通篇对话)双重功能**:人物发言 + 叙述推进,节奏与旋律感。完成标准:对话同时在讲故事。 +6. **检验声音真实性**:朗读是否自然?完成标准:对话自然且有辨识度。 + +## 张力标注:事前设计 vs 过程发现 + +毕飞宇的关系网与性格词(见 [relationship-web.md](relationship-web.md)、[character-collision.md](character-collision.md))是动笔前的设计工具;余华的人物声音是写作过程中自然长出来的。两者分工:设计工具管骨架,声音发现管血肉。短篇可先用人物小传提前"熟悉"人物。 + +## 与相邻 skill 的区分 + +- **说话方式技术**:`dialogue-craft` owner,见 [character-voice.md](../../dialogue-craft/references/character-voice.md)。 +- **极端情绪下的身体呈现**:`show-and-omission` owner。 diff --git a/framework/catalog/pi/skills/concept-design/SKILL.md b/framework/catalog/pi/skills/concept-design/SKILL.md new file mode 100644 index 0000000..a3d6c1f --- /dev/null +++ b/framework/catalog/pi/skills/concept-design/SKILL.md @@ -0,0 +1,93 @@ +--- +name: concept-design +description: | + 激活场景:用户手里只有模糊 idea、真实素材或"写了一半散掉"的稿子,还没形成能撑长篇的概念—— + "我想写 X 但不知道够不够"、"我的点子太平"、"题材写烂了,我没新意"、"真实事件想写成小说"、 + "朋友问小说讲什么我答不上来"、"写到一半故事散了"、"教学生怎么从 idea 到 concept"(教学演示)、 + "我有 3 个 idea,哪个最有潜力"(比较选择)、"朋友推荐我写 X,怎么判断值不值得"(第三方评估)、 + "真实人物的真实经历(传记/回忆录)怎么让它有 concept"、"读到一本好书/好新闻,想改写成小说"(非虚构改编)。 + 关键 trigger:"what if / 把 idea 变成 concept / 升级点子 / 故事种子 / premise / 这个点子够不够 / + 这个点子能写成小说吗 / 能撑 30 万字吗 / 哪个 idea 最有潜力 / 题材写烂了 / 我没新意 / 和别人一样 / + 我必须想新点子 / 真实事件写小说 / 历史题材 / 传记 / 回忆录 / 非虚构改编 / 叙事策略 / 通过谁的眼睛讲 / + 故事引擎 / story engine / 核心问题 / 小说在回答什么问题 / 中段失去方向 / 写到一半散了 / 故事没有主心骨"。 + 不适用于:纯抒情散文与反结构实验小说(问题引擎合法缺席);要求严格 1:1 复刻真实的新闻报道; + 概念已定之后的结构诊断(见 story-structure);写作习惯、心理状态等作者培养问题。 + 与 story-planning 交接:用户第一句话只有模糊 idea / 素材 / 引擎不清 → 本 Skill;概念已定、要做节拍表/工作流 → story-planning。 +--- + +# 概念设计(concept-design) + +动笔前先定下"这本书到底在回答什么问题":把模糊 idea 升级成疑问式概念,校验它撑不撑得住长篇,给真实素材找到自己的讲法,再用一个核心问题把整本书驱动起来。 + +## 方法索引 + +按创作动作组织;方法细节、案例、引文都在 references 里,这里只给一句话和指针。 + +### 产生:把"我想写 X"变成概念 + +- idea 是陈述句,concept 是疑问句:用"如果……会怎样"把题材升级成带角色、障碍、赌注的问题 → references/what-if.md +- idea→concept→premise→theme 四级递进,先判断种子到了哪一级 → references/what-if.md +- 写 3-5 个不同角度的疑问句,只挑最有戏剧张力的那一个 → references/what-if.md + +### 校验:这个概念配不配写成长篇 + +- 新鲜、新角度、冲突、可撑长四问校验;至少 3 问 Yes 且"可撑长"必须过 → references/four-questions.md +- 四问不全过也能写:新鲜度失败时用角色、主题、声音当补偿桶 → references/four-questions.md + +### 讲真实素材:真实事件也有概念 + +- 真实事件改不了,但"通过 X 的眼睛看 Y"就是概念,不同视角 = 不同故事 → references/delivery-strategy.md +- 视角人物化、时间结构化、形式实验化、主题聚焦化四种交付策略 → references/delivery-strategy.md +- 先列 ≥5 个候选视角再挑最强的,写成"通过 X 的眼睛,故事变成了 Y" → references/delivery-strategy.md + +### 找角度:"题材写烂了"是假问题 + +- 原创性不是题材新,是诚实:精确说出自己的看法,俗套提纲也能写出新故事 → references/originality.md +- 用信念清单挖角度,用旧题材验证,用目前的信念动笔,不等"想清楚" → references/originality.md + +### 驱动:用一个问题撑住整本书 + +- 主题陈述不是引擎,具体问题才是读者翻页的理由 → references/story-engine.md +- 引擎分答案驱动与过程驱动两类;副线迷你引擎必须服从主引擎 → references/story-engine.md +- 引擎体检:问题一句话说出、逐章推进比例、中段进展密度 → references/story-engine.md + +### 冲突标注 + +- Brooks 四问把"新鲜独特"列为第一关;布兰德主张视角的深度与诚实决定原创、题材不必新。两条规则都保留,见 references/originality.md 的"冲突标注"节。 + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|---------| +| references/what-if.md | 疑问句升级法、四级递进、芭蕾舞者/可爱的骨头/冰球队案例、失败模式与盲点、中文适配 | +| references/four-questions.md | 四问校验与记分标准、The Closers/Cold Mountain 案例、双向用法、失败模式、中文适配 | +| references/delivery-strategy.md | 真实素材四种交付策略、五步视角选择、Miracle/可爱的骨头/Collateral 案例、失败模式、中文适配 | +| references/originality.md | 原创性 = 诚实、信念清单、24 学生课堂/华顿/海明威案例、不等最后智慧、与 Brooks 新鲜度的冲突标注、与原书裁剪相邻方法的区分注记 | +| references/story-engine.md | 引擎三层概念、两类引擎、Kansas/Rosebud/Baby No. 81 案例、逐章与中段诊断、抒情传统与网文边界、相邻方法区分与衔接(write-toward-ending/gold-coins/mix-narrative-modes/inciting-incident 指针)、疑问句即 concept 即引擎的合并点 | +| references/_coverage.md | 五个源单元的覆盖对照表(唯一追溯文件,落点到小节) | + +## 脚本 + +| 脚本 | 用途 | +|------|------| +| references/concept-worksheet.md | 概念自查台账:从素材陈述、what-if 候选、四问记分、引擎一句话、视角候选到信念清单,一份填完 | + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落。 + +## 红线 + +- 只给当前创作阶段的建议,不越权改设定主权、不绕过检测链、不复制粘贴其它 Skill 的 owner 定义。 +- 无用户明确授权不得替用户定稿或提交 Git。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/pi/skills/concept-design/references/_coverage.md b/framework/catalog/pi/skills/concept-design/references/_coverage.md new file mode 100644 index 0000000..fc1f781 --- /dev/null +++ b/framework/catalog/pi/skills/concept-design/references/_coverage.md @@ -0,0 +1,13 @@ +# concept-design 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| becoming-a-writer/originality-is-honesty | references/originality.md | +| story-engineering/concept-delivery-strategy | references/delivery-strategy.md | +| story-engineering/concept-four-questions | references/four-questions.md | +| story-engineering/concept-four-questions | references/originality.md | +| story-engineering/concept-what-if | references/what-if.md | +| story-engineering/concept-what-if | references/story-engine.md | +| writing-tools-clark/story-engine | references/story-engine.md | diff --git a/framework/catalog/pi/skills/concept-design/references/concept-worksheet.md b/framework/catalog/pi/skills/concept-design/references/concept-worksheet.md new file mode 100644 index 0000000..593f5fc --- /dev/null +++ b/framework/catalog/pi/skills/concept-design/references/concept-worksheet.md @@ -0,0 +1,102 @@ +# 概念自查台账 + +用法:小说种子阶段从 0 到 6 顺着填。每节有"过关线",达标进下一节,不达标按标注回退。判断标准全部来自本包 references/ 各文件,这里只是填写骨架;方法细节与案例见各节标注的落点。 + +--- + +## 0. 素材陈述 + +我要写的(idea / 真实素材),1-2 句陈述句: + +> ____ + +## 1. What-if 候选(→ references/what-if.md) + +写 3-5 个不同角度的疑问句;试加反转 / 限制 / 时间压力 / 对手介入: + +1. 如果____? +2. 如果____? +3. 如果____? +4. (可选)如果____? +5. (可选)如果____? + +选定一个:____ +句子里有没有:角色 □ 障碍 □ 赌注 □ +为什么这个最有戏:____ + +过关线:能挑出一个含角色、障碍、赌注的疑问句。写不出 = 还没到 concept 阶段,回 0 重想素材。纯虚构以外的真实素材可直接跳第 4 节。 + +## 2. 四问校验(→ references/four-questions.md) + +| 问 | 问题 | Yes/No | 备注 | +|---|---|---|---| +| 1 | 新鲜独特:别人写过吗?这个类型里写烂了吗? | | | +| 2 | 新角度:不新的话,有没有独特角度(历史 / 真实事件也算)? | | | +| 3 | 冲突性:核心是不是冲突? | | | +| 4 | 可撑长:能撑满预定篇幅不枯竭吗(网文按连载字数算,中短篇改问"会不会注水")? | | | + +记分: + +- 全 Yes → 过关,进第 3 节 +- 3 Yes(必须含第 4 问)→ 可写;弱项:____;补救方式:____(参考 Cold Mountain 的补偿桶:角色、主题、声音) +- 2 Yes 或更少 → 回炉,回第 1 节 + +注意:第 1、2 问别混用——"不新但有新角度"记为问 1 No、问 2 Yes。"我觉得有趣"不算标准。第 4 问不作弊。 + +## 3. 引擎问题(→ references/story-engine.md) + +一句话说出(≤ 25 字,who / what / which / how): + +> ____ + +- 引擎类型:□ 答案驱动(读者要答案本身) □ 过程驱动(答案已知,看过程) +- 是不是主题陈述?("伟大的爱战胜死亡"这类判断不合格,要改写成具体问题)□ 已是问题 □ 已改写为:____ +- 副线迷你引擎(每个都必须服从主引擎): + - 副线 A:他 / 她的赌注是____? + - 副线 B:____? + +过关线:一句话说不出 = 没有引擎 = 故事会散,回第 1 节重磨疑问句。 + +## 4. 真实素材视角候选(仅真实素材填;→ references/delivery-strategy.md) + +素材(事件 / 人物 / 题材):____ + +| # | 视角人物 | 位置(主角 / 配角 / 反对者 / 旁观者 / 受影响者) | 对事件的信息差或情感连接 | 能撑 30 万字吗 | +|---|---------|--------------------------|---------------------------|----------------| +| 1 | | | | | +| 2 | | | | | +| 3 | | | | | +| 4 | | | | | +| 5 | | | | | + +最强视角一句话:通过____的眼睛,故事变成了____。 + +→ 把这句话当 concept,回第 2 节复验四问。 + +警告自检:□ 没有把"反派视角"当创新 □ 视角选择是戏剧策略不是营销策略 □ 没有为有趣牺牲史实 + +## 5. 信念清单(→ references/originality.md) + +排除"应该",只留"真的": + +1. 我真正相信什么?____ +2. 我真正愤怒什么?____ +3. 我最难忘的经历?____ +4. 我与大多数人不同意的看法?____ +5. 我的失败 / 丑事?____ +6. 我想对谁说什么话?____ + +列不出 → 问自己"我最讨厌什么?最反感什么?" + +验证:挑一个烂大街题材(灰姑娘 / 英雄之旅 / 复仇 / 爱情),用上面清单里的一条写 1 段 1-2 分钟的故事,必须包含我自己的看法。写得动吗?□ 能 □ 不能 + +只有我经历过的细节 3 个:____;____;____。 + +承诺:用我现在的想法写,不等"以后想清楚"。□ + +## 6. 总评 + +- 概念定稿(一句话):____ +- 引擎问题(一句话):____ +- 判定:□ 四问通过且引擎到位 □ 可写,弱项补救清单:____ □ 回炉 +- 下一步:结构规划(见综合 skill story-structure)/动笔 diff --git a/framework/catalog/pi/skills/concept-design/references/delivery-strategy.md b/framework/catalog/pi/skills/concept-design/references/delivery-strategy.md new file mode 100644 index 0000000..b4707e7 --- /dev/null +++ b/framework/catalog/pi/skills/concept-design/references/delivery-strategy.md @@ -0,0 +1,99 @@ +# 真实素材也是 concept:叙事交付策略 + +## 原文摘录 + +> "A story about the 1980 U.S. Olympic hockey team and their gold medal may seem to defy the notion of a concept, because it is what it is, you can't mess with the truth. But you can—and should—land upon a conceptual delivery strategy to show us that truth, and it doesn't always have to do with plot. The moment you tell that story through the eyes of a single player—the goalie, for example, or maybe the coach—then you have evolved the idea into the realm of concept." +> +> — Larry Brooks, *Story Engineering* (2011), Part 2 + +## 方法规则 + +### 核心洞察 + +Concept 不一定是"疯狂的点子"。即使你的素材是真实事件,选一个独特的**叙事视角 / 策略**就构成 concept。 + +- Concept 不必是"如果 X 会怎样"(虚构 what if) +- Concept 可以是"通过 X 的眼睛看 Y"(视角选择) +- 同一真实事件,不同视角 = 不同 concept = 不同故事 + +### 4 种常见叙事策略 + +1. **视角人物化**:通过一个非中心人物(守门员、医生妻子、敌方士兵)看大事件 +2. **时间结构化**:用倒叙 / 闪回 / 跨越数十年的结构重组事件 +3. **形式实验化**:用日记 / 信件 / 审讯记录 / 多个短篇拼图等非传统形式 +4. **主题聚焦化**:把大事件压到单一主题维度(种族、阶级、性别、信仰) + +### 操作法 + +拿到你的真实素材,问"如果我通过 X 的眼睛讲,会怎样?"——这个 X 必须对原始事件有独特的"信息差"或"情感连接"。 + +## 案例全文 + +### 案例 1:Miracle——1980 美国冰球队 + +- **问题**:真实事件"1980 美国冰球队夺金"看似无法加 concept +- **方法论的使用**:通过守门员 Jim Craig 的眼睛讲(他在 1980 年成为美国精神的象征) +- **结论**:叙事策略 = concept +- **结果**:2004 年电影 *Miracle*,Kurt Russell 主演,票房评论双成功 + +### 案例 2:The Lovely Bones——天堂题材 + +- **问题**:Alice Sebold 想"写天堂是什么" +- **方法论的使用**:通过一个被谋杀的 14 岁女孩的眼睛(她在天堂叙述)讲谋杀案 +- **结论**:叙事策略(死后视角)+ 主题(正义、宽恕、家庭)= 概念 +- **结果**:全球 1000 万册 + +> 本案例在 references/what-if.md 也出现,那边角度是把"想写天堂"升级成疑问句,这边角度是视角交付策略,角度不同,两处都保留。 + +### 案例 3:Collateral——出租车 + +- **问题**:"杀手 + 出租车"太单薄 +- **方法论的使用**:通过一个普通出租车司机的眼睛,整晚被迫载杀手,逐渐变成被迫害者 +- **结论**:视角选择 = concept +- **结果**:验证了"非典型视角"的有效性 + +## 操作步骤 + +1. **陈述素材** + - 完成标准:1-2 句说清真实素材(事件 / 人物 / 题材) +2. **列出可能的视角人物(≥ 5 个)** + - 完成标准:至少 5 个不同位置的人(主角 / 配角 / 反对者 / 旁观者 / 受影响者) + - 不要先挑,先全列 +3. **对每个视角评估"戏剧性"** + - 完成标准:每个视角回答"这个视角能撑 30 万字吗?" + - 戏剧性 = 角色 + 障碍 + 赌注 + 信息差 +4. **挑 1 个最强视角** + - 完成标准:给出 1 句话:"通过 X 的眼睛,故事变成了 Y" + - 这是你的 concept +5. **验证**(用 references/four-questions.md 的 4 问) + - 完成标准:4 问通过,进入下一阶段 + +## 边界与失败模式 + +### 不要在以下情况使用 + +- 已经在写纯虚构(用 references/what-if.md) +- 写非叙事 / 学术 / 技术(这不适用) +- 真实素材需要严格 1:1 复刻(新闻 / 纪实)——应保持中立,不叙事化 + +### 作者警告的失败模式 + +- 把"通过反派视角讲"当创新——经常是噱头,戏剧性不够 +- 视角选择 = 营销策略(如"我们这次用女性视角")而不是戏剧策略 +- 忽略真实人物 / 事件的约束——只选有趣的视角,牺牲史实 + +### 作者盲点 + +- 默认西方个人主义视角——集体 / 文化 / 家族视角可能更适合某些题材 +- "通过 X 眼睛"的视角单一——多视角(POV 切换)是另一种合法策略 + +## 中文适配 + +- 中国历史与家族题材(村志、厂史、家变、年代群像)常用"小人物看大事件"或"一个家族当视角容器",这正是 Brooks 盲点条款指出的集体 / 家族视角方向,比硬套个人英雄视角更顺。 +- 中文历史题材有史实硬边界:视角人物可以虚构,事件骨架要尊重史实,失败模式里"牺牲史实"的警告在此同样成立。 +- 形式实验化在中文里有现成传统可依托:日记体(鲁迅《狂人日记》)、书信体、供状 / 卷宗体、章节拼图都有本土成例,选形式时优先想清楚形式与"信息差"的关系,不为新而新。 + +## 易混方法论 + +- "Rashomon 效应"——多个视角讲同一事件,不同于本方法的"挑 1 个" +- 电影 *Rashomon* vs 小说多 POV:前者展示真相多面性,后者展示人物丰富性 diff --git a/framework/catalog/pi/skills/concept-design/references/four-questions.md b/framework/catalog/pi/skills/concept-design/references/four-questions.md new file mode 100644 index 0000000..f5d6cf1 --- /dev/null +++ b/framework/catalog/pi/skills/concept-design/references/four-questions.md @@ -0,0 +1,93 @@ +# 概念合格性校验:concept 四问 + +## 原文摘录 + +> "A concept, it could be said—and it should be viewed this way—is something that asks a question. The answer to the question is your story. Is the concept fresh and original? Does it at least present an opportunity to impart a new spin on a familiar theme or premise? Is it cast in terms of conflict? Can you sustain reader interest in this concept over the length of a novel?" +> +> — Larry Brooks, *Story Engineering* (2011), Part 2 + +## 方法规则 + +判断一个写作种子是否升级为"concept"的 4 个筛子。任何一题答 No,种子就还没准备好作为故事,需要回炉。 + +### 4 问 + +1. **新鲜独特(Fresh & Original)**:这个 concept 是不是别人没写过的?或者至少在这个时代 / 这个 genre 还没被写烂?(过低 = 没人想看) +2. **新角度(New Spin)**:如果不新,它有没有给熟悉主题一个独特角度?(历史 / 真实事件都算) +3. **冲突性(Cast in Conflict)**:这个 concept 的核心是不是"有冲突"?没有冲突 = 不是概念 +4. **可撑长(Sustains Novel-length)**:这个 concept 能不能撑 300+ 页而不枯竭?(概念太单薄 = 写不到长篇) + +### 判断逻辑 + +不必 4 问全 Yes,但至少 3 问 Yes,第 4 问(可撑长)必须 Yes。没有冲突的 idea 不是 concept,单一事件的 idea 撑不到长篇。 + +### 用法的关键:双向 + +这是**双向的**——可以 (a) 评估现有 idea,也可以 (b) 在 idea 阶段就自我检查,避免"写了 200 页才发现 concept 撑不住"。 + +## 案例全文 + +### 案例 1:The Closers——同 idea 多种 concept + +- **问题**:Michael Connelly 想写一个"警探破案"故事,这个 idea 撑不起 30 万字 +- **方法论的使用**:对 idea 问 4 问:(1) 新鲜?不,警探破案写烂了 (2) 新角度?加:20 年前的悬案 + 警方掩盖 + 种族歧视历史背景 (3) 冲突?是 (4) 可撑长?是 +- **结论**:通过 4 问后,idea 升级为 killer concept +- **结果**:成为纽约时报畅销书 + +### 案例 2:Cold Mountain——4 问不通过但仍成功 + +- **问题**:Civil War 士兵回家,这个 idea 极度普通(第 1 问失败) +- **方法论的使用**:接受第 1 问失败,用 (2)(3)(4) 强力支撑——靠"角色 + 主题 + 声音"救场 +- **结论**:4 问不全通过也能写,但必须有补偿桶 +- **结果**:#1 畅销书,国家图书奖,证明 6 桶互为补偿 + +> "6 桶"指 Brooks 的六项核心能力(six core competencies),该框架归属综合 skill novel-diagnosis,此处不展开。 + +## 操作步骤 + +1. **陈述你的 idea/concept** + - 完成标准:用户能用 1-2 句话说清他的种子 +2. **逐题问 4 问** + - 完成标准:4 问都有 yes/no 答案 + - 答案不需要长解释,是 / 否即可 +3. **统计 + 诊断** + - 完成标准:给出"通过 X 问"的总评 + - 全 Yes:升级成功,进入下一阶段 + - 3 Yes(含第 4 问):可写,但需补不强项 + - 2 Yes 或更少:需回炉,用 references/what-if.md 升级 +4. **给出建议** + - 完成标准:用户拿到一个"下一步做什么"的具体指引 + +## 边界与失败模式 + +### 不要在以下情况使用 + +- 已有 concept 但想改进结构(用 story-structure 综合 skill) +- 想把 idea 升级到 concept(用 references/what-if.md) +- 非小说写作(诗歌 / 散文 / 论文) + +### 作者警告的失败模式 + +- 把"我觉得有趣"当"concept 达标"——主观趣味不等于客观 4 问 +- 第 4 问(可撑长)容易作弊——以为 200 页就够了,但商业小说需 300+ +- 第 1 问和第 2 问混用——"不新但有新角度"应该归到第 2 问 Yes,第 1 问 No + +### 作者盲点 + +- 4 问默认"商业出版"标准,文学 / 实验小说可能需要更宽松 +- 第 4 问"撑 300 页"假设长篇——中短篇不需要这条 + +## 中文适配 + +- "撑 300+ 页"是商业出版页数口径:中文纸质出版可按 20-30 万字折算;网文连载要按几十万字到百万字的连载体量算,"可撑长"要拆到小钩子的更新节奏上逐段检验。 +- 中短篇免除第 4 问,改问"能不能在预定篇幅内把故事讲完而不注水"。 +- 中文网文里被写烂的类型(赘婿、系统、刑侦悬疑)可以走 The Closers 的路:保留熟悉框架,叠加本土悬案、时代背景、社会议题当"新角度",把第 1 问的失败转成第 2 问的通过。 + +## 冲突标注(一句话指针) + +第 1 问"新鲜独特"与布兰德的原创性观点相左——布兰德认为题材不必新,视角的诚实与深度才决定原创 → 见 references/originality.md 的"冲突标注"节。 + +## 易混方法论 + +- "Save the Cat 的 10 个 genre 类型"——那是 genre 分类,不是 concept 质量 +- Christopher Booker 的 7 个原型——那是主题原型,不是 concept 评估 diff --git a/framework/catalog/pi/skills/concept-design/references/originality.md b/framework/catalog/pi/skills/concept-design/references/originality.md new file mode 100644 index 0000000..493caf5 --- /dev/null +++ b/framework/catalog/pi/skills/concept-design/references/originality.md @@ -0,0 +1,173 @@ +# 原创性就是诚实:你的视角本身就是原创 + +## 原文摘录 + +> "只要你能够和自己友好相处,能够而且愿意精确地说出你对任何一种情形或一个人的看法, +> 如果你能够讲出一个好像包括地球上所有人在内只有你自己看到的故事, +> 你自然而然地就有了一篇原创作品。 +> 而这一点看起来似乎非常简单,却是一般作家最难做到的。 +> 那些作家的优点恰恰在于,他们拒绝像他们的模仿者那样谦卑地人云亦云。 +> 他们每一个人都有一个自己的视角,都传达出了自己对世界的描写。" +> +> — 多萝西娅·布兰德,《成为作家》第十二章(引用伊迪丝·华顿) + +## 方法规则 + +### 核心反直觉命题 + +**原创性 = 你的诚实**——精确说出自己的看法。不是"想新点子"。 + +### 流行误解 + +- 原创性 = 想到没人想到的题材 +- 原创性 = 独特的风格 +- 原创性 = 标新立异 + +### 布兰德的真相 + +- 原创性 = 精确说出**自己**对情形的看法 +- 你的视角**已经**是独特的——"即使是一对双胞胎也不会对同样的故事有完全一样的看法" +- 不需要"新点子",需要"真诚的旧点子" + +### 为什么"旧点子"也是原创 + +- 同样一个"俗套"提纲,24 个学生写出 24 个故事 +- 你的"愤怒"和别人的"愤怒"不是同一种 +- 你的"爱"和别人的"爱"经历不同 +- 你的"妈妈" / "童年" / "失败" / "成功"**不是**别人的 +- 关键不是题材,是**你怎么看待** + +### "不要等最后智慧"(布兰德的反复警告) + +- 思想永远不会"完成",因为人在持续成长 +- 等"最终" = 等"死"——因为只有死时思想才"停止变化" +- "等我想清楚再写"的人永远不写 +- 在你**目前的信念**基础上写,不要假装成未来的自己 + +### "令人吃惊的结尾"的陷阱 + +- 有些作者为"原创"而原创,把结尾写得"惊人" +- 他们为了服务"原创"这个上帝,让角色做不该做的事 +- 故事不连贯,失败 +- 真正的好结尾是**角色自身**会做的事,不是作者强加的 + +### 为什么布兰德说"难" + +- "看起来似乎非常简单"——你只需要说自己的看法 +- "却是一般作家最难做到的"——因为作者会**模仿**别人的看法 +- 长期读书的人,习惯"通过别人的眼睛看世界" +- 重新"通过自己的眼睛看",需要勇气 + +### 华顿夫人的两条法则(布兰德引用) + +1. 小说家应该只处理他力所能及之事(与你真诚相关的题材) +2. 一个主题的价值完全取决于作者能够从中发现什么以及他发现的深度 + +### 原创性的"诚实清单" + +- 你相信什么?(信念) +- 你为什么愤怒?(情感) +- 你最难忘的经历是什么?(记忆) +- 你与大多数人不同意的看法是什么?(立场) +- 你的"丑事" / "失败"是什么?(隐私) +- 你想对谁说什么话?(目标) + +## 案例全文 + +### 案例 1:高尔夫球冠军少女的课堂 + +- **问题**:布兰德给一个"极俗套"的提纲(娇生惯养的女孩结婚,对金钱的态度差点毁了姻缘) +- **方法论的使用**:让学生 10 分钟内各写一段 +- **结论**:同一提纲,24 个学生写出 24 个完全不同的故事——视角本身就是原创 +- **结果**:学生再没抱怨"我唯一的思路陈腐" + +### 案例 2:华顿夫人的"两项基本法则" + +- **问题**:写小说时不知如何处理题材 +- **方法论的使用**:引用华顿:题材的价值不在于"题材本身多新",在于"你从中发现的深度" +- **结论**:同一个"旧"题材,写得有深度 = 原创 +- **结果**:重新定义"原创"的来源 + +### 案例 3:海明威 vs 模仿者 + +- **问题**:模仿者模仿海明威"硬汉味",但越来越僵 +- **方法论的使用**:布兰德诊断:模仿者模仿"风格"(海明威的"味道"),不是"视角"(海明威的真实经验) +- **结论**:风格 = 海明威的真实;模仿者 = 抄别人的真实,永远不真 +- **结果**:模仿者凝在错误年代 + +## 操作步骤 + +1. **诊断:用户的"原创性"误解是哪一个** + - 完成标准:用户能说出"我以为原创是 X,现在知道是 Y" + - 提问:"你说的'新意'是什么意思?是新题材,还是新视角?" + - 判停条件:若用户说"我两者都要" → 解释:视角才是真正可得的,题材是无限的也是不重要的 +2. **诚实地填一份"信念清单"** + - 完成标准:用户能列出 3-5 个"我真正相信的事" / "我真正愤怒的事" + - 关键:排除"应该"相信的,只留"真的"相信的 + - 例:"我相信'努力就会成功'是骗人的" / "我相信现代婚姻本质上是经济关系" + - 判停条件:若用户列不出 → 提问"你最讨厌什么?最反感什么?" +3. **从一个"旧"提纲开始** + - 完成标准:用户能写"1 段 1-2 分钟"的故事,用"旧"提纲 + 自己的视角 + - 任务:"挑一个'烂大街'的题材(灰姑娘 / 英雄之旅 / 复仇 / 爱情),写 1 段 1-2 分钟的故事,必须包含你'自己的看法'" + - 关键:不是"想新点子",是"用你真实的看法写" +4. **找出"你独有的细节"** + - 完成标准:用户能列出"别人没经历过的 3 个细节" + - 任务:列出只属于你的"童年记忆 / 工作细节 / 某次失败 / 某次惊喜" + - 这些细节是"你"写的,别人无法抄 +5. **不要等"最后智慧",现在就写** + - 完成标准:用户承诺"用我现在的想法写,不等'以后想清楚'" + - 关键:现在的看法 = 现在的原创;以后的看法 = 以后的原创 + - 写出来后,以后还能改 + +## 边界与失败模式 + +### 不要在以下情况使用 + +- **用户没有素材**——对应的是素材积累类方法,未收入本技能库 +- **用户写得好但没发表**——对应的是写后心态类方法,未收入本技能库 +- **用户被"不知写什么"卡住**——对应的是写作困难诊断类方法,未收入本技能库 +- **用户被法律 / 版权问题困扰**——那是原创性之外的"抄袭"问题 + +### 作者在书中警告的失败模式 + +- **等最后智慧**:想"等想清楚再写",永远想不清楚 +- **模仿风格**:模仿别人的"味道"(别人的真实),永远不是自己的 +- **公共场合批评**:在班上当众批评,让学生扔掉自己的风格 +- **一本正经学技巧**:把"学技巧"当作主要工作,越学越像别人 + +### 作者的盲点 / 时代局限 + +- **"诚实"假设你有勇气**——现实中很多人因为经济压力 / 家庭压力,不能完全诚实 +- **"你的视角"假设你能表达**——有些人有视角但表达不出来(那是技术问题) +- **不区分"创作自由"和"商业写作"**——商业写作有时不能完全诚实(客户要求) +- **过度理想化"自我表达"**——写公众号 / 营销文 / 学术论文,都不是"自我表达"主导 + +## 冲突标注:与 Brooks"新鲜独特"第 1 问的分歧 + +Brooks 的概念四问把"新鲜独特"列为第一关:concept 不新就不合格(→ references/four-questions.md)。布兰德相反:题材根本不必新,原创来自作者的诚实视角与发现深度,"旧"题材写出深度就是原创。 + +两条规则冲突,都保留。使用分工: + +- Brooks 的标准评的是**概念的市场成立性**——判断一个点子能不能撑起读者兴趣时用。 +- 布兰德的标准评的是**作者的独有角度**——卡在"题材写烂了、我没新意"时用。 +- 可操作的顺序:先用布兰德的方法把真实视角挖进熟悉题材,再用 Brooks 的第 2 问(新角度)检验这个视角是否构成独特角度——"诚实"用来供给"新角度",两套标准就接上了,而不是互相抵消。(此段为合并整合说明,两条规则的出处见 references/_coverage.md。) + +## 中文适配 + +- 《成为作家》中译本直接可用:信念清单、旧提纲练习、独有细节清单可以原样用于中文写作自查和课堂。 +- 中文写作者填信念清单时,"应该相信"的干扰常来自教育与平台语境的套话;按布兰德的标准,这些"应该"一律排除,只留"真的"相信的。 +- 平台定制、商业连载写作中,布兰德的盲点条款依然成立:诚实要与类型契约商量着来,但"你怎么看待这个处境"仍然是别人抄不走的部分。 + +## 易混的邻近方法论 + +- **"寻找独特卖点"(USP 营销)**——是商业概念,找市场差异,不是"你的真实" +- **个人品牌建设**——是包装自己,不是诚实表达 +- **"创新方法论"(TRIZ 等)**——是技术发明方法,不是写作原创 + +## 与原书相邻方法的区分 + +以下相邻方法均属作者培养类,未收入本技能库;区分条目按原文保留,供理解本方法的边界: + +- **与"重新看世界"(素材积累类方法)的区别**:素材积累教"重新看世界";本方法教"从自己的视角写"。前者是 input,后者是 output 角度;先"重新看",再找到自己的视角。 +- **与"学别人的技术"(模仿学习类方法)的区别**:模仿学习教"学别人的技术";本方法教"写自己的内容"。两者**对比**——**技术可借,内容不可借**(学别人的技术 vs 写自己的内容)。这条判断标准有独立方法价值。 +- **与"保护创作能量"(能量管理类方法)的区别**:能量管理解决"能量被消耗";本方法解决"内容无自己"。前者是 energy,后者是 angle;自己的视角需要保护。 diff --git a/framework/catalog/pi/skills/concept-design/references/story-engine.md b/framework/catalog/pi/skills/concept-design/references/story-engine.md new file mode 100644 index 0000000..8e7da16 --- /dev/null +++ b/framework/catalog/pi/skills/concept-design/references/story-engine.md @@ -0,0 +1,122 @@ +# 故事引擎:让核心问题驱动整本书 + +## 原文摘录 + +> Who done it? Guilty or not guilty? Who will win the race? Which man will she marry?… This narrative strategy is so powerful that it needs a name, and Tom French gave it to me: he calls it the "engine" of the story. He defines the engine as the question the story answers for the reader. +> +> — Roy Peter Clark, *Writing Tools* (Tool 31) + +> I have read many manuscripts that lack a story engine. The writers have worked hard, often beautifully, but there is no narrative fuel to power the piece to its end. +> +> — Roy Peter Clark, *Writing Tools* (Tool 31, on the failure mode) + +## 方法规则 + +Clark 通过 Tom French 提出"故事引擎",核心论断是:**长篇 / 短篇集 / 非虚构书的结构不是"主题",而是"问题"。** + +### 三层概念必须分清 + +- **主题(theme / premise)**:抽象判断,如"伟大的爱战胜死亡"、"权力腐蚀人"。是结论,是终点,不能驱动翻页。 +- **故事(story)**:事件流,人物动作、情节转折。是回答的载体,但不是回答的吸引力。 +- **引擎(engine / key question)**:贯穿全书的**核心问题**——读者翻页的唯一原因是想知道这个问题的答案。 + +### 区分两类引擎问题 + +1. **答案驱动(who / what / which)**:"她会不会回到 Kansas?"、"Rosebud 是什么?"、"Baby No. 81 是谁家的孩子?"——读者要的是"答案本身"。 +2. **过程驱动(how)**:"007 怎么能赢?"——答案已预知,读者要的是"过程如何精彩"。 + +### 一句话说出来 + +Clark 强调:**小说写作者要能用一句话说出"我的故事在回答什么问题?"** 说不上来 = 没有引擎 = 故事散了。 + +### 副线迷你引擎 + +副线可以挂"迷你引擎"(每个角色"他的赌注是什么?")——但所有迷你引擎必须服从主引擎。 + +## 案例全文 + +### 案例 1:奥兹《Short Story》("她会不会回到 Kansas?") + +- **问题**:短篇如何让人一口气读完? +- **方法论的使用**:奥兹把一个小说压缩到一个人物的一句话里——"她会不会回到 Kansas?"——这是 who 引擎,读者必须翻到末尾才知道答案。 +- **结论**:即使最短的短篇也需要一个"答案驱动"的问题;**没有这个问题,短篇会被读者搁置**。 +- **结果**:成为了"短篇也需要引擎"的金标准案例;Clark 用来反驳"短篇不需要结构"的天真假设。 + +### 案例 2:《公民凯恩》("Rosebud 是什么?") + +- **问题**:看似无情节的人物传记片如何让人想看下去? +- **方法论的使用**:整部电影就是一个侦探在追问"Rosebud 是什么?"——一个 who 引擎,答案(童年雪橇)在最后一秒揭晓。 +- **结论**:引擎可以**穿越任何题材**——传记、悬疑、爱情、家庭——只要有一个具体问题,故事就有动力。 +- **结果**:成为了"答案驱动 vs 过程驱动"分类的标志案例;展示了"如果题材本身没戏剧性,人造一个问题也能造出动力"。 + +### 案例 3:Tom French 的 HB 婴儿案("Baby No. 81 是谁家的孩子?") + +- **问题**:非虚构长篇报道如何让人愿意读 30 万字? +- **方法论的使用**:Tom French 把整本非虚构书围绕一个具体问题——一个被错换的女婴最终回到哪家?——读者翻页是因为想知道"答案"。 +- **结论**:**非虚构书也需要引擎问题**——不是"主题"(医疗体系批判),而是"一个具体问题"——主题是结论,问题是钩子。 +- **结果**:成为了"非虚构 = 故事"论点的最强证据;证明了 French 概念在虚构 / 非虚构之间的可迁移性。 + +## 操作步骤 + +1. **一句话写出引擎问题** + - 问用户:"你的小说在回答什么问题?"——强制 25 字以内,who/what/which 形式。 + - 完成标准:用户能用一句话说出"她会不会……" / "他能不能……" / "X 是什么……";说不出的,标为"无引擎"。 + - 判停条件:若用户写的是"主题陈述"(如"伟大的爱战胜死亡"),需帮其改写为具体问题(如"她会不会为他放弃自己的医生事业?")。 +2. **检验每章是否被引擎驱动** + - 列出每章标题,逐一问:"这章把引擎问题往答案推了多远?"——回答应是"推了一半"、"让它更复杂"、"让答案变成新问题"。 + - 完成标准:90% 章节被标"推进引擎";若超过 30% 章节"无关于引擎",标为"引擎失效"——需重写或删减。 + - 判停条件:章节可能是"必需但无关引擎"(如背景铺垫),允许最多 10% 的"装饰性章节",但作者需明确知道这些是"非引擎"。 +3. **中段诊断:三分之一处读一遍** + - 单独读 1/3 处的章节(全书 30%-40% 位置),问:"如果我读到这页,我会想翻下一页吗?" + - 完成标准:中段每 5000-10000 字至少 1 次"问题进展"(新信息 / 矛盾 / 加码 / 答案翻盘);否则诊断为"中段塌陷",用金币密布的方法修补(gold-coins,归属综合 skill narrative-momentum)。 + - 判停条件:若中段每章都"等距推进",说明引擎问题"线性可预测"——需在中段加入"答案翻盘"或"问题变形"。 + +## 激活场景 + +用户在这些情境下需要本方法: + +1. 写到长篇中段,每章都写了但"读起来像流水账"——章节之间没有"答案推进"。 +2. 朋友 / 编辑问"你这本小说讲什么?",你只能回答"呃……很多事"。 +3. 写短篇集,各篇都好但整本读完"没有主心骨"——读者记不住你。 +4. 写非虚构书,书里充满"主题"但没有一个具体问题钩住读者。 +5. 动笔前不知道"我这本书在回答什么问题"——主题写满三页纸但没有一句话的问题。 +6. 长篇写到 1/3 处感觉"故事散了"——人物还在动,但读者(和自己)已经忘了"为什么在动"。 + +语言信号:"故事没有主心骨"、"中段失去方向"、"小说要回答什么问题"、"故事散了" / "写到一半散了"、"故事引擎" / "story engine" / "key question"、"我小说讲什么?"答不上来、"主题太抽象" / "落不进情节"、"Tom French" / "French engine"。 + +## 边界与失败模式 + +### 不要在以下情况使用 + +- **纯抒情散文 / 散文诗**——没有"问题"是合法的,引擎是叙事性文学的工具。 +- **反结构实验小说**——故意无情节、无问题(《项狄传》、某些后现代)是反"引擎"的合法艺术选择,不能用此方法评判。 +- **单场景剧本 / 独幕剧**——没有长程结构,引擎失效。 +- **工具书 / 教材**——引擎问题不适用,改用"读者翻页是为了解 X"——那是手册结构,不是故事结构。 + +### 作者在书中警告的失败模式 + +- **"没有引擎 = 故事散"**:失败模式是长篇没有核心问题——读者读完 200 页不知道"作者想说什么"。**信号**:朋友问"你小说讲什么?"作者回答"呃……很多事"。**机制**:人脑把故事存储为"问答结构"——核心问题 + 解答过程;没有问题 = 没有存储格式 = 记不住 / 不想继续。**警告信号**:用一句话说不清 / 章节之间没有"答案推进" / 中段之后结构松散。 +- **"主题陈述当引擎"(常见混淆)**:把"伟大的爱战胜死亡"当引擎——但这是判断,不是问题。判断被读者接受就完了,问题才会让人翻页。 + +### 作者的盲点 / 时代局限 + +- Clark 的引擎理论主要在**非虚构**和**小说长篇**语境下发展(Tom French 是记者,Clark 自己是写作教师),**散文诗 / 抒情文学**不在视野内,中文文学传统里大量"无问题"的散文会被错误判定为"无引擎"——这是工具的边界,不是文学的失败。(中文适配) +- **时代局限**:Clark 写于 2006 年(英文版),未涵盖**网文连载**——网文有独特的"明线引擎" + "暗线升级"双轨结构(明线是表层问题,暗线是深层问题翻盘),直接套用"一句话引擎"会让网文结构被错判为"单一"。(中文适配) +- **概念溯源需注明**:故事引擎这个概念**主要来自 Tom French**(记者、普利策奖得主),Clark 在书里**明确把命名权归给 French**。引用时不应说"Clark 发明了故事引擎",而应说"Clark 通过 French 的概念提炼为可操作工具"。 + +## 与概念的关系:疑问句既是 concept 也是引擎(两书合并点) + +Brooks 说概念是"asks a question","问题的答案就是你的故事";French 把引擎定义为"故事为读者回答的那个问题"。两本书说的是同一件事的两面: + +- 同一个疑问句,在概念阶段是 what if(→ references/what-if.md),在运行阶段是引擎。 +- 概念阶段产不出疑问句,运行阶段就没有问题可驱动;反过来,写到中段引擎失效,回概念阶段检查疑问句本身有没有角色、障碍、赌注。 +- Brooks 四问里的第 4 问"可撑长",其实就是对"引擎能不能撑长篇"的预检(→ references/four-questions.md)。 + +## 易混的邻近方法论 + +- **与 "inciting incident" 的区别**:那个是"第一秒扔出来的打火石",这个是"持续牵引的问题";前者是开关,后者是发动机。一本书可以**没有 inciting incident(慢热)**但**必须有 engine**——反之不行。两者可衔接:inciting incident 是引擎的"开场打火石"。(inciting-incident 方法归属综合 skill story-structure。) +- **与 "write-toward-ending" 的区别**:那个是"先定结局"——锚定终局再反向写作;这个是"先定问题"——锚定核心问题再驱动写作。**问题在前,结局在后**——读者读小说不是为看结尾,是看问题怎么被回答。两者可衔接:先定引擎问题,再倒推向结局。(write-toward-ending 方法归属综合 skill story-ending。) +- **与 "gold-coins" 的区别**:那个是"中段撒金币"——防止读者在中段弃读的小高潮密布;这个是"中段为什么不散"——**引擎持续运转,中段自然不塌**。金币是"锦上添花",引擎是"主结构";引擎不散 + 金币不弃读 = 长篇双保险。(gold-coins 方法归属综合 skill narrative-momentum。) +- **与 "mix-narrative-modes" 的区别**:那个是"主线 / 折线 / 蒙太奇"等模式调度;这个是"无论用哪种模式,都在回答同一个核心问题"。(mix-narrative-modes 方法归属综合 skill narration-pov。) +- **与 "theme / premise"(经典写作书)的区别**:主题是抽象判断("爱战胜死亡"),引擎是具体问题("她会不会为他死?")。**判断是终点,问题是路径**——读者读小说是走路径,不是看终点。 +- **与 "logline"(编剧术语)的区别**:logline 是"卖点压缩"(人物 + 冲突 + 钩子),引擎是"贯穿问题"——logline 可以多重,引擎只能一个。 diff --git a/framework/catalog/pi/skills/concept-design/references/what-if.md b/framework/catalog/pi/skills/concept-design/references/what-if.md new file mode 100644 index 0000000..d2e37d1 --- /dev/null +++ b/framework/catalog/pi/skills/concept-design/references/what-if.md @@ -0,0 +1,109 @@ +# 把 idea 升级成 concept:concept 必须是"what if"疑问句 + +## 原文摘录 + +> "A concept, it could be said—and it should be viewed this way—is something that asks a question. The answer to the question is your story. The idea to write a story about ballet dancers is not a concept. It is just an idea. But when you add a forward-thinking realm to that idea, and do it in the form of a question—what if a ballet dancer loses her leg at the knee but perseveres against great prejudice to become a professional dancer?—you have evolved the idea into the realm of conceptualization." +> +> — Larry Brooks, *Story Engineering* (2011), Part 2 + +## 方法规则 + +### idea 是陈述句,concept 是疑问句 + +"想写 X"是一个 idea,但 idea 不是 concept。Concept 必须以**疑问句(what if?)**形式存在——只有疑问才能撑起故事的张力。 + +核心规则对照: + +| Idea(陈述句) | Concept(疑问句) | +|---|---| +| "我想写律师" | "如果律师发现自己辩护的凶手是父亲?" | +| "我想写芭蕾舞者" | "如果芭蕾舞者失去膝盖以下?" | +| "我想写珍珠港事件" | "如果珍珠港当天一个日本飞行员的妻子在等他回家?" | + +### 4 级递进 + +1. **Idea**(陈述性)→ 2. **Concept**(疑问性)→ 3. **Premise**(概念 + 角色任务)→ 4. **Theme**(故事意义) + +### 为什么必须是疑问句 + +- 疑问自带戏剧张力——读者想知道答案 +- 疑问暗示"还没决定"——给角色留出走过的路径 +- 疑问暗示"还有风险"——给故事留下起伏空间 + +### 操作法 + +拿到 idea,用 "What if...?" 起头,强逼自己写出疑问句。如果写不出 = 还没到 concept 阶段。 + +## 案例全文 + +### 案例 1:芭蕾舞者 → 概念化 + +- **问题**:写作者只想"写一个芭蕾舞者" +- **方法论的使用**:强加 what if? ——"如果她在 25 岁失去膝盖以下呢?" +- **结论**:失去肢体 + 坚持 + 偏见 = 戏剧张力,撑起 30 万字 +- **结果**:演示了 idea→concept 的标准路径 + +原文摘录里 Brooks 的说法是 "what if a ballet dancer loses her leg at the knee but perseveres against great prejudice to become a professional dancer?"——同一个案例,多了"顶着偏见成为专业舞者"这层坚持与偏见的具体内容,两处对照使用。 + +### 案例 2:The Lovely Bones——从主题到 concept + +- **问题**:Alice Sebold 想"写天堂是什么样" +- **方法论的使用**:用 what if? ——"如果一个被谋杀的 14 岁女孩在天堂,她的家人不知道真相,她干预?" +- **结论**:疑问句打开 murder mystery 主题 +- **结果**:全球 1000 万册 + +> 本案例在 references/delivery-strategy.md 再次出现,那边角度是"死后视角"作为叙事交付策略,角度不同,两处都保留。 + +### 案例 3:1980 美国冰球队 → 守门员视角 + +- **问题**:写作者想"写 1980 美国冰球队夺金" +- **方法论的使用**:用 what if? ——"如果通过守门员的视角看这支球队?" +- **结论**:疑问句把历史事件变成故事 +- **结果**:成为 2004 年电影 *Miracle* + +> 本案例同时是 references/delivery-strategy.md 的头号案例(真实事件的视角化交付),角度不同,两处都保留。 + +## 操作步骤 + +1. **陈述 idea** + - 完成标准:1-2 句,描述性(非疑问) +2. **用 what if? 起头,写 3-5 个疑问句** + - 完成标准:至少 3 个不同角度的 what if? 句 + - 提示:试加"反转" / "限制" / "时间压力" / "对手介入" +3. **挑出最有戏剧张力的疑问句** + - 完成标准:选 1 个,并解释"为什么这个最有戏" + - 戏剧张力 = 角色 + 障碍 + 赌注 +4. **验证**:这个疑问句能展开成 30 万字吗? + - 完成标准:yes 走四问校验(references/four-questions.md),no 重新写 + +## 边界与失败模式 + +### 不要在以下情况使用 + +- 已经有完整 concept(用 references/four-questions.md 评估) +- 在优化叙事视角(用 references/delivery-strategy.md) +- 非小说写作 + +### 作者警告的失败模式 + +- 把"我想问 X"当 what if?——"我想问律师的道德"不是疑问句,是研究主题 +- what if? 句子里没有"障碍 / 赌注"——"如果律师是好人?"没戏 +- what if? 太多——只挑 1 个,不是 5 个 + +### 作者盲点 + +- 默认疑问句 = 西方式"个体困境",不适配集体 / 文化 / 宇宙级故事 +- what if? 假设写作者用英语——其他语言的疑问句构造不同 + +## 中文适配 + +- 中文疑问句用"如果/要是/倘若……会怎样?"起头,构造与 "What if...?" 功能相同,不需要翻译腔的"如果有一天"式长定语。 +- 家族史诗、村志厂史、群像题材不一定从个体困境起问:可以把疑问抬到集体层面——"如果这个家族……""如果这个村子……";也可以不硬造虚构疑问,直接走 references/delivery-strategy.md,用"通过谁的眼睛讲"当概念。 +- 中文网文里疑问句的赌注常挂在长线悬念上(升级、复仇、真相),验证"能不能撑 30 万字"时要按连载体量算,参见 references/four-questions.md 的中文适配。 + +## 与其他方法的关系 + +- **校验**:concept 成型后用四问校验 → references/four-questions.md。 +- **真实素材**:真实事件 / 非虚构素材不必硬造虚构 what if → references/delivery-strategy.md。 +- **引擎**:这个疑问句同时就是全书要回答的问题——概念在诞生时是 what if,在运行时是引擎 → references/story-engine.md。 +- **易混方法论**:Snowflake Method 的"一句话前提"——那是 premise 不是 concept;Logline 公式——那是概念 + 主角 + 冲突,已经到 premise 阶段。 diff --git a/framework/catalog/pi/skills/dialogue-craft/SKILL.md b/framework/catalog/pi/skills/dialogue-craft/SKILL.md new file mode 100644 index 0000000..61f9307 --- /dev/null +++ b/framework/catalog/pi/skills/dialogue-craft/SKILL.md @@ -0,0 +1,115 @@ +--- +name: dialogue-craft +description: | + 激活场景:写或改小说对话——用户说"我对话写不好"、"对话太书面、像论文答辩"、 + "对话全是 X 说 Y 说"、"所有角色说话一个声音"、"对话推动不了情节"、 + "不知道什么时候用对话什么时候用叙述"、"对话只是在传递信息"、"对话没张力"、 + "对话写得像答辩"、"写了一整章对话情节没推进"、"权力博弈场景对话没张力"、 + "对话怎么暴露人物、怎么改变权力关系"。 + 关键 trigger:"对话写不好"、"对话太书面"、"对话像答辩"、"什么时候用对话"、 + "对话一个声音"、"对话推动情节"、"X说Y说"、"对话没张力"、"对话太碎/太满"、 + "对话即行动"、"dialogue as action"、"对话和引语的区别"、"dialogue vs quote"、 + "对话暴露人物"、"对话改变权力"、"小说对话技巧"。 + 不适用于:说明文/议论文;访谈记录与会议实录(非虚构对话是转录,不是小说); + 剧本(两书冲突保留:布兰德认为对白即剧本全体、无需判断何时用;克拉克源单元声明 + 适用于写剧本;见 references/boundaries-and-pitfalls.md 适用范围节); + 纯抒情与内心独白(规则不同,见 narration-pov); + 无对话的纯动作戏(见 scene-craft);辩论稿与演讲稿(目标是说服,不是"做事"); + 用户整篇不会写(那是 story-planning 的活);对话只是其中一部分、想整体优化 + (先把稿子放一边、隔夜重读做整篇优化,不在对话层面修)。 + 与 character-presentation 交接:登场呈现与"过程发现"归后者;说话方式、句长、口头禅、同一声音诊断归本 Skill。 +--- + +# 对话写作(dialogue-craft) + +把对话当事件写:先判断该不该用对话,再给每段对话派任务、给每个角色定声音、磨出真人质感、控好节奏、删掉标签让读者偷听。 + +## 方法索引 + +按创作动作组织;方法细节、案例、引文都在 references 里,这里只给一句话和指针。 + +### 判断:这段该不该用对话 + +- 对话是故事在高潮处的"喷涌",冲突与高潮必用,密度可达 50%-80% → references/when-to-use-dialogue.md +- 对话是"在场发生",事后补话是引语:判断一句话是"上方传来"还是"在场发生" → references/when-to-use-dialogue.md +- 信息、背景、前情交给叙述/独白/闪回,别让角色用嘴讲设定 → references/when-to-use-dialogue.md +- 对话还是叙述,按 7 行速查表定(冲突用对话、信息用叙述、过渡看隐含冲突) → references/when-to-use-dialogue.md + +### 派任务:每段对话都要做事 + +- 对话不是装饰,是事件:推进关系、改变权力、揭示人物三件事至少做一件 → references/dialogue-does-things.md +- 好对话是不同目标与价值观的碰撞,互相分享信息的对话改用叙述 → references/dialogue-does-things.md +- 闲聊也要藏东西:表面聊童年实际在比"谁更惨",纯寒暄删掉 → references/dialogue-does-things.md +- 案例:《卡瓦利与克雷的神奇冒险》开篇一句"什么是漫画书?"一次做实关系、性格与氛围 → references/dialogue-does-things.md + +### 建声音:每个角色说话像那个人 + +- 句长、用词、节奏随年龄、教育、性格走,内向的人句子更短 → references/character-voice.md +- 让人物自己暴露:删掉叙述者说明,看对话本身能不能让读者懂 → references/character-voice.md +- 给每个角色固定语言习惯,至少 2 个区别点:一个总说"反正",一个总说"你懂的" → references/character-voice.md +- 一个声音的诊断:把对话单独抽出来,看分不清是谁 → references/character-voice.md + +### 磨质感:对话要像真人说话 + +- 真人说话有半句话、重复、嗯嗯、打断;一样都没有的标准化台词是作者代笔 → references/real-speech-texture.md +- 反书面化也反"太真实":不能是"我非常感谢你的意见",也不是逐字录音 → references/real-speech-texture.md +- 教科书式对话(ce24)的信号:说整句、不重复、不卡顿、不用俚语 → references/real-speech-texture.md +- 中文适配:语气词密度、翻译腔与公文腔信号 → references/real-speech-texture.md + +### 控节奏:对话的快与慢 + +- 短对话加叙述增强时间感,长独白不如短的来回交换 → references/rhythm-and-density.md +- 一页纸切成数不清的小段对话 = 时间快,大段叙述 = 时间慢 → references/rhythm-and-density.md +- 短对话比长独白有力:海明威的对话几乎都是 1-6 个字 → references/rhythm-and-density.md +- 对话是读者的"通风口":伦纳德"删除读者会跳过的部分",对话恰是读者不跳过的 → references/rhythm-and-density.md + +### 删标签:让读者偷听 + +- "X 说 Y 说"挂满标签节奏被切碎,"他严肃地说"把读者推出场景 → references/tags-and-attribution.md +- 用动作、环境、段落归属替代:"她把茶杯摔在桌上"比"她生气地说"传达得多 → references/tags-and-attribution.md +- 量化标准:一段来回"X 说"不超过 2-3 次,中介标签 ≤ 30% 对话 → references/tags-and-attribution.md +- 中文适配:中文"说"无变位,删标签必须补动作节拍,语气词节奏别删丢 → references/tags-and-attribution.md + +### 诊断与改写 + +- 五病诊断(太书面/标签多/一个声音/推不动/不知何时用)+ 克拉克四步逐段诊断 + 布兰德五步改写 → references/execution-flow.md +- 逐段过稿的可执行清单 → references/dialogue-revision-checklist.md + +### 边界与误区 + +- 适用范围声明(克拉克侧 frontmatter)、剧本适用性两书冲突保留、不适用场景(含"对话只是其中一部分、想整体优化"分流)、两书警告的失败模式、盲点(网文对话、多人对话归属)、易混方法与相邻 skill 区分 → references/boundaries-and-pitfalls.md + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|---------| +| references/when-to-use-dialogue.md | 布兰德 R 段"喷涌"原文、克拉克 R 段 quote/dialogue 原文、三条原则、引语 vs 对话二分与"上方传来/在场发生"判断标准、三个使用场景、对话 vs 叙述速查表、"信息不是对话的活"两书合并点、视角差异注记 | +| references/dialogue-does-things.md | 对话是事件、三大功能(推进关系/改变权力/揭示人物)、碰撞原则、闲聊藏东西、信息反例两条、查邦《卡瓦利与克雷》案例全文、《红楼梦》王熙凤中文案例 | +| references/character-voice.md | 三种声音全文、固定语言习惯与 2 个区别点标准、同一声音诊断与修、布兰德课堂 24 个故事案例、中文声音区分工具与王熙凤例 | +| references/real-speech-texture.md | 克拉克规则 3 与加质感执行、教科书式对话 ce24 全文、布兰德错误 2 全文与例句、不书面也不过真实的平衡、中文适配(语气词密度、翻译腔/公文腔信号、中文真话质感) | +| references/rhythm-and-density.md | 时间感原则全文、密度 50%-80%、海明威 1-6 字案例全文、伦纳德"通风口"案例全文、两书节奏链合并 | +| references/tags-and-attribution.md | 布兰德错误 1 全文、克拉克规则 2、去中介标签执行与茶杯例句、2-3 次与 ≤30% 双标准合并表、多人对话归属补充、中文适配(无变位归属、副词标签、语气词情绪) | +| references/execution-flow.md | 布兰德诊断五问与两条判停路由("我都不会写"→ story-planning;"想整体优化"→ 写后阶段)、克拉克 E 段四步全文、布兰德 E 段六步全文、"两个自我对话"批评法案例、日常训练汇总、两套流程衔接说明 | +| references/boundaries-and-pitfalls.md | 克拉克侧适用范围声明全文(写小说/写剧本/写场景戏/人物对白设计/对话节奏校准)与剧本适用性冲突注记(两书冲突都保留)、两书激活场景与语言信号全文、不适用边界 10 条、失败模式 6 条、盲点 7 条(含网文/微信对话体)、易混邻近方法论、相邻 skill 区分与相关 skills 指针 | +| references/_coverage.md | 两个源单元的覆盖对照表 | + +## 脚本 + +| 脚本 | 用途 | +|------|------| +| references/dialogue-revision-checklist.md | 对话改写检查清单:定病 → 逐段功能标注/在场检查 → 整场时机密度/声音区分/质感/标签计数/节奏复查 → 完稿纪律,逐条打钩过稿 | + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/pi/skills/dialogue-craft/references/_coverage.md b/framework/catalog/pi/skills/dialogue-craft/references/_coverage.md new file mode 100644 index 0000000..ad59291 --- /dev/null +++ b/framework/catalog/pi/skills/dialogue-craft/references/_coverage.md @@ -0,0 +1,22 @@ +# dialogue-craft 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| becoming-a-writer/fiction-dialogue | references/when-to-use-dialogue.md | +| becoming-a-writer/fiction-dialogue | references/rhythm-and-density.md | +| becoming-a-writer/fiction-dialogue | references/character-voice.md | +| becoming-a-writer/fiction-dialogue | references/real-speech-texture.md | +| becoming-a-writer/fiction-dialogue | references/tags-and-attribution.md | +| becoming-a-writer/fiction-dialogue | references/dialogue-does-things.md | +| becoming-a-writer/fiction-dialogue | references/execution-flow.md | +| becoming-a-writer/fiction-dialogue | references/boundaries-and-pitfalls.md | +| writing-tools-clark/dialogue-as-action | references/when-to-use-dialogue.md | +| writing-tools-clark/dialogue-as-action | references/dialogue-does-things.md | +| writing-tools-clark/dialogue-as-action | references/real-speech-texture.md | +| writing-tools-clark/dialogue-as-action | references/tags-and-attribution.md | +| writing-tools-clark/dialogue-as-action | references/rhythm-and-density.md | +| writing-tools-clark/dialogue-as-action | references/character-voice.md | +| writing-tools-clark/dialogue-as-action | references/execution-flow.md | +| writing-tools-clark/dialogue-as-action | references/boundaries-and-pitfalls.md | diff --git a/framework/catalog/pi/skills/dialogue-craft/references/boundaries-and-pitfalls.md b/framework/catalog/pi/skills/dialogue-craft/references/boundaries-and-pitfalls.md new file mode 100644 index 0000000..e21c013 --- /dev/null +++ b/framework/catalog/pi/skills/dialogue-craft/references/boundaries-and-pitfalls.md @@ -0,0 +1,160 @@ +# 边界、失败模式、盲点与相邻区分 + +来源:(多萝西娅·布兰德,《成为作家》第八章 + 第十章 + 第十一章 的 A2 与 B 段);(Roy Peter Clark,《Writing Tools: 55 Essential Strategies for Every Writer》Tool 26 的 A2 与 B 段) + +## 激活场景与语言信号 + +### 布兰德侧() + +用户会在什么情境下需要: + +1. **"我对话写不好"**——经典信号 +2. **"我对话太'说人话'/太书面"**——风格问题 +3. **"我对话总是'X 说 Y 说'"**——标签病 +4. **"我不知道什么时候用对话什么时候用叙述"**——决策问题 +5. **"我对话推动不了情节"**——对话无功能 +6. **"我对话里的人都一个声音"**——区分度问题 +7. **"我对话写得太满/太碎"**——密度问题 +8. **"我想让对话有'喷涌'感"**——风格目标 + +语言信号(用户的话里出现这些就应激活): + +- "对话写不好" +- "对话太书面" +- "什么时候用对话" +- "对话一个声音" +- "对话推动不了情节" +- "X说Y说" +- "对话没张力" +- "对话太碎/太满" + +源 frontmatter 的询问式触发词同等激活:"对话怎么写"、"小说对话技巧"、"什么时候用对话"。其中"什么时候用对话"已在上述清单,"对话怎么写"与克拉克侧"如何写对话"同义;"小说对话技巧"原包无对应信号,本次核验补录。() + +### 克拉克侧() + +用户会在什么情境下需要: + +1. 写对话时觉得"读起来像论文答辩"——人物都在说整句、不重复、不卡顿。 +2. 写了一整章对话,但情节没推进——读者跳读或弃读。 +3. 不知道一段话该用"引号 + X 说道"还是让人物在场景里说。 +4. 写到权力博弈场景(谈判、对质、审讯、家庭冲突)时,对话读起来没张力。 +5. 问"对话如何暴露人物性格"——而不是用旁白告诉读者"他很冷酷"。 + +语言信号: + +- "对话写得像答辩" +- "对话推进不了情节" +- "对话只是传递信息" +- "dialogue as action" / "对话即行动" +- "dialogue vs quote" / "对话和引语的区别" +- "对话如何暴露人物" +- "如何写对话" +- "写对话没张力" + +## 适用范围(源单元 frontmatter 声明) + +### 克拉克侧() + +源单元 frontmatter 声明的适用范围,全量保留:**写小说、写剧本、写场景戏、人物对白设计、对话节奏校准**。() + +布兰德源单元 frontmatter 未列适用范围声明,只列不适用分流(见下文"不适用边界"布兰德侧)。() + +**规则冲突(两书冲突都保留,标注冲突与各自出处)**——"写剧本"的适用性两书冲突: + +- 克拉克侧:frontmatter 适用范围含**写剧本**。() +- 布兰德侧:**写剧本**列入不适用——"剧本对话是唯一内容,不需要'什么时候用对话'的判断"。() + +两条都保留,不做单边裁决。使用指引:写剧本时打磨对白本身(对白质量、人物声音、节奏、删标签),本 skill 的方法可用(克拉克侧);布兰德侧不适用的是"什么时候用对话"这一判断——剧本对白即全体,references/when-to-use-dialogue.md 的时机框架与速查表对剧本没有适用空间。 + +## 不适用边界 + +### 布兰德侧() + +- **用户不知道怎么写故事**——那是 story-draft-flow(已并入综合 skill `story-planning`) +- **对话只是其中一部分,想整体优化**——那是写后阶段:对话只是稿子问题的一部分、用户要的是整篇整体优化时,不在对话技术层面修,先把稿子放一边再做整体优化 +- **写非虚构对话**(访谈/会议记录)——那是 transcript,不是 fiction +- **写剧本**——剧本对话是唯一内容,不需要"什么时候用对话"的判断(冲突注记:克拉克源单元 frontmatter 声明"适用于写剧本",两书冲突都保留,见上文"适用范围"节) +- **写诗/散文**——对话不是主要工具 +- **用户已经能写好对话**——这是基础技术,不是优化 + +### 克拉克侧() + +- **纯抒情独白 / 内心独白**——这是"内心 dialogue",规则不同(参见 mix-narrative-modes 的 broken line;该单元在综合 skill `narration-pov`) +- **纯动作戏(无对话)**——没有对话可优化,改用 cinematic-distances(该单元在综合 skill `scene-craft`) +- **说明文 / 议论文**——角色对话的功能性差异不适用 +- **辩论稿 / 演讲稿**——目标是说服,不是"做事";Clark 的"做事"标准会让辩论稿被错判 + +## 失败模式 + +### 布兰德警告的失败模式() + +- **"X 说 Y 说"标签**——节奏断,读者疲倦(→ references/tags-and-attribution.md) +- **对话太书面化**——失真,像"教课"(→ references/real-speech-texture.md) +- **对话都是同一声音**——失角色化(→ references/character-voice.md) +- **用对话传递信息**——说教化(→ references/dialogue-does-things.md) +- **模仿别人的对话风格**(ce02)——永远追不上(→ references/character-voice.md) + +### 克拉克警告的失败模式() + +- **"教科书式"对话(ce24)**:失败模式是写人物对话像"论文答辩"——"你是否同意 X 观点?""是的,因为……"。信号:对话中人物都"说整句、不重复、不卡顿、不用俚语"。机制:真实对话充满"半句话、重复、嗯嗯、打断";标准化对话是"作者代笔"而非"人物说话"。(全文 → references/real-speech-texture.md) + +## 盲点与时代局限 + +### 布兰德的盲点() + +- **1934 年的"对话"偏文学**——类型小说(悬疑/科幻/言情)的对话有不同要求 +- **不区分"第一人称对话"/"全知对话"**——视角影响对话限制 +- **没考虑"网文对话"**——网络连载的对话节奏更快,信息密度更高 +- **没考虑"多人对话"**——3 人以上对话的归属难题,布兰德没细说(中文落地补充 → references/tags-and-attribution.md) +- **"对话暴露人物"假设每个角色都有"真实"性格**——有时角色是"工具人",不必太深 + +### 克拉克的盲点() + +- Clark 的对话理论在**中文小说**中的迁移需要本地化:中文的"嗯"、"这个"、"那个"等语气词比英文对话标签更密集,直接套用"去中介标签"会丢失中文对话的特殊节奏。(中文适配,落地 → references/tags-and-attribution.md) +- 时代局限:Clark 写于 2006 年(英文版),未涵盖**网文 / 微信对话体**——这些是 2010 年后兴起的对话形式,有自己的一套"动作化"机制(括号表情、截图、撤回)。 + +## 容易混淆的邻近方法论 + +两本书各列一份,合并保留(show don't tell 两书都提,各自视角都留): + +### 布兰德侧() + +- **"Show don't tell"**——是大原则,对话是 show 的一种工具(跨域指针:综合 skill `show-and-omission`) +- **"潜台词"(Subtext)**——高级技术,角色不说"真话",读者自己懂 +- **"对话作为独白"(Soliloquy)**——是戏剧技术,不是小说主流 + +### 克拉克侧() + +- 与 "show, don't tell"(Tool 27):那个管"用动作和细节显示人物",这个管"对话的功能化"——前者是"如何写一个画面",后者是"如何让声音做事"。(跨域指针:综合 skill `show-and-omission`) +- 与 "active verbs"(Tool 3):那个管"动词的力度",这个管"对话作为动词事件"——前者是"句法",后者是"叙事事件类型"。 + +## 与相邻 skill 的区分 + +跨域引用只留一句话指针: + +### 布兰德侧() + +- **与 `fiction-opening` 的区别**:fiction-opening 是"怎么写第一句"(包括用对话);fiction-dialogue 是"怎么用对话"的整体技术。前者是局部,后者是贯穿。(fiction-opening 已并入综合 skill `story-structure` 的开篇段) +- **与 `fiction-scene-craft` 的区别**:fiction-dialogue 是"对话"这个工具;fiction-scene-craft 是"场景/节奏"这个整体。前者是工具,后者是框架。(fiction-scene-craft 已并入综合 skill `scene-craft`) +- **与"模仿技术而非风格"的区别**:那个教"学别人的对话节奏";本 skill 教"自己写对话"。前者是模仿,后者是原创。(该方法未入本技能库,区分条目按原文保留) + +### 克拉克侧() + +- 与 `mosaic-of-detail` 的区别:那个用"具体物清单"显示人物,这个用"对话做的事"显示人物——前者是"物品语言",后者是"声音语言"。(mosaic-of-detail 在综合 skill `character-presentation`) +- 与 `voice-equalizer` 的区别:那个管"作者声音的杠杆"(节奏、句长、词汇),这个管"角色声音的功能"(让对话推进情节)。(voice-equalizer 在综合 skill `prose-craft`) +- 与 `mix-narrative-modes` 的区别:那个是"主线 / 折线 / 蒙太奇"等叙事模式调度,这个专注对话作为单一模式的功能最大化。(mix-narrative-modes 在综合 skill `narration-pov`) + +## 相关 skills(原书登记,指针化) + +### 布兰德侧() + +- **composes-with** `fiction-opening`:方法 2(对话开头)的延伸(→ `story-structure`) +- **composes-with** `fiction-scene-craft`:对话是场景的一部分(→ `scene-craft`) +- **composes-with**"作者的双重自我":角色差异化来自作者的多视角(该方法未入本技能库,关系条目按原文保留) +- **composes-with** `story-draft-flow`:阶段 4-5 的内部技术(→ `story-planning`) + +### 克拉克侧() + +- depends-on:无 +- contrasts-with:`mosaic-of-detail`(用"物"显示人物 vs 用"声音"显示人物)(→ `character-presentation`) +- composes-with:`cinematic-distances`(对话放在哪个镜头距离?)(→ `scene-craft`)、`voice-equalizer`(对话的语言风格统一)(→ `prose-craft`) diff --git a/framework/catalog/pi/skills/dialogue-craft/references/character-voice.md b/framework/catalog/pi/skills/dialogue-craft/references/character-voice.md new file mode 100644 index 0000000..5d50239 --- /dev/null +++ b/framework/catalog/pi/skills/dialogue-craft/references/character-voice.md @@ -0,0 +1,87 @@ +# 角色声音:让每个人说的话像那个人 + +来源:(多萝西娅·布兰德,《成为作家》第八章 + 第十章 + 第十一章);与 的"揭示人物"功能合并 + +## 布兰德的三种声音 + +角色对话的差异化,布兰德给了三种声音。() + +### 声音 1:"听上去像那个人" + +- 每个角色说话的**节奏/用词/句长**应该**像那个人** +- 老人说话 vs 年轻人说话:句长不同,用词不同 +- 受过教育 vs 没受过教育:词汇量不同 +- 性格内向 vs 外向:句子长度不同(内向更短) +- **怎么练**:第二遍阅读时,标出不同角色的对话,听"他们声音不同吗" + +() + +### 声音 2:"暴露人物" + +- 好的对话,**让人物**自己暴露性格/价值观/关系 +- 不需要"叙述者说:他很紧张"——让他说话时暴露 +- 例:"我没想伤害她,我只是想——"(暴露:内疚,怕被拒绝) +- **怎么练**:写完对话,删掉"叙述者说明",看对话本身能不能让人懂 + +() + +两本书在这条上合并:Clark 把"揭示人物"列为对话"做事"的三大功能之一(推进关系 / 改变权力 / 揭示人物),并反对用旁白代替暴露——"而不是用旁白告诉读者'他很冷酷'"。() + +### 声音 3:"推动情节" + +- 好的对话,**让情节前进一步** +- 不是"闲话"——不是角色聊天气/吃饭/与情节无关 +- 哪怕是"闲聊",也**隐含**着冲突/价值观 +- 例:两个角色聊童年——表面是闲聊,实际在对比"谁更惨" + +(;与 Clark"推进关系/改变权力"合并,展开见 references/dialogue-does-things.md) + +## 给每个角色固定语言习惯 + +修法与量化标准:() + +- **怎么修**(发现一个声音之后):给每个角色**固定的语言习惯**(口头禅/句长/用词) +- 例:一个人总说"反正",另一个人总说"你懂的"——这就是区分 +- 执行标准:能列出 2-3 个角色的"口头禅/句长/用词";至少 2 个区别点(口头禅/句长) +- 例:角色 A 总说"反正",角色 B 总说"你懂的" + +() + +## "同一个声音"的诊断与修 + +这是布兰德列的对话三大常见错误之一(错误 3),全量保留:() + +- **错误 3:对话都是"同一个声音"** +- 全部角色用**作者的口吻**说话——那是因为作者没用"不同的声音" +- 怎么发现:把对话单独抽出来,看每段是不是能**区分**是谁 +- **怎么修**:给每个角色**固定的语言习惯**(口头禅/句长/用词) +- 例:一个人总说"反正",另一个人总说"你懂的"——这就是区分 + +() + +## 案例全文:布兰德的课堂实验——同一提纲 24 个故事 + +- **问题**:不知道怎么让故事有"自己的声音" +- **方法论的使用**:同一提纲,24 个学生写 24 个故事,每个对话声音都不同 +- **结论**:对话声音的差异 = 作者视角的差异 = 原创性 +- **结果**:学生发现自己对话的"声音",不必模仿别人 + +() + +由此引出的失败模式:**模仿别人的对话风格**(ce02)——永远追不上;对话声音的差异本身就是作者视角的差异,那是原创性。() + +## 中文适配与中文落地 + +(以下第 1 条为源单元原有内容,第 2-4 条为本次合并补充,标注"中文适配") + +1. Clark 的"揭示人物"在中文里同样成立:中文的"嗯"、"这个"、"那个"等语气词比英文对话标签更密集,用不用、怎么用这些词,本身就是人物声音的一部分。(,中文适配) +2. **中文区分声音的现成工具**(中文适配):称呼语与敬语(你/您、职称、老 X/小 X、亲属称谓)、语气词习惯(吧/呢/嘛/啊各人不同)、方言词与儿化音、书面语与口语的配比(有人张嘴就是成语,有人全是短句碎句)。给角色定语言习惯时,这些比"口头禅"更不容易写油。 +3. **中文范本**(中文适配):《红楼梦》第三回王熙凤出场,"我来迟了,不曾迎接远客!"——人未到声先到,一句话立住泼辣、得宠、越礼三层性格,是"听上去像那个人 + 暴露人物"的合一。判断标准照布兰德的来:遮住名字,读这句话能不能认出是谁。 +4. **网文与类型小说**(中文适配):网文对话节奏快、信息密度高,角色声音区分更要靠固定语言习惯——连载里读者跳着读,声音不稳的角色会互相混成一个人。 + +## 本主题常见误区 + +- **对话都是同一声音**——全用作者的口吻说话;用口头禅、句长、用词修,至少 2 个区别点。() +- **用叙述者说明代替暴露**——"他很紧张"式旁白;删掉旁白,看对话本身能不能让人懂。(;) +- **模仿别人的对话风格**(ce02)——追别人的声音永远追不上。() +- **"对话暴露人物"的适用前提**——假设每个角色都有"真实"性格;有时角色是"工具人",不必太深(布兰德的盲点之一,→ references/boundaries-and-pitfalls.md)。() diff --git a/framework/catalog/pi/skills/dialogue-craft/references/dialogue-does-things.md b/framework/catalog/pi/skills/dialogue-craft/references/dialogue-does-things.md new file mode 100644 index 0000000..87240b8 --- /dev/null +++ b/framework/catalog/pi/skills/dialogue-craft/references/dialogue-does-things.md @@ -0,0 +1,69 @@ +# 给每段对话派任务:对话是事件,不是装饰 + +来源:(Roy Peter Clark,《Writing Tools: 55 Essential Strategies for Every Writer》Tool 26);(多萝西娅·布兰德,《成为作家》第八章 + 第十章 + 第十一章) + +## 核心命题:对话不是装饰,是事件 + +Clark 给场景写作的核心定位:**对话不是装饰,是事件。** 写对话要"做事"——推进关系 / 改变权力 / 揭示人物,而非传递信息。() + +## 对话的三大功能(克拉克规则 1) + +每段对话至少做成三件事里的一件:() + +1. **推进关系**——两人之间的距离、亲疏、攻守在这一段里发生了变化 +2. **改变权力**——谁占上风、谁被拿捏、谁翻盘,在这段话之后不一样了 +3. **揭示人物**——读者通过角色怎么说话,看清这个人是谁 + +执行方法:找出场景中所有对话,逐一问:"这段对话在做事吗?推进关系 / 改变权力 / 揭示人物,还是只是传递信息?"每段对话被标注"做事"或"传信息";只传信息且无法改写为"做事"的,标记为删除候选。(完整流程 → references/execution-flow.md)() + +## 好对话是碰撞,不是交换 + +布兰德从冲突角度说同一件事:() + +- 对话**不仅**强调冲突,**而且**制造冲突(原则 3,见 references/when-to-use-dialogue.md) +- 好的对话 = 角色在**不同的目标/价值观**上碰撞 +- 坏的对话 = 角色在"分享信息"——那应该用叙述 + +中文落地:中文小说里"碰撞"常藏在礼数底下——饭桌上客客气气的敬酒词,每句都在争座次、争面子、争话语权;写碰撞不一定要吵架,把目标和价值观的对立压进客套话里,张力反而更大。(中文落地说明,方法出自) + +## 闲聊也要藏东西 + +哪怕写的是"闲聊",也得隐含冲突或让情节前进一步:() + +- 好的对话,**让情节前进一步** +- 不是"闲话"——不是角色聊天气/吃饭/与情节无关 +- 哪怕是"闲聊",也**隐含**着冲突/价值观 +- 例:两个角色聊童年——表面是闲聊,实际在对比"谁更惨" + +() + +## 信息不是对话的活:让角色用嘴交代背景是最糟的"告诉" + +两本书在这条上合并:(;) + +- 布兰德:需要**传递信息**(背景/前情/设定)时,**不要**用对话——那是"告诉"的最糟方式;用叙述/独白/闪回。() +- Clark:引语(quote)提供信息与解释,对话(dialogue)让情节变厚;信息是引语和叙述的活,不是对话的活。() + +反例两个,照原样保留:() + +- 例:不要用两个角色说"你知道吗,上世纪 90 年代我们..." +- **反例**:"老师对学生说:'写作需要想象力...'"——这是说教,不是故事 + +## 案例全文:查邦《卡瓦利与克雷的神奇冒险》对话开篇 + +Michael Chabon《Kavalier & Clay》对话开篇(Clark 评价"对话即行动"的金标准案例):() + +- **问题**:如何在第一章就让人物关系"瞬间定型"? +- **方法论的使用**:Chabon 让 Joe 和婶婶的对话从"什么是漫画书?"开始——表面温和,每个动作("head down", "shoulder against the door frame")都在场景中"做事",同时揭示 Joe 的羞涩、婶婶的惊讶、家族氛围。 +- **结论**:对话是"角色正在发生的事件",读者通过偷听获得信息,而非被告知。 +- **结果**:成为了 Clark 评价"对话即行动"的金标准案例;展示了"开篇对话 = 关系 + 性格 + 氛围"的复合功能。 + +() + +中文落地:中文开篇对话做复合功能的经典样本是《红楼梦》第三回王熙凤出场——人没到,"我来迟了,不曾迎接远客!"先到:一句话同时做了三件事,立住人物声音(揭示人物)、压住全场辈分秩序(改变权力)、让黛玉和读者瞬间知道这个人在家族里的位置(推进关系)。写中文开篇对话可以照这个标准自查:这一句做了几件事?只做"传递信息"一件事的,改。(中文适配:中文案例补充,判断标准出自) + +## 常见误区(本主题相关) + +1. **用对话的嘴传信息**——"你知道吗,上世纪 90 年代……"式对话是说教,不是故事;信息交给叙述。(;) +2. **拿闲聊当对话**——"今天天气真好"直接删;日常对话得透出人物真正的担忧再用。() +3. **写了一整章对话,情节没推进**——读者跳读或弃读;每段对话都要过"做事还是传信息"的标注。() diff --git a/framework/catalog/pi/skills/dialogue-craft/references/dialogue-revision-checklist.md b/framework/catalog/pi/skills/dialogue-craft/references/dialogue-revision-checklist.md new file mode 100644 index 0000000..a334795 --- /dev/null +++ b/framework/catalog/pi/skills/dialogue-craft/references/dialogue-revision-checklist.md @@ -0,0 +1,96 @@ +# 对话改写检查清单 + +> 把两个源单元的可执行步骤串成一份逐段过稿清单:先定病,再逐段过功能、在场、质感、标签,最后整场复查。 +> 方法全文见 [references/execution-flow.md](execution-flow.md);速查表见 [references/when-to-use-dialogue.md](when-to-use-dialogue.md)。 + +## 〇、定病:这段对话的问题是哪一种 + +先回答(): + +- [ ] (a) 太书面?→ 重点过第五节 +- [ ] (b) 标签太多?→ 重点过第六节 +- [ ] (c) 一个声音?→ 重点过第四节 +- [ ] (d) 推动不了情节?→ 重点过第一、二节 +- [ ] (e) 不知道什么时候用?→ 先对第八节速查表 +- [ ] 判停:若"我都不会写"——问题不在对话,在整篇流程,先走 story-planning +- [ ] 判停:若对话只是其中一部分、想整体优化——不在对话层面修,走写后阶段:先把稿子放一边再做整体优化 + +## 一、功能标注(逐段) + +找出场景中所有对话,逐段问(): + +- [ ] 这段对话在做事吗?——推进关系 / 改变权力 / 揭示人物,还是只是传递信息? +- [ ] 每段都已标注"做事"或"传信息" +- [ ] 只传信息且改写不成"做事"的,已列为删除候选 +- [ ] 表面闲聊的段落,确认隐含冲突或让情节前进一步(两角色聊童年 = 在比"谁更惨")() +- [ ] 没有用对话的嘴交代背景/前情/设定("你知道吗,上世纪 90 年代我们..."式句子已改为叙述)() + +## 二、在场检查(逐段) + +对每段保留的对话问(): + +- [ ] 这句话是"在场发生"(dialogue)还是"事后补话"(quote)? +- [ ] "事后补话"已改写为当下场景,或转叙述/动作/内心独白 +- [ ] 判停:需要"事后才知道"的内容,改成当下场景或转 narrator 描述,不保留"事后补话"形式 + +## 三、时机与密度(整场) + +对照速查表与三场景框架(): + +- [ ] 冲突/高潮段落用了对话,密度在 50%-80% +- [ ] 信息/说明段落交给叙述、独白或闪回,没有让角色用嘴讲课 +- [ ] 日常/过渡段落的对话隐含冲突;纯"今天天气真好"已删 + +## 四、声音区分度(整场) + +- [ ] 把对话单独抽出来,能分清每段是谁说的() +- [ ] 每个主要角色有固定语言习惯(口头禅/句长/用词),至少 2 个区别点(角色 A"反正"/角色 B"你懂的")() +- [ ] 句长、用词、节奏贴合人物的年龄、教育、性格(内向更短)() +- [ ] 删掉叙述者说明后,对话本身仍能让读者懂人物("我没想伤害她,我只是想——"自带内疚);不懂的段落回头加动作() + +## 五、质感检查(逐段) + +- [ ] "做事"对话中已插入 1-2 处"半句话/重复/嗯/打断/俚语"() +- [ ] 改写后至少 1 处非标准化表达(口音、停顿、思维跳跃、方言词)() +- [ ] 没有"论文答辩"式对白——"你是否同意 X 观点?""是的,因为……"(ce24 信号:说整句、不重复、不卡顿、不用俚语)() +- [ ] 没有"我非常感谢你的意见"式书面台词() +- [ ] 判停:插入质感后通读,确认不像台词剧本、不是逐字录音(;) +- [ ] 中文自查:无翻译腔("哦,我的天"、代词用满)、无公文腔(会议体家常话)(中文适配:本次合并补充) + +## 六、标签计数(逐段 + 全篇) + +- [ ] 一段来回里"X 说"不超过 2-3 次() +- [ ] 中介标签 ≤ 30% 对话,其余用动作/沉默/表情替代() +- [ ] "他严肃地说""她解释道"式副词标签已换成动作("她把茶杯摔在桌上")() +- [ ] 归属不清处用段落归属 + 动作节拍补上,不只删不补(;中文适配:中文"说"无变位,删标签要补动作) +- [ ] 中文语气词节奏没被删丢("嗯/这个/那个"比英文标签密,删过头对话失掉自身节奏)(,中文适配) + +## 七、节奏复查(整场) + +- [ ] 高潮段对话切成短交换,没有拖节奏的长独白() +- [ ] 对话与叙述的配比让页面有"通风口"——读者会跳过的部分已删(伦纳德标准)() +- [ ] 大段叙述没有压在需要快的段落上(切小段 = 时间快,大段叙述 = 时间慢)() + +## 八、对话 vs 叙述速查表 + +| 场景 | 优先用 | +|---|---| +| 冲突/高潮 | 对话 | +| 信息/说明 | 叙述 | +| 动作/事件 | 叙述 | +| 思考/感受 | 叙述或内心独白 | +| 角色关系/性格 | 对话(暴露) | +| 日常/过渡 | 看情况(隐含冲突才用) | +| 故事开头 | 可用对话(建声音)或不用 | + +() + +## 九、完稿纪律 + +- [ ] 写完立刻放一边,至少隔一夜再读对话 +- [ ] 重读时可用布兰德"两个自我对话"批评法:一个自我写,一个自我批,用对话形式逐段审,比独白式自查更具体、不极端 + +## 日常训练(不在改稿时用) + +- [ ] 第二遍阅读时标出不同角色的对话,听他们声音是否不同() +- [ ] 听身边人说话,录下来,看真实的说法长什么样() diff --git a/framework/catalog/pi/skills/dialogue-craft/references/execution-flow.md b/framework/catalog/pi/skills/dialogue-craft/references/execution-flow.md new file mode 100644 index 0000000..54251c5 --- /dev/null +++ b/framework/catalog/pi/skills/dialogue-craft/references/execution-flow.md @@ -0,0 +1,96 @@ +# 诊断与改写流程:从"我的对话哪里病了"到逐段修完 + +来源:(Roy Peter Clark,《Writing Tools: 55 Essential Strategies for Every Writer》Tool 26 的 E 段四步);(多萝西娅·布兰德,《成为作家》第八章 + 第十章 + 第十一章 的 E 段六步) + +两套流程合并使用:克拉克四步管"逐段诊断"(每段对话做什么、是不是在场、有没有质感、标签多不多),布兰德六步管"定病 + 逐段改写 + 完稿纪律"。可执行版清单 → references/dialogue-revision-checklist.md。 + +## 第 0 步:诊断入口——用户的对话问题在哪(布兰德 E 步骤 1) + +全量保留:() + +- 完成标准:用户能指出"我的对话是 X 问题" +- 提问:"你的对话问题是——(a) 太书面?(b) 标签太多?(c) 一个声音?(d) 推动不了情节?(e) 不知道什么时候用?" +- 判停条件:若用户说"我都不会写" → 路由到 `story-planning` 的起草流程阶段 1,不在本 skill 内解决 +- 判停条件:若用户的问题里对话只是其中一部分、想整体优化 → 走写后阶段:不在对话技术层面修,先把稿子放一边再做整篇优化 + +各病对应的治法入口: + +| 病 | 治法入口 | +|---|---| +| (a) 太书面 | references/real-speech-texture.md | +| (b) 标签太多 | references/tags-and-attribution.md | +| (c) 一个声音 | references/character-voice.md | +| (d) 推动不了情节 | references/dialogue-does-things.md | +| (e) 不知道什么时候用 | references/when-to-use-dialogue.md | + +## 克拉克四步:逐段功能诊断(全量保留) + +() + +1. **诊断对话的功能** + - 找出场景中所有对话,逐一问:"这段对话在做事吗?推进关系 / 改变权力 / 揭示人物,还是只是传递信息?" + - 完成标准:每段对话被标注"做事"或"传信息";只传信息且无法改写为"做事"的,标记为删除候选。 + +2. **判断引语 vs 对话** + - 对每个被保留的对话,问:"这句话是角色在场景里说的(dialogue),还是事后补话(quote)?" + - 完成标准:每段对话的角色定位明确——"在场说话"或"事后补话";"事后补话"被改写到"在场说话",或改用其他方式(内心独白、动作)。 + - 判停条件:若对话需要"事后才知道",应改成"当下场景",或转用 narrator 描述;不要保留"事后补话"形式。 + +3. **加生活质感** + - 在"做事"对话中插入 1-2 个"半句话 / 重复 / 嗯 / 打断 / 俚语"——让对话"听着像人"。 + - 完成标准:改写后的对话中至少 1 处非标准化表达(口音、停顿、思维跳跃、方言词)。 + - 判停条件:若场景中角色均为"标准话",插入 1-2 处后通读,确认不像台词剧本。 + +4. **去中介标签** + - 把"他严肃地说"、"她解释道"等中介标签删掉,用动作标签替代("她把茶杯摔在桌上")。 + - 完成标准:中介标签 ≤ 30% 对话;其余用动作 / 沉默 / 表情替代。 + +## 布兰德五步:改写执行(E 步骤 2-6,全量保留) + +() + +1. **第一步:选好"什么时候用对话"** + - 完成标准:用户能用"3 个使用场景"框架判断 + - 关键:冲突/高潮必用,信息/说明用叙述,日常/过渡看情况 + +2. **第二步:给每个角色"固定语言习惯"** + - 完成标准:用户能列出 2-3 个角色的"口头禅/句长/用词" + - 关键:至少 2 个区别点(口头禅/句长) + - 例:角色 A 总说"反正",角色 B 总说"你懂的" + +3. **第三步:写对话时减少"标签"** + - 完成标准:用户承诺"一段对话中,'X 说'不超过 2-3 次" + - 关键:用动作/环境/段落归属代替标签 + +4. **第四步:检查对话"暴露人物/推动情节"** + - 完成标准:用户的每段对话,都**暴露**人物(性格/价值观)或**推动**情节 + - 检验:删掉叙述者说明,看对话本身能不能让读者懂 + +5. **第五步:写完不立即重读** + - 完成标准:用户承诺"写完后立刻放一边,至少隔一夜" + - 隔一夜再读对话,声音差异和标签问题才听得出来 + +## 案例全文:布兰德的"两个自我对话"批评法 + +布兰德 A1 案例 2,全量保留:() + +- **问题**:不知道如何自我批评 +- **方法论的使用**:假装是**两个**自己在对话(一个写得好,一个写得不好) +- **结论**:自我对话**用对话的形式**,比独白有效 +- **结果**:自我批评更具体,不会极端 + +用法:隔夜重读对话时,把"作者自我"和"批评者自我"分成两个声音对话,逐段审对话的声音、标签与功能。 + +## 日常训练(布兰德散见各条的"怎么练",汇总) + +() + +1. **第二遍阅读**时,标出不同角色的对话,听"他们声音不同吗"(声音 1 的练法,→ references/character-voice.md)。 +2. **写完对话,删掉"叙述者说明"**,看对话本身能不能让人懂(声音 2 的练法,→ references/character-voice.md)。 +3. **听身边人说话,录下来**,看你**真的**怎么说话(错误 2 的练法,→ references/real-speech-texture.md)。 + +## 两套流程的衔接说明(合并整合) + +- 顺序建议:先走克拉克四步(逐段过功能、在场性、质感、标签),再走布兰德五步里的第一、二步(时机框架、语言习惯)做整场复查——克拉克是逐段显微镜,布兰德是整场框架。 +- 两套完成标准都保留,不互相覆盖:克拉克的"≤ 30% 中介标签"与布兰德的"一段 2-3 次 X 说"分别计数(→ references/tags-and-attribution.md)。 +- 判停条件都保留:克拉克两处判停(事后补话的处理、质感插入后通读),布兰德两处判停("我都不会写"→ story-planning;"对话只是其中一部分、想整体优化"→ set-aside-the-manuscript 写后阶段,该单元已裁剪、路由注记保留)。 diff --git a/framework/catalog/pi/skills/dialogue-craft/references/real-speech-texture.md b/framework/catalog/pi/skills/dialogue-craft/references/real-speech-texture.md new file mode 100644 index 0000000..6828a3a --- /dev/null +++ b/framework/catalog/pi/skills/dialogue-craft/references/real-speech-texture.md @@ -0,0 +1,59 @@ +# 真话质感:让对话像真人说话 + +来源:(Roy Peter Clark,《Writing Tools: 55 Essential Strategies for Every Writer》Tool 26);(多萝西娅·布兰德,《成为作家》第八章 + 第十章 + 第十一章) + +两本书在这条上合并:Clark 的规则 3(避免论文化)与布兰德的错误 2(太书面化/太完美)说的是同一件事,合并一条,各自视角与例句全部保留。 + +## 克拉克规则 3:避免论文化 + +真实对话有"半句话、重复、嗯嗯、打断";标准化对话是作者代笔,不是人物。() + +执行(加生活质感):在"做事"对话中插入 1-2 个"半句话 / 重复 / 嗯 / 打断 / 俚语"——让对话"听着像人"。完成标准:改写后的对话中至少 1 处非标准化表达(口音、停顿、思维跳跃、方言词)。判停条件:若场景中角色均为"标准话",插入 1-2 处后通读,确认不像台词剧本。() + +## 失败模式全文:教科书式对话(ce24) + +Clark 在书中警告的失败模式,全量保留:() + +- **"教科书式"对话(ce24)**:失败模式是写人物对话像"论文答辩"——"你是否同意 X 观点?""是的,因为……"。信号:对话中人物都"说整句、不重复、不卡顿、不用俚语"。机制:真实对话充满"半句话、重复、嗯嗯、打断";标准化对话是"作者代笔"而非"人物说话"。 + +对应激活场景:写对话时觉得"读起来像论文答辩"——人物都在说整句、不重复、不卡顿。() + +## 布兰德错误 2:对话太"书面化"/太"完美" + +全量保留:() + +- **错误 2:对话太"书面化"/太"完美"** +- 真实的人说话:有停顿,有"嗯"/"那个"/"就是说" +- 太书面:"我非常感谢你的意见"——没人这么说话 +- 真实:"嗯,我觉得还行,反正..." +- **怎么练**:听身边人说话,录下来,看你**真的**怎么说话 +- **平衡**:不要"太真实"(文学要节奏)——但**不要**完全"书面化" + +() + +## 平衡:不书面,也不过真实 + +两个方向的错误都要防,这是两本书共同的分寸: + +- 太书面 = 失真,像"教课"(布兰德警告的失败模式之一)。() +- 太真实 = 一字不落地记录"嗯""啊"会丢掉小说的节奏,质感要控制——"不要'太真实'(文学要节奏)"。() +- 插入 1-2 处非标准化表达后要通读,确认不像台词剧本——过了就成录音稿。() + +## 中文适配 + +### 源单元原有的中文适配条目 + +- Clark 的对话理论在**中文小说**中的迁移需要本地化:中文的"嗯"、"这个"、"那个"等语气词比英文对话标签更密集,直接套用"去中介标签"会丢失中文对话的特殊节奏。(,中文适配) + +### 本次合并补充(中文适配) + +- **翻译腔信号**:对话里出现"哦,我的天"、"我向你保证"、每句话以"你知道的"开头、代词用满(他/她反复出现而不靠称呼和上下文省略)、每句都是主谓宾完整的书面句——这是翻译过来的腔调,不是中文口语。自查法:把对话念出声,舌头打结、平时没人这么说的,就是翻译腔。 +- **公文腔信号**:角色对家人朋友说会议体——"我们要认真对待这件事"、"总体来说我同意你的看法,但是……"、"这个问题我们要分两方面看"。这是论文答辩式对话(ce24)的中文变体:信号同样是"说整句、不重复、不卡顿",只是把英文教科书腔换成了机关腔。 +- **中文真话质感长什么样**:省略多("走了啊"而不是"我要先离开了")、倒装("真好吃,这个")、称呼代替代词("妈给你留了饭"而不是"我给你留了饭")、语气词收尾(吧、呢、嘛、啊、呗)、半句话和打断("我其实——算了,没什么")。按 Clark 的分寸:每段挑 1-2 处用,不是逐字录音。 +- **方言的分寸**:方言词可以做角色区别点(→ references/character-voice.md),但整段方言会挡住非本地读者;用词点缀,不用方言写整句语法。 + +## 本主题常见误区 + +1. **答辩式对话**——人物全说整句、不重复、不卡顿、不用俚语,像论文答辩;信号一出现就是作者在代笔。() +2. **太书面**——台词完美得不像人话;"我非常感谢你的意见"没人这么说话。() +3. **太真实**——纯录"嗯啊"会丢小说节奏;插 1-2 处质感后通读,确认不像台词剧本。(;) diff --git a/framework/catalog/pi/skills/dialogue-craft/references/rhythm-and-density.md b/framework/catalog/pi/skills/dialogue-craft/references/rhythm-and-density.md new file mode 100644 index 0000000..a5260e8 --- /dev/null +++ b/framework/catalog/pi/skills/dialogue-craft/references/rhythm-and-density.md @@ -0,0 +1,51 @@ +# 节奏与密度:对话的时间感、短对话、通风口 + +来源:(多萝西娅·布兰德,《成为作家》第八章 + 第十章 + 第十一章);(Roy Peter Clark,《Writing Tools: 55 Essential Strategies for Every Writer》Tool 26) + +## 布兰德原则 2:对话要"增强时间感" + +全量保留:() + +- 短的对话,加上周围的叙述,**增强**段落的紧凑感 +- 长的独白,不如短的交换 +- 一页纸上**被分割成数不清的小段**对话 = 时间快,节奏紧 +- 反过来:大段叙述 = 时间慢,节奏松 + +R 段原文对应句:"这种波涛的升高和薄落,这种浪潮的喷涌,即使只表现为一页纸上被分割成数不清的小段的对话,也足以让它的时间感增强了,段落的时间感增强。"(原文全引 → references/when-to-use-dialogue.md)() + +## 密度标准 + +- 冲突/高潮场景:**对话占比 50%-80%**(布兰德"场景 1:冲突/高潮——必用对话"的密度项)。() +- 故事开头:可用对话(建声音)或不用(速查表条目)。() + +## 案例全文:海明威的"短对话"风格 + +- **问题**:想知道"对话怎么用最有力" +- **方法论的使用**:海明威的对话几乎都是 1-6 个字("嗯"/"好"/"是") +- **结论**:**短对话**比长独白有力,节奏快 +- **结果**:像"喷涌"——强张力 + +() + +## 案例全文:伦纳德(Elmore Leonard)的写作哲学——对话是通风口 + +- **问题**:写作时如何决定"删什么"? +- **方法论的使用**:Leonard 给出标准——"删除读者会跳过的部分"。"而对话是读者不会跳过的部分"——对话的白色空间在视觉上吸引眼睛,本身就是场景的"通风口"。 +- **结论**:对话承担"读者粘性"功能,是小说节奏的调节器。 +- **结果**:成为了"对话 vs 描述"决策的金句;说明对话不是"信息容器",是"注意力锚点"。 + +() + +## 两本书的合并点 + +- 布兰德管**对话内部的时间感**:切小段提速、短交换强过长独白、叙述包裹对话。() +- Clark(借伦纳德)管**对话在页面上的注意力功能**:对话是读者不跳过的部分,空白本身调节节奏。() +- 合起来是一条完整节奏链:场景内的快慢靠对话长短与切段(布兰德),场景之间的透气靠对话与叙述的配比(伦纳德标准)。 + +中文落地:中文网文连载的对话密度普遍偏高,大段叙述在手机阅读里容易被跳过——伦纳德的"删除读者会跳过的部分"在网文语境下几乎是硬规则;但布兰德的提醒同样成立:对话的喷涌要靠叙述铺垫,全是碎对话没有叙述包裹,张力反而泄掉。两边标准的用法:用伦纳德标准砍掉读者会跳的叙述,用布兰德标准保住高潮场景 50%-80% 的对话密度和外围叙述。(中文落地说明,规则出自、) + +## 相关误区与边界 + +- **对话写得太满/太碎**——这是激活本 skill 的典型信号之一;太满(全是独白)拖节奏,太碎(没有叙述包裹)泄张力。() +- **长独白不如短的交换**——独白拖慢时间感;需要角色长篇表达时,拆成交换或让叙述打断。() +- **网文对话**是布兰德没考虑过的形态:网络连载的对话节奏更快,信息密度更高(布兰德盲点,完整清单 → references/boundaries-and-pitfalls.md)。() diff --git a/framework/catalog/pi/skills/dialogue-craft/references/tags-and-attribution.md b/framework/catalog/pi/skills/dialogue-craft/references/tags-and-attribution.md new file mode 100644 index 0000000..829f24f --- /dev/null +++ b/framework/catalog/pi/skills/dialogue-craft/references/tags-and-attribution.md @@ -0,0 +1,72 @@ +# 标签与归属:删"X 说 Y 说",让读者偷听 + +来源:(多萝西娅·布兰德,《成为作家》第八章 + 第十章 + 第十一章);(Roy Peter Clark,《Writing Tools: 55 Essential Strategies for Every Writer》Tool 26) + +两本书在这条上合并:布兰德的错误 1("X 说 Y 说"标签)与 Clark 的规则 2(让读者偷听、去中介标签)方向一致,合并一条;各自的量化标准与例句全量保留。 + +## 布兰德错误 1:"X 说 Y 说"标签 + +全量保留:() + +- **错误 1:"X 说 Y 说"标签** +- 不要每句话都加"X 说"/"Y 说"/"他说"/"她回答" +- 标签用**过头** = 节奏断,读者疲倦 +- **怎么做**:段落归属 + 偶尔插入"她说" +- 真正好的对话:**靠动作/环境**暗示谁在说话,不靠"说" + +执行标准(布兰德 E 步骤):一段对话中,"X 说"不超过 2-3 次;用动作/环境/段落归属代替标签。() + +## 克拉克规则 2:让读者偷听 + +让读者偷听——去掉"他说"等中介标签,让读者直接进入场景。() + +这一条的理论根据是引语/对话二分:读者"偷听"到对话发生,叙事才被推进;中介标签把读者拦在场景外面,偷听变成听转述。(→ references/when-to-use-dialogue.md)() + +## 克拉克执行:去中介标签(含例句与量化标准) + +全量保留:() + +- 把"他严肃地说"、"她解释道"等中介标签删掉,用动作标签替代("她把茶杯摔在桌上")。 +- 完成标准:中介标签 ≤ 30% 对话;其余用动作 / 沉默 / 表情替代。 + +() + +## 两本书的量化标准合并 + +| 标准 | 数值 | 出处 | +|---|---|---| +| 一段来回里"X 说"的次数 | 不超过 2-3 次 | | +| 中介标签占全部对话的比例 | ≤ 30% | | +| 替代手段 | 动作 / 环境 / 沉默 / 表情 / 段落归属 | 两本书合并 | + +两条标准不冲突,分别管两个层面:布兰德数的是单段来回里的显性标签个数,Clark 算的是全篇中介标签占比。中文落地时两条一起用:先按 Clark 的 30% 扫全篇,再按布兰德的 2-3 次抠单段。(合并说明) + +## 视角差异注记(不冲突,互补) + +- 布兰德保留"偶尔插入'她说'":标签不是全删,是用过头才病;对话靠外围叙述托着("为了创作这个段落,作家必须依赖他的叙事能力")。() +- Clark 的删法更彻底:中介标签(尤其带情绪的"他严肃地说")直接删,让动作说话。() + +实操取中间:归属不明时保留最朴素的"说",带副词的情绪标签("严肃地说""生气地说")一律换成动作。(合并说明,依据上面两条原文) + +## 多人对话的归属难题(布兰德盲点,本条补充) + +布兰德没细说 3 人以上对话的归属难题(其盲点之一,→ references/boundaries-and-pitfalls.md)。中文落地办法(中文适配:本次合并补充): + +- 3 人以上场景,每个新说话人出场给一次归属(动作或名字),之后靠段落和声音习惯维持 +- 用各角色固定语言习惯做无标签归属(→ references/character-voice.md):声音区分度够高,读者不需要"X 说"也知道是谁 +- 超过 4 人同时说话的场景,考虑用叙述点名其中一两个,其余并入群像 + +## 中文适配 + +(以下除第 1 条外为本次合并补充,标注"中文适配") + +1. 中文的"嗯"、"这个"、"那个"等语气词比英文对话标签更密集,直接套用"去中介标签"会丢失中文对话的特殊节奏——删标签删到对话失掉自身节奏就是删过头。(,中文适配) +2. **中文归属的天然弱点**(中文适配):中文"说"没有人称变位、没有首字母大写,说话人切换完全靠分段、动作和语境;英文里能靠形式区分的地方,中文必须靠动作节拍(beat)补——删标签的代价在中文里更高,替换动作要跟上,不能只删不补。 +3. **中文最常见的中介标签是副词标签**(中文适配):"他严肃地说"、"她不悦地回道"、"他意味深长地说"——翻译腔小说里尤其密集。按 Clark 标准这些全在 ≤ 30% 的清点范围里,优先删。 +4. **语气词分担情绪功能**(中文适配):中文里"吧、呢、嘛、呗"本身携带情绪和态度,"她说:'好吧。'和'她说:'好。'"情绪不同;删标签后用语气词和标点找补情绪,是中文对话的独门手段。 + +## 本主题常见误区 + +1. **"X 说 Y 说"挂满标签**——节奏被切碎,读者疲倦;用动作、环境、段落归属替代。() +2. **语气标签把读者推出场景**——"他严肃地说""她解释道"是中介,不是信息;换成动作("她把茶杯摔在桌上")。() +3. **只删不补**——删掉标签后归属不清,读者分不清谁在说话;删的同时用动作节拍、段落归属、声音习惯补上。(合并说明,依据两书规则) diff --git a/framework/catalog/pi/skills/dialogue-craft/references/when-to-use-dialogue.md b/framework/catalog/pi/skills/dialogue-craft/references/when-to-use-dialogue.md new file mode 100644 index 0000000..136bfbb --- /dev/null +++ b/framework/catalog/pi/skills/dialogue-craft/references/when-to-use-dialogue.md @@ -0,0 +1,110 @@ +# 什么时候用对话:定位、时机与形式判断 + +## 原文摘录 + +> "小说中使用对话好像是几个固定的规则之一。它应该用在故事最高潮的时候, +> 就像' 喷涌'。这种波涛的升高和薄落, 这种浪潮的喷涌, 即使只表现为一页纸上被分割成 +> 数不清的小段的对话, 也足以让它的时间感增强了, 段落的时间感增强。 +> 为了创作这个段落, 作家必须依赖他的叙事能力。 +> 因此, 对话的应用不仅是为了强调故事的冲突和高潮, 而且是为了总体上增强故事持续发展的更大流畅。" +> +> — 多萝西娅·布兰德,《成为作家》第八章 + +> While quotes provide information or explanation, dialogue thickens the plot. The quote may be heard, +> but dialogue is overheard. The writer who uses dialogue transports us to a place and time where +> we get to experience the events described in the story. +> +> — Roy Peter Clark, *Writing Tools* (Tool 26) + +## 对话是什么:布兰德的三条原则 + +布兰德给对话定了三条底层逻辑。 + +### 原则 1:对话是"喷涌"——在高潮时用 + +- 对话**不是**为对话而对话 +- 对话**不是**"展示角色在说话" +- 对话**是**"故事在高潮时喷涌"——情绪/冲突达到顶点时的爆发 +- 就像河水在窄口喷涌,对话是故事**在窄口喷涌** + +### 原则 2:对话要"增强时间感" + +- 短的对话,加上周围的叙述,**增强**段落的紧凑感 +- 长的独白,不如短的交换 +- 一页纸上**被分割成数不清的小段**对话 = 时间快,节奏紧 +- 反过来:大段叙述 = 时间慢,节奏松 + +节奏机制的细节与案例(海明威、伦纳德)→ references/rhythm-and-density.md。 + +### 原则 3:对话是"冲突"工具 + +- 对话**不仅**强调冲突,**而且**制造冲突 +- 好的对话 = 角色在**不同的目标/价值观**上碰撞 +- 坏的对话 = 角色在"分享信息"——那应该用叙述 + +碰撞的展开与案例 → references/dialogue-does-things.md。 + +## 引语 vs 对话:克拉克的核心二分法 + +Clark 的核心二分法:**引语(quote)** 与 **对话(dialogue)** 看似都是"角色说话",但在叙事功能上截然不同。 + +- **引语(quote)**:角色事后补话,**关于**动作。读者**听到**它在解释,叙事被打断。 +- **对话(dialogue)**:角色在场景中说话,**在**动作中。读者**偷听**到它发生,叙事被推进。 + +**判断标准:一句话在角色嘴里是"上方传来"还是"在场发生"?** + +这是场景写作的核心理论:**对话不是装饰,是事件。**事件的三大功能见 references/dialogue-does-things.md。 + +中文落地:这个二分法来自 Clark 的新闻写作背景(新闻里引语是采访所得的事后陈述),迁到小说里就是"转述"与"场景直呈"的区别。中文稿子里常见的病灶是把关键戏写成"他后来告诉我……""据他说……"式的转述带过;按 Clark 的标准,凡是读者需要"在场经历"的段落,就把转述改回当下场景里的说话。 + +## 三个使用场景:什么时候用对话 + +### 场景 1:冲突/高潮——必用对话 + +- 角色之间**有冲突**(目标不一致/价值观不一致/隐藏动机) +- 故事到了**高潮点**(情绪达到顶点) +- 例:离婚谈判,告白,摊牌,争吵 +- **密度**:对话占比 50%-80% + +### 场景 2:信息/说明——慎用对话 + +- 需要**传递信息**(背景/前情/设定) +- **不要**用对话(那是"告诉"的最糟方式) +- 用叙述/独白/闪回 +- 例:不要用两个角色说"你知道吗,上世纪 90 年代我们..." +- **反例**:"老师对学生说:'写作需要想象力...'"——这是说教,不是故事 + +### 场景 3:日常/过渡——选着用对话 + +- 故事中**日常的过渡**(角色一起吃饭/坐车/走路) +- 可以用对话,但要让它**隐含冲突**/推动情节 +- 纯粹的"今天天气真好" = 删掉 +- 例:角色吃饭时,一句话透露了他**真正的担忧**——看似闲聊,实际推进 + +## 对话还是叙述:速查表 + +| 场景 | 优先用 | +|---|---| +| 冲突/高潮 | 对话 | +| 信息/说明 | 叙述 | +| 动作/事件 | 叙述 | +| 思考/感受 | 叙述或内心独白 | +| 角色关系/性格 | 对话(暴露) | +| 日常/过渡 | 看情况(隐含冲突才用) | +| 故事开头 | 可用对话(建声音)或不用 | + +## 两本书的合并点:信息不是对话的活 + +两本书从不同方向落到同一条规则上: + +- 布兰德:传递信息、背景、前情是叙述/独白/闪回的活;用对话的嘴交代背景,是"告诉"的最糟方式,会写成说教。 +- Clark:引语(quote)才是提供信息与解释的形式;对话(dialogue)的本职是让情节变厚(thickens the plot),不是给信息。 + +中文落地:中文网文里常见的"设定问答"(两个角色互相讲解世界观)就是本条的反面教材;设定该用叙述、动作、冲突逐步放出来,而不是让角色在课堂上互相提问。 + +## 视角差异注记(不冲突,互补) + +- 布兰德强调对话**需要叙述能力托着**:R 段原文里"为了创作这个段落,作家必须依赖他的叙事能力"——对话的喷涌要靠周围叙述铺垫和承接。() +- Clark 强调**去掉中介让读者直接进场景**:删"他说"之类的标签,读者才不被叙述者拦住。() + +两条不冲突:布兰德说的是叙述在对话**外围**做的事(铺垫、承接、控制时间感),Clark 说的是删掉对话**中间**的转述性标签。删标签的量化标准 → references/tags-and-attribution.md;外围叙述与对话的比例节奏 → references/rhythm-and-density.md。 diff --git a/framework/catalog/pi/skills/foreshadow-payoff/SKILL.md b/framework/catalog/pi/skills/foreshadow-payoff/SKILL.md new file mode 100644 index 0000000..9faa801 --- /dev/null +++ b/framework/catalog/pi/skills/foreshadow-payoff/SKILL.md @@ -0,0 +1,78 @@ +--- +name: foreshadow-payoff +description: | + 小说写作的伏笔与回收方法:把显著元素登记成债务、把铺垫埋得自然、让兑现从已埋细节生长出来。 + 当用户说"埋了没收""线索失踪""伏笔太突兀""这个细节是装饰还是债务""契诃夫之枪怎么用" + "伏笔怎么分层""兑现时间表",或明确在谈埋/收/铺垫链、特殊人物出场前的台阶时激活。 + 关键 trigger:"伏笔" / "回收" / "铺垫" / "契诃夫之枪" / "chekhov's gun" / "foreshadow" / + "线索失踪" / "埋了没收" / "承诺不兑现" / "前面挖的坑没填" / "删除测试" / "伏笔分层" / + "短期伏笔 / 中期伏笔 / 长期伏笔" / "兑现时间表" / "伏笔台账" / "修楼梯" / "Hitchcock 变体" / + "显眼的凶器" / "预暴露的伏笔" / "前后呼应" / "高潮从天而降(欠债未兑)"。 + 不适用于:仅问「高潮怎么写」「反转怎么设计」「大场面怎么拍」而无埋/收/契诃夫语境 + (归 scene-craft / story-structure / story-ending); + 散文/随笔(无情节承兑机制)、纯意识流/氛围小说(无情节闭环压力,元素出现又消失是合法的)、 + 解构/反小说(刻意让伏笔不兑现正是其目的)、需要大场面直接冲击的灾难/战争场景、 + 1000 字以下超短篇(没有埋设与生长的空间;1500 字以下不需要分层)。 + 与 scene-craft 交接:单场景高潮执行(使命/镜头/进出)归 scene-craft;本 Skill 只管债务登记与兑现链。 + 与 story-ending 交接:终局姿态与倒推收束归 story-ending;本 Skill 只保证前文债务可兑。 +--- + +# 伏笔与回收 + +伏笔是一条完整链路:**登记埋设 → 自然生长 → 兑现/高潮**。三家各管一段:《写作工具》管"显著元素就是借款,必须登记、偿还",《小说课》管"铺垫埋得自然,给读者的接受度修楼梯",《我能否相信自己》管"高潮不是凭空降临,而是从不动声色的细节里长出来"。 + +## 方法索引 + +### 埋设决策:埋什么、在哪里还 + +- 显著元素就是借款:被镜头对准、被台词反复提及、被位置强调的元素都在向读者借款,用位置/重复/特写/对话四个信号判断"装饰还是债务" → references/register-and-repay.md +- 建伏笔台账,按短/中/长期分层,写兑现时间表;找不到兑现点的伏笔就删除或降低显著度 → references/register-and-repay.md +- 删除测试(修订阶段用):删掉它故事不变轻就是装饰,删;变轻就是隐性债务 → references/register-and-repay.md +- Hitchcock 变体:把凶器预先命名、预先暴露,悬念从"会发生什么"移到"怎么发生" → references/register-and-repay.md + +### 自然埋设:埋得不露痕迹 + +- 铺垫就是修楼梯:特殊人物/事件/场景出场前,先垫 2-4 个普通同类台阶 → references/natural-staircase.md +- 每级台阶 1-3 句话,台阶要独立、有"无关感",读者不能一眼看出是台阶 → references/natural-staircase.md +- "去掉铺垫"测试校准台阶数量:突兀就加一级,还能接受就删一级 → references/natural-staircase.md +- 铺垫要有双重功能:表层让特殊物出场自然,深层同时承担情节、主题或性格描写 → references/natural-staircase.md + +### 兑现与高潮:让细节爆发 + +- 细节先行、细节生长、细节爆发三段链路:高潮由一个微小的动作、物品或一句话触发 → references/detail-driven-climax.md +- 回溯有效性验收:回溯时一切合理,初读时不察觉 → references/detail-driven-climax.md + +### 诊断与边界 + +- 不适用场景、常见误区(承诺不兑现、装饰过载、铺垫露形、细节与高潮关联太弱等)、盲点与中文落地 → references/boundaries-and-pitfalls.md + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|----------| +| references/register-and-repay.md | 显著元素即借款;装饰 vs 债务判断;伏笔台账与显著信号四条;短/中/长期分层与兑现时间表;删除测试;Hitchcock 变体;契诃夫 1889 年信与《Lamb to the Slaughter》案例;伏笔与线索的区分 | +| references/natural-staircase.md | 铺垫=修楼梯;识别特殊物;设计 2-4 级普通台阶;台阶简洁与独立;去掉铺垫测试;铺垫双重功能;奈保尔四个乞丐、水浒林冲风雪、《促织》驼背巫与斗蛐蛐案例 | +| references/detail-driven-climax.md | 细节先行/生长/爆发三段链路;不动声色的埋法;回溯恍然大悟;《一千零一夜》戒指、《拜占庭的陷落》小门、《威尼斯商人》一磅肉案例;与契诃夫之枪的关系 | +| references/boundaries-and-pitfalls.md | 不适用场景汇总;常见误区(线索失踪、装饰过载、伏笔露形三形态、关联太弱、只用一次、常见错误表);盲点与时代局限(网文落地、类型惯例、红鲱鱼);与相邻方法的区分及跨 skill 配合 | + +## 脚本 + +| 脚本 | 用途 | +|------|------| +| references/foreshadow-ledger-template.md | 伏笔台账与兑现时间表模板:登记显著元素,标注装饰/债务与短/中/长期,对应埋设点与兑现点 | +| references/foreshadow-checklist.md | 修订阶段检查清单:场景四问、删除测试、去掉铺垫测试、回溯有效性三问 | + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/pi/skills/foreshadow-payoff/references/_coverage.md b/framework/catalog/pi/skills/foreshadow-payoff/references/_coverage.md new file mode 100644 index 0000000..589ab4d --- /dev/null +++ b/framework/catalog/pi/skills/foreshadow-payoff/references/_coverage.md @@ -0,0 +1,13 @@ +# foreshadow-payoff 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| bifeiyu-novel-skill/bifeiyu-foreshadowing | references/natural-staircase.md | +| bifeiyu-novel-skill/bifeiyu-foreshadowing | references/boundaries-and-pitfalls.md | +| bifeiyu-novel-skill/bifeiyu-foreshadowing | references/detail-driven-climax.md | +| wo-neng-fou-xiang-xin-zi-ji/detail-driven-climax | references/detail-driven-climax.md | +| wo-neng-fou-xiang-xin-zi-ji/detail-driven-climax | references/boundaries-and-pitfalls.md | +| writing-tools-clark/chekhov-gun | references/register-and-repay.md | +| writing-tools-clark/chekhov-gun | references/boundaries-and-pitfalls.md | diff --git a/framework/catalog/pi/skills/foreshadow-payoff/references/boundaries-and-pitfalls.md b/framework/catalog/pi/skills/foreshadow-payoff/references/boundaries-and-pitfalls.md new file mode 100644 index 0000000..2bb020f --- /dev/null +++ b/framework/catalog/pi/skills/foreshadow-payoff/references/boundaries-and-pitfalls.md @@ -0,0 +1,107 @@ +# 适用边界、常见误区与盲点 + +> 伏笔与回收方法的边界、失败模式、盲点和相邻方法区分在此汇总。 + +## 不适用场景 + +**《写作工具》列出的不要用此方法的情况:** + +- **解构 / 反小说 / 后现代叙事**——这类作品**刻意**让伏笔不兑现(让读者意识到"叙事的不可信"),此时 Clark 的承诺原则正是被颠覆的对象。例:Paul Auster 的迷宫式叙事。 +- **散文 / 随笔 / 抒情独白**——没有"情节"承兑机制,伏笔概念无意义。 +- **意识流 / 极简叙事(去情节化)**——元素出现又消失是合法的(无情节闭环压力)。 +- **写作前期的"灵感囤积"阶段**——伏笔管理是**修订阶段**的工具,不是初稿阶段的工具。初稿应该"先埋一堆",修订再决定"哪些留 / 删 / 兑现"。 +- **极短篇(< 1500 字)**——伏笔跨度有限,所有元素"立刻"兑现,不需要分层工具。 + +**《小说课》列出的适用边界:** + +- **适合**:短篇、超短篇、长篇关键场景 +- **不适合**:长篇的章节切换(可以用整章铺垫) +- **不适合**:节奏要求快的惊悚/悬疑(铺垫要短到极致) + +**《我能否相信自己》列出的不要用此方法的情况:** + +- **纯氛围/意识流小说**:没有传统情节结构的作品,不需要"高潮"概念 +- **灾难/战争大场面**:有时需要直接的大场面冲击,不适合用微小细节驱动 +- **超短篇(1000 字以下)**:篇幅太短,没有足够空间埋下细节并让它生长 + +**字数边界对照(两说并存,都保留)**:Clark 说 1500 字以下不需要分层工具(元素几乎立刻兑现);余华说 1000 字以下连埋设与生长的空间都没有。两者口径不同但不冲突:1000 字以下彻底不用伏笔机制,1000-1500 字可以埋但无需台账分层。 + +## 常见误区(失败模式) + +### 1. 承诺不兑现("线索失踪") + +失败模式是**承诺但不兑现**——显著元素(角色提到"A 先生的秘密"、墙上挂的猎枪、孩子的红雨衣)出现后又消失。读者记得,作者忘了,结尾没有交代。信号:第 5 章的伏笔在 25 章后无交代;读者在评论中问"那个 X 怎么了"。机制:读者对"重要元素"有"准记忆"——如果后续不提,他们会期待却失望,觉得"作者控不住结构"。对策:伏笔台账 + 兑现时间表。 + +### 2. 装饰过载 + +与"线索失踪"相反——**埋太多"假装是债务"的装饰**。把每个细节都写得像伏笔,结果兑现不了 → 读者疲劳 + 不信任作者的承诺系统。**删除测试**正是用来对抗这种失败。 + +### 3. 伏笔露形(三种形态) + +同一个误区的三种形态: + +- **作者大声宣布**(新手陷阱):把伏笔写成"作者大声宣布"("那把猎枪很重要,主角一定会用到它!")。正确做法是**埋得自然,关键是被镜头/语言显著,不必被作者宣判"重要"**。 +- **埋细节时给太多强调**:如果前段埋下细节时给了太多强调,读者会猜到后续,失去"恍然大悟"的快感。 +- **台阶被一眼看穿**:铺垫太明显,读者预先猜到结局。修正:台阶要有"无关感"。 + +### 4. 细节与高潮关联太弱 + +如果细节和高潮之间的逻辑链条不清晰,读者会觉得"太巧合了"而非"精妙"。细节必须能逻辑地推出高潮。 + +### 5. 只在高潮用一次细节 + +好的细节应该在故事中多次出现(以不同形式),形成回响。孤证式的细节爆发没有说服力。 + +### 6. 铺垫的常见错误(《小说课》错误表) + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 铺垫变"介绍" | 啰唆、啰唆 | 每个台阶只 1-3 句 | +| 铺垫太明显 | 读者预先猜到结局 | 台阶要有"无关感" | +| 铺垫不够 | 突兀、做作 | 增加台阶数 | +| 多个特殊物同时出场 | 全都突兀 | **一次只铺一个** | + +## 盲点与时代局限 + +**《写作工具》:** + +- Chekhov 原则本身是经典的(19 世纪俄国戏剧),Clark 的**独特贡献是配套的"已暴露的凶器"(Hitchcock 变体)+ 删除测试 + 伏笔台账的工作流**。如果只教"伏笔要兑现"是常识;这个方法的真正价值在"**分层 + 决策测试 + 工作流**"。 +- **长篇 / 系列小说的伏笔管理工具**:Clark 写于 2006 年(英文版),针对的主要是"中短篇小说 + 非虚构",对**网文百万字连载 / 跨 5+ 卷的系列小说**没有给出系统化方案。迁移到中文长篇 / 网文时,需要补充:台账软件(Notion / Airtable / Excel)、团队协作下的"伏笔分配表"(多人合写)、"读者已知 vs 角色已知"的双轨追踪。(中文适配) +- **类型文学的伏笔惯例不同**:悬疑/推理的"公平竞争"(Fair Play)规则(读者必须和侦探有同等线索)是 Chekhov 原则的子类,Clark 未展开;言情/玄幻的"线索失踪"容忍度比悬疑高(读者更关心情绪而非线索);这些类型差异需要本地化调整。(中文适配) + +**《我能否相信自己》:** + +- 余华主要从经典文学中举例,没有讨论当代类型小说(如网络小说)中如何使用这种技巧——类型小说的读者对伏笔更敏感,需要更隐蔽的处理。(中文适配) +- 没有讨论"红鲱鱼"(假伏笔)的使用——有时需要用假细节来误导读者,让真细节的爆发更有力。 + +**《小说课》:** + +- 无独立盲点;需要注意的边界已并入上文"不适用场景"与"常见错误表"。 + +## 与相邻方法的区分(跨领域指针) + +**来自《写作工具》:** + +- 与 `gold-coins`(沿途埋金,今 narrative-momentum)的区别:那个是"沿途奖赏"——在中段撒"小高潮 / 逸事 / 惊人事实"让读者不弃读,**不要求回收**;这个是"埋伏-兑现"——埋的每个元素都**必须回收**。前者是"节奏分布",后者是"因果闭环"。一个金币是礼物(发完就完),一把枪是债务(借了要还)。那个的"金"是奖励(节奏),这个的"枪"是债务(因果);两者并存,但功能截然不同——一个让读者"继续走",一个让读者"记住回头看"。 +- 与 `write-toward-ending`(倒推向结局,今 story-ending)的区别:那个是"结尾策略"——先锚定终局反向写作;这个是"为结尾铺路"——把通往结尾的路径标记成可被回收的伏笔。前者是"倒推",后者是"前向埋伏 + 承诺兑现"。两个方法强配对:用 write-toward-ending 定结尾,再用契诃夫之枪设计通往结尾的伏笔链。 +- 与 `inciting-incident`(触发事件 + 加码,今 story-structure)的区别:那个管"开篇的破局一击 + 中段加码",伏笔是"开局后的稳定结构"——前者是"打破平衡",后者是"维护平衡下的承诺"。两者不冲突:触发事件之后,伏笔系统开始运转。 +- 与 `mix-narrative-modes`(混合叙事模式,今 narration-pov)的区别:那个管"主线 / 折线 / 蒙太奇"的叙事模式调度;这个管"每个具体元素是否值得存在"——前者是"段落/章节级的模式",后者是"物件/对话级的内容层"。 +- 与 "show, don't tell"(Tool 27,今 show-and-omission 领域)的区别:那个管"如何显示"——伏笔管理管"显示什么 / 显示的东西是否兑现"。前者是"风格",后者是"结构"。 + +**来自《我能否相信自己》:** + +- 与 `obstacle-crossing`(写作障碍应对,已裁剪单元、不入综合 skill)的区别:本方法是情节设计技巧(如何用细节驱动高潮),obstacle-crossing 是写作过程策略(如何面对障碍)。制造障碍后,往往需要用细节来跨越障碍。 +- 与 `certainty-uncertainty-tension`(确定与不确定的张力,今 narration-pov)的区别:本方法给出确定的情节转折(细节爆发),certainty-uncertainty-tension 保留不确定性。一个是"恍然大悟",一个是"回味无穷"。 +- 与 `no-psychological-description`(不写心理写动作,今 show-and-omission)配合:细节(动作/视觉)既是心理描写的替代,也是高潮的驱动力。 + +**来自《小说课》:** + +- 与 `bifeiyu-iceberg`(冰山理论,今 show-and-omission)配合:铺垫是"水下的结构",冰山是"水下的内容"。 +- 与 `bifeiyu-momentum`(叙事动力,今 narrative-momentum)关联:铺垫 = 给"势"铺路。 +- 与 `bifeiyu-system`(体系,今 story-structure)配合:短篇铺垫极简,长篇铺垫可厚——体裁决定密度。 + +**来自《写作工具》的配合关系:** + +- `internal-cliffhanger`(章末内悬念,今 narrative-momentum):章末内悬念可作为短期伏笔的兑现触发。 +- `mix-narrative-modes`(混合叙事模式,今 narration-pov):折线叙事中可嵌入伏笔的回顾/解释。 +- `mosaic-of-detail`(细节马赛克,今 character-presentation):细节马赛克中选出的 5-9 个细节应优先考虑作为"债务"而非"装饰"。 diff --git a/framework/catalog/pi/skills/foreshadow-payoff/references/detail-driven-climax.md b/framework/catalog/pi/skills/foreshadow-payoff/references/detail-driven-climax.md new file mode 100644 index 0000000..67b2fab --- /dev/null +++ b/framework/catalog/pi/skills/foreshadow-payoff/references/detail-driven-climax.md @@ -0,0 +1,112 @@ +# 细节驱动高潮:高潮从不动声色的细节里长出来 + +> 本文件管伏笔链路的兑现端:高潮怎么由前段埋下的微小细节触发。埋设登记见 [register-and-repay.md](register-and-repay.md),埋设的自然度见 [natural-staircase.md](natural-staircase.md);边界与误区见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> "故事中最辉煌的段落, 这些高潮的篇章和最终结束的篇章其实来自一个微小的和不动声色的细节, 来自类似国王挥手这样的描述, 就像是那些粗壮的参天大树其实来自细小的根须一样。" +> +> "我们总是沉醉在叙述中那些最为辉煌的段落之中, 那些出人预料和惊心动魄的段落...山鲁佐德的故事指出了这些华彩的篇章...其实来自一个微小的和不动声色的细节。" +> +> — 余华, 《什么才是故事》 + +## 方法核心:三段链路 + +故事中最出人预料、最惊心动魄的高潮,往往不是来自大场面或大转折,而是来自一个**微小的、不动声色的细节**——一个平常的动作、一个不起眼的物品、一句随口说的话。这个细节像树根一样,在叙述中悄悄生长,最终支撑起整个高潮。 + +关键机制: + +1. **细节先行**:在故事前段,以一种"让人疏忽和视而不见"的方式埋下一个细节 +2. **细节生长**:这个细节在后续叙述中被反复触及或自然发展,但读者不会意识到它的重要性 +3. **细节爆发**:到高潮时,这个细节突然成为情节转折的关键——读者才意识到"原来前面那个细节是这个意思" + +这种技巧的力量在于:高潮不是凭空降临的(那样会显得突兀),而是从已有叙述中自然生长出来的(那样会显得精妙且有说服力)。读者回溯时会发现一切早有伏笔,从而获得"恍然大悟"的快感。 + +## 案例 + +### 案例 1:《一千零一夜》——国王挥手丢戒指 + +- **问题**:如何让好人艾彼·绥尔从死刑中逃脱并重获国王信任? +- **方法论的使用**:船长释放艾彼·绥尔后,把一块大石头放入麻袋以假乱真。国王在临海的宫窗前,船长问是不是可以抛入海中,国王说抛吧——"国王说话的时候举起戴着宝石戒指的右手一挥, 一道闪光从他的手指上划到了海面, 戒指掉入了大海。"这个平常的挥手动作,让国王的权力戒指掉入海中,而戒指恰好被艾彼·绥尔捞到。 +- **结论**:一个挥手的微小细节,决定了后续情节的全部走向。 +- **结果**:艾彼·绥尔用戒指还给国王,重获信任,坏人艾彼·勾尔被处死。 + +### 案例 2:茨威格《拜占庭的陷落》——凯卡波尔塔小门 + +- **问题**:奥斯曼土耳其人久攻君士坦丁堡不下,如何让城破? +- **方法论的使用**:茨威格没有写土耳其人靠强大攻势破城,而是写了一个被遗忘的小门——凯卡波尔塔小门。它是和平时期大门紧闭时供行人出入用的,"正是因为它不具有军事意义, 罗马人忘记了它的存在。凯卡波尔塔小门敞开着, 而且无人把守, 土耳其人发现了它, 然后攻入了城中。" +- **结论**:一个不具军事意义的小门,决定了强盛一千多年的东罗马帝国的灭亡。 +- **结果**:成为"一个影响深远的决定其实来自一个日期、一个小时,甚至是来自一分钟"的经典例证。 + +### 案例 3:莎士比亚《威尼斯商人》——夏洛克忘记血 + +- **问题**:如何让夏洛克的报复失败? +- **方法论的使用**:莎士比亚让夏洛克在签订契约时,只要求"一磅肉",忘记了一个事实——割下肉会流血。这个微小的遗漏,在审判时成为鲍西娅反击的关键:"你可以割一磅肉, 但不能流一滴血。" +- **结论**:夏洛克的一个疏忽(忘记血),造就了全剧的情节跌宕和叙述紧张。 +- **结果**:成为文学史上最经典的反转之一。 + +## 可执行步骤 + +1. **确定高潮事件** + - 明确故事的核心高潮是什么(人物命运转折、真相揭露、关系破裂等) + - 完成标准:能用一句话说清高潮事件 + +2. **回溯寻找细节根须** + - 问自己:这个高潮可以由什么微小细节触发? + - 细节应该是:一个动作 / 一个物品 / 一句话 / 一个被遗忘的约定 / 一个角色的小习惯 + - 细节必须在故事前段有自然出现的理由(不能为了埋伏笔而硬加) + - 完成标准:找到一个可以触发高潮的微小细节 + +3. **在前段自然埋下细节** + - 以"让人疏忽和视而不见"的方式写出这个细节 + - 不要强调它,不要给它特殊的叙述权重 + - 最好让它融入日常场景中(如挥手、关门、随口一句话) + - 完成标准:细节已出现在故事前段,且不显得刻意 + +4. **让细节在中段悄悄生长** + - 在故事中段,可以再次触及这个细节(但仍不强调) + - 或者让细节所处的环境发生变化,为后续爆发做准备 + - 完成标准:细节与后续高潮之间有逻辑链条 + +5. **在高潮让细节爆发** + - 高潮时,让这个细节成为情节转折的关键 + - 读者应该在这一刻"恍然大悟":原来前面那个细节是这个意思! + - 完成标准:高潮由细节触发,而非凭空降临 + +6. **检查回溯有效性** + - 读者回溯时,能否发现一切早有伏笔? + - 细节在前段出现时是否自然? + - 高潮是否由细节逻辑地推出,而非强行关联? + - 完成标准:回溯时一切合理,初次阅读时不察觉 + +## 什么时候用这个单元 + +用户会在这些情境下需要"细节驱动高潮": + +1. 设计情节转折时觉得突兀,读者反馈"太巧合了" +2. 高潮写得不够有力,缺乏说服力 +3. 想学习"伏笔"的具体操作方法 +4. 写反转 / twist 时不知道怎么铺垫 +5. 故事中段平淡,想让后续高潮更有冲击力 +6. 被反馈"前面铺的东西后面没用上" + +语言信号: + +- "高潮怎么写" "情节转折" +- "伏笔怎么埋" "前后呼应" +- "反转太突兀" "太巧合了" +- "剧情设计" "plot twist" +- "前面写的细节没用上" +- "故事中段太平淡" + +## 与本领域另外两个方法的关系 + +- **与"契诃夫之枪"(本包 register-and-repay.md)的区别**:契诃夫之枪是"如果第一幕墙上挂着枪,第三幕必须开枪"——强调前后呼应。本单元更精确——不仅是呼应,而是"微小细节驱动整个高潮",细节本身就是高潮的发动机,不只是呼应元素。 +- **与"伏笔 / foreshadowing"(更宽泛的概念)的区别**:伏笔是更宽泛的概念,本单元是伏笔的一种特定高效用法——用微小不动声色的细节驱动最辉煌的高潮。 + +## 中文落地说明 + +余华的三案例都出自中文读者熟悉的经典(《一千零一夜》中译传统、茨威格历史特写、莎士比亚),方法本身无语言隔阂。中文写作落地时注意两点: + +- **古典白话传统里这套手法极成熟**:《水浒》林冲的风雪、《促织》的五次失败(见 [natural-staircase.md](natural-staircase.md))都是"细节先行 → 爆发"的中文范本,可直接对照学习。(中文适配) +- **类型小说读者对伏笔更敏感**:余华只从经典文学举例,没讨论网络小说——类型读者读得多,埋细节要更隐蔽,少给叙述权重。详见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md) 盲点一节。(中文适配) diff --git a/framework/catalog/pi/skills/foreshadow-payoff/references/foreshadow-checklist.md b/framework/catalog/pi/skills/foreshadow-payoff/references/foreshadow-checklist.md new file mode 100644 index 0000000..b673b46 --- /dev/null +++ b/framework/catalog/pi/skills/foreshadow-payoff/references/foreshadow-checklist.md @@ -0,0 +1,80 @@ +# 伏笔与回收检查清单 + +> 伏笔与回收的可执行检查项,按写作进程排列:写作中 → 修订阶段 → 完稿验收。 +> 台账模板见 [foreshadow-ledger-template.md](foreshadow-ledger-template.md)。 + +## 一、写作中的场景四问 + +写场景/转折/章节末时逐条自问: + +- [ ] 写场景时:墙上这把枪会开火吗?如果不,弱化或删。 +- [ ] 写转折前:我前面给读者埋下可信的钩子了吗? +- [ ] 写章节末:这个元素是"装饰"还是"债务"?如果是债务,它在哪一章兑现? +- [ ] 通读时:用删除测试扫一遍——哪些元素删掉后故事没变轻,就该删。 + +## 二、特殊物出场前的铺垫检查 + +列出读者会觉得突兀的元素,逐项检查: + +- [ ] 特殊人物(杀人犯/乞丐诗人/性格怪癖的人)、特殊事件(不可能的巧合/超自然/极端选择)、特殊场景(异国他乡/历史时期/极端环境)都识别出来了 +- [ ] 每个特殊物出场前有 2-4 级普通同类台阶 +- [ ] 每级台阶只有 1-3 句话(铺垫变啰唆就是小说内部的肿瘤) +- [ ] 台阶彼此独立、有"无关感",读者不能一眼看出是台阶 +- [ ] 一次只铺一个特殊物(多个特殊物同时出场会全都突兀) +- [ ] 铺垫有双重功能:表层让特殊物出场自然,深层承担情节/主题/性格描写 + +## 三、细节根须检查(为高潮找伏笔) + +设计高潮/反转时逐条核对: + +- [ ] 能用一句话说清高潮事件 +- [ ] 触发高潮的微小细节已选定:一个动作 / 一个物品 / 一句话 / 一个被遗忘的约定 / 一个角色的小习惯 +- [ ] 细节在故事前段有自然出现的理由(不是为埋伏笔硬加) +- [ ] 细节以"让人疏忽和视而不见"的方式埋下,没有特殊叙述权重 +- [ ] 中段再次触及或让其环境变化,但仍不强调 +- [ ] 细节与高潮之间的逻辑链条清晰(不是强行关联) + +## 四、修订阶段:删除测试 + +仅用于修订阶段,初稿不要用(初稿时不知道哪些元素会被用上): + +对每个"装饰"候选元素问:"如果删掉它,这个场景/章节/全书是否变轻?" + +- [ ] 不变轻 → 真的只是装饰 → 删 +- [ ] 变轻 → 隐性债务 → 要么加强它(让它"显著")进伏笔台账,要么删除/弱化避免误导读者 +- [ ] 每个候选元素都有"留 / 删 / 加强"决定,理由是"删除后变轻"还是"不变轻" + +## 五、修订阶段:"去掉铺垫"测试 + +把所有铺垫台阶删掉,只看特殊物: + +- [ ] 突兀?→ 铺垫不够,加 1 级 +- [ ] 还能接受?→ 铺垫可能太多,删 1 级 +- [ ] 反而更自然?→ 你可能没真正铺垫,只是堆细节 + +## 六、完稿验收:兑现与回溯 + +**兑现核对**: + +- [ ] 台账里所有"债务"元素都兑现了,无"线索失踪"(信号:第 5 章的伏笔在 25 章后无交代;读者问"那个 X 怎么了") +- [ ] 没有"装饰过载"——没有一堆写得像伏笔却兑现不了的细节 + +**回溯有效性三问**: + +- [ ] 读者回溯时,能否发现一切早有伏笔? +- [ ] 细节在前段出现时是否自然? +- [ ] 高潮是否由细节逻辑地推出,而非强行关联? + +验收标准:**回溯时一切合理,初次阅读时不察觉。** + +## 七、快速排错表 + +| 症状 | 诊断 | 处方 | +|------|------|------| +| 读者问"那个 X 怎么了" | 承诺不兑现(线索失踪) | 补兑现,或删埋设、降显著度 | +| 读者疲劳、不信作者的承诺 | 装饰过载 | 删除测试扫一遍 | +| 读者提前猜到结局 | 伏笔露形(作者宣判/强调过多/台阶被看穿) | 显著靠镜头语言不靠宣判;台阶加"无关感" | +| 读者说"太巧合了" | 细节与高潮关联太弱 | 补逻辑链条,或换细节 | +| 高潮爆发没说服力 | 细节只在高潮用了一次 | 让细节以不同形式多次出现,形成回响 | +| 特殊物出场突兀做作 | 铺垫不够 | 增加台阶数 | +| 铺垫段又长又闷 | 铺垫变"介绍" | 每级台阶压到 1-3 句 | diff --git a/framework/catalog/pi/skills/foreshadow-payoff/references/foreshadow-ledger-template.md b/framework/catalog/pi/skills/foreshadow-payoff/references/foreshadow-ledger-template.md new file mode 100644 index 0000000..d6f740f --- /dev/null +++ b/framework/catalog/pi/skills/foreshadow-payoff/references/foreshadow-ledger-template.md @@ -0,0 +1,60 @@ +# 伏笔台账与兑现时间表模板 + +> 用途:长篇/系列/网文连载在**修订阶段**登记所有显著元素,追踪每个伏笔的兑现位置。初稿阶段不要用——初稿应该先放手埋,修订再登记。 + +## 第一步:登记显著元素 + +扫描全书/当前章节,凡是命中任一"显著信号"的元素都要进台账: + +- **位置**:被放在墙/桌上/口袋等被点名的位置上 +- **重复**:被提及 2 次以上 +- **特写**:用 1 段以上篇幅描写 +- **对话**:被角色直接说出来 + +每个元素标注"装饰"或"债务": + +- **装饰**:不承担叙事债务,考虑删除或弱化 +- **债务**:必须进入兑现时间表 + +## 第二步:台账模板 + +(下表示例行仅演示格式与填法:线索归属、兑现章节、"酒吧招牌的霓虹色"等字段值为占位示意。) + +| # | 元素 | 显著信号(位置/重复/特写/对话) | 装饰/债务 | 线索归属(plot thread) | 尺度 | 埋设位置(章/卷) | 预计兑现位置(章/卷) | 实际兑现位置 | 状态 | +|---|------|------------------------------|-----------|------------------------|------|------------------|----------------------|--------------|------| +| 1 | 墙上挂的猎枪 | 位置+对话 | 债务 | 主线:复仇 | 中期 | 第 1 章 | 第 8 章 | 第 8 章 | 已兑现 | +| 2 | 孩子的红雨衣 | 特写 | 债务 | 支线:失踪案 | 长期 | 第 1 卷 | 第 5 卷(显式标注最终兑现卷) | —— | 待兑现 | +| 3 | 酒吧招牌的霓虹色 | 特写 | 装饰 | 无 | —— | 第 3 章 | 无 | —— | 删除测试后删 | + +字段说明: + +- **线索归属**:线索是人物/事件级叙事线(如"主角追查父亲死因"),伏笔是元素级承诺;一条线索可含多个伏笔,一个伏笔可跨多条线索,两者分开管理。 +- **尺度**: + - **短期**:同章/同幕内兑现(5-30 页内回收)。例:章末"她看见了那封信" → 章内"信里是离婚协议"。 + - **中期**:同卷/同一故事弧内兑现(50-200 页内回收)。例:第 1 章"父亲的旧钥匙" → 第 8 章开门。 + - **长期**:全书/全系列内回收(30 万字 / 5 本书)。例:第 1 卷"主角的母亲从未出现" → 第 5 卷"母亲身份的揭示"。 +- **状态**:待兑现 / 已兑现 / 已删除 / 已弱化。 + +## 第三步:兑现时间表(埋 → 兑现对应表) + +左边是"埋",右边是"兑现",中间是章节/卷数: + +| 埋(元素 + 位置) | 章节/卷数跨度 | 兑现(方式 + 位置) | +|-------------------|---------------|---------------------| +| | | | + +兑现校验标准: + +- 所有**短期伏笔**都在同章/同幕内兑现 +- 所有**中期伏笔**在 200 页内有兑现节点 +- 所有**长期伏笔**有显式"最终兑现卷/章"标注 +- 跨度 > 30 万字或 > 3 卷的长期伏笔:定期回顾本台账,防止"线索失踪" +- 找不到兑现点的伏笔:**删除**或**降低显著度**,不留"承诺但不兑现" + +## 网文/连载补充(中文适配) + +Clark 的台账针对中短篇,网文百万字连载/跨 5+ 卷系列需要自行补充: + +- 台账工具:Notion / Airtable / Excel +- 多人合写:加一张"伏笔分配表"(谁埋的、谁负责收) +- 双轨追踪:分别记录"读者已知"与"角色已知",两条轨道都要对得上 diff --git a/framework/catalog/pi/skills/foreshadow-payoff/references/natural-staircase.md b/framework/catalog/pi/skills/foreshadow-payoff/references/natural-staircase.md new file mode 100644 index 0000000..4fc32f4 --- /dev/null +++ b/framework/catalog/pi/skills/foreshadow-payoff/references/natural-staircase.md @@ -0,0 +1,120 @@ +# 铺垫术:给读者的接受度修楼梯 + +> 本文件管伏笔链路的埋设端:怎么把特殊人物/事件埋得自然、不突兀。登记与兑现见 [register-and-repay.md](register-and-repay.md);高潮怎么从细节生长见 [detail-driven-climax.md](detail-driven-climax.md);边界与误区见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> 「铺垫就是修楼梯。二楼到一楼有三米高,一个大妈如果从二楼直接跳到一楼,大妈的腿就得断。」 + +## 方法核心 + +**铺垫 = 修楼梯**。让你的"特殊事物"通过几级"普通台阶"自然进入读者视野。 + +**关键洞察**:铺垫不是给"特殊事物"找合理性,而是给"读者的接受度"找台阶。 + +### 书中原文:奈保尔怎么写第五个乞丐 + +奈保尔写第五个乞丐(诗人沃滋沃斯)出场前,**先写了四个乞丐**。每个乞丐只用一句话: + +``` +第一个乞丐:…… +第二个乞丐:…… +下午两点,一个盲人由一个男孩引路,来取走他的那一分钱。 +第四个乞丐:…… +``` + +**结果**:第五个乞丐(沃滋沃斯)出场时,读者已经接受了"这里有很多奇怪的乞丐"——他再特殊也不突兀了。 + +**没有这四步**:一个"乞丐兼诗人"突然出现,读者会本能地觉得"太特殊、太做作"。 + +## 案例 + +### 案例 1:奈保尔四个乞丐 → 沃滋沃斯 + +- 4 个普通乞丐 → 1 个特殊诗人 +- **每个乞丐只 1 句话**——简洁是铺垫的灵魂 + +### 案例 2:施耐庵《水浒》林冲出场 + +- 写林冲"走"上梁山之前,先写**风**、**雪**、**石头**——这些"环境物"不是闲笔,是给"林冲的转变"修楼梯 +- 没有雪 → 林冲不会去烤火 → 不会离开房间 → 不会听到阴谋 → 不会杀人 → 不会上山 +- 每一级台阶都是必然 + +### 案例 3:蒲松龄《促织》驼背巫 + +- 写驼背巫之前,先写**成名搜虫、捕虫、失败、被责、寻死**——五次失败 = 五级台阶 +- 没有这五级,驼背巫的"神卜"就不显得必要 + +### 案例 4:蒲松龄《促织》斗蛐蛐 + +- 斗蛐蛐之前,必须先有**"将献公堂,惴惴恐不当意,思试之斗以觇之"**——这一句是**左腿** +- 斗蛐蛐 = **右腿** +- 没有这一句,斗蛐蛐就是不自然 + +## 可执行步骤 + +### 步骤 1:识别"特殊物" + +列出你小说里**读者会觉得突兀**的元素: + +``` +特殊人物:杀人犯 / 乞丐诗人 / 性格怪癖的人 +特殊事件:不可能发生的巧合 / 超自然事件 / 极端选择 +特殊场景:异国他乡 / 历史时期 / 极端环境 +``` + +### 步骤 2:设计 2-4 级"普通台阶" + +每个台阶是**一个独立的、普通的、看起来和主题无关的细节**: + +``` +台阶 1:写一个普通的同类物(普通乞丐) +台阶 2:再写一个普通的同类物 +台阶 3:写一个稍微特殊的同类物 +台阶 4:你的特殊物出场(已经不再突兀) +``` + +**关键**:每个台阶要"独立"——读者不能一眼看出这是台阶,要读完后才恍然。 + +### 步骤 3:保证简洁 + +**每个台阶 = 1-3 句话**。铺垫最忌讳"啰唆"——它会变成小说内部的"肿瘤"。 + +> 「简洁是短篇小说的灵魂,也是短篇小说的秘密。」——毕飞宇 + +### 步骤 4:做"去掉铺垫"测试 + +写完后,把所有铺垫删掉,看你的特殊物: + +- [ ] 突兀?→ 铺垫不够,加 1 级 +- [ ] 还能接受?→ 铺垫可能太多,删 1 级 +- [ ] 反而更自然?→ 你可能没真正铺垫,只是堆细节 + +### 步骤 5:铺垫的隐藏法则 + +**好的铺垫要有"双重功能"**: + +- 表层功能:让特殊物出场自然 +- 深层功能:本身要承担情节/主题/性格描写 + +海明威《杀手》的环境铺垫不只是"做气氛"——它同时塑造了乔治这个人物。 + +## 什么时候用这个单元 + +1. 你的"特殊人物/事件"出场时读者可能觉得突兀 +2. 短篇/开头需要快速建立世界观 +3. 主人公命运大转折前 +4. 反派/异类登场 +5. 任何"不可能的事情"在小说内部必须变得"可能" + +## 一句话总结 + +> **特殊物出场前,先让读者见 2-4 个普通同类。每个同类只 1-3 句话。** + +## 适用边界 + +- **适合**:短篇、超短篇、长篇关键场景 +- **不适合**:长篇的章节切换(可以用整章铺垫) +- **不适合**:节奏要求快的惊悚/悬疑(铺垫要短到极致) + +常见错误表见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 diff --git a/framework/catalog/pi/skills/foreshadow-payoff/references/register-and-repay.md b/framework/catalog/pi/skills/foreshadow-payoff/references/register-and-repay.md new file mode 100644 index 0000000..1e25c3a --- /dev/null +++ b/framework/catalog/pi/skills/foreshadow-payoff/references/register-and-repay.md @@ -0,0 +1,132 @@ +# 埋设决策与伏笔台账:显著元素就是借款 + +> 本文件管伏笔链路的埋设端:哪些元素必须埋、怎么登记、在哪偿还。埋设怎么做到不露痕迹,见 [natural-staircase.md](natural-staircase.md);高潮怎么从细节生长,见 [detail-driven-climax.md](detail-driven-climax.md);边界与误区见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> In dramatic literature, this technique inherits the name Chekhov's Gun. In a letter he penned in +> 1889, Russian playwright Anton Chekhov wrote: "One must not put a loaded rifle on the stage if +> no one is thinking of firing it." Do you ever violate the principle of Chekhov's Gun? Do you place +> seemingly significant elements high in your work that never come into play again? +> +> — Roy Peter Clark, *Writing Tools* (Tool 29) + +契诃夫原话的通行表述:「如果没人打算开枪,就不要把上膛的步枪放到舞台上。」另一个版本:「如果第 1 幕墙上挂了一把枪,第 3 幕它必须开火。」 + +## 方法核心:三个机制 + +Clark 提出的不是单一原则,而是**一组围绕"显著元素必须被使用"的因果决策框架**,有三个核心机制: + +1. **埋伏 + 兑现的因果链**——任何"被显著引入"的元素(挂在墙上的枪、被反复提起的名字、刻意描述的物件)都在向读者**借款**。读者无意识记下这些"准记忆"。如果后续不提,读者会感到"作者控不住结构"。伏笔管理 = 借债台账管理。 +2. **分时间尺度(短 / 中 / 长)**——短篇里 3 页兑现,长篇里 30 万字兑现,系列里 5 本兑现。Clark 用 Hitchcock 的"暴露的羊腿"演示"短程伏笔"——标题里已告诉读者"羊腿是凶器",凶器当场兑现。Chekhov 原版是"中长程"——舞台第 1 幕,剧本第 3 幕。 +3. **删除测试(decision filter)**——Clark 的关键操作化工具:写完一段,问"如果删掉这个元素,故事是否变轻?"如果不变轻 → 它没承担叙事债务 → 删;如果变轻 → 它就是该被回收的伏笔。 + +**判断标准**:一个元素是"装饰"还是"债务"——取决于它是否被**显著呈现**(被镜头对准、被台词提及、被位置强调)。一旦被显著,就是借款,必须偿还。 + +**理论定位**:这是"结构-因果"层面的方法论(像 story-engine 是"问题-驱动"),不是"风格-修辞"层面(像 voice-equalizer)。它管的是"哪个元素必须存在",不是"这个元素怎么写得更好"。 + +## 操作清单(作者应自问) + +1. 写场景时:墙上这把枪会开火吗?如果不,弱化或删。 +2. 写转折前:我前面给读者埋下可信的钩子了吗? +3. 写章节末:这个元素是"装饰"还是"债务"?如果是债务,它在哪一章兑现? +4. 通读时:用删除测试扫一遍——哪些元素删掉后故事没变轻,就该删。 + +## Hitchcock 变体("已暴露的凶器") + +Chekhov 强调"枪必须开火"但**不必告诉观众它是凶器**;Hitchcock 反过来——**凶手在标题就暴露**(《Lamb to the Slaughter》"给屠夫的羔羊"=羊腿),读者看着"羊腿"登场即知其宿命,凶手戏仍成立,因"如何被用作凶器"本身仍是悬念。 + +**中文用法(中文适配)**:章名/卷名可借鉴——把关键元素**预先命名**,让读者带着"我等着看它怎么兑现"的预期进入。 + +变体给出的反直觉选项:**告诉读者你要兑现,让读者等兑现方式**。伏笔不一定"藏"——预暴露的凶器也是有效伏笔(戏剧反讽:观众比角色知道得早)。 + +## 伏笔与线索要分开管理 + +与"线索"(plot thread)的区别:线索是**人物/事件级别的叙事线**(如"主角追查父亲死因"是线索);伏笔是**具体元素级别的承诺**(墙上挂的猎枪是伏笔)。一条线索可包含多个伏笔,一个伏笔可跨多条线索。台账上两者要分别管理。 + +## 案例 + +### 案例 1:Anton Chekhov 1889 年关于"舞台上的枪"的信 + +- **问题**:戏剧/小说中如何避免"无关紧要的细节"稀释紧张感? +- **方法论的使用**:Chekhov 写信给同行,提出"如果第 1 幕墙上挂了一把枪,第 3 幕它必须开火"——这是**场景经济学的最严苛版本**:每一个被引入的显著元素都必须"做工"。 +- **结论**:元素是"装饰"还是"债务",**取决于它是否被显著呈现**。一旦被镜头/语言突出,就被读者标记为"重要",必须后续兑现。 +- **结果**:成为了西方戏剧/小说"伏笔管理"的金标准。所有关于 foreshadow、payoff、setup 的讨论都回到这条原则。 + +### 案例 2:Alfred Hitchcock《Lamb to the Slaughter》(希区柯克变体) + +- **问题**:Chekhov 说枪必须开火,但能否让读者**提前知道**它是凶器? +- **方法论的使用**:Hitchcock 在**标题**就告诉读者"羊腿会被杀"(lamb to the slaughter = 羔羊赴屠),读者带着"我等着看它怎么杀人"进入故事。戏剧张力不靠"谁干的",而靠"她怎么用一根无辜的羊腿杀人 + 警察怎么吃掉证据"。 +- **结论**:伏笔不一定"藏"——**预暴露的凶器**也是有效伏笔(戏剧反讽:观众比角色知道得早)。这种"变体"给了写作者一个反直觉选项:**告诉读者你要兑现,让读者等兑现方式**。 +- **结果**:成为了"伏笔不一定要藏"教学的标准案例;也展示了"已暴露的凶器"如何制造与 Chekhov 不同类型的悬念(what vs how)。 + +## 可执行步骤 + +### 步骤 1:建立伏笔台账(列出显著元素) + +- 列出当前章节/全书所有"被显著呈现"的元素(被镜头特写、被台词反复提及、被位置重点强调)。 +- 完成标准:每个元素被标注"装饰"或"债务";装饰项可考虑删除/弱化;债务项必须进入兑现时间表。 +- 判停条件:如果不知道哪些是显著元素,用这条判据——任何被**位置**(墙/桌上/口袋)、**重复**(提 2 次以上)、**特写**(用 1 段以上描写)或**对话**(被角色直接说出的)命中的元素。 + +台账模板见 [../references/foreshadow-ledger-template.md](foreshadow-ledger-template.md)。 + +### 步骤 2:按时间尺度分层(短 / 中 / 长) + +- **短期伏笔**:同章/同幕内(章末钩子 → 章内兑现,5-30 页内回收)。例:章末"她看见了那封信"→ 章内"信里是离婚协议"。 +- **中期伏笔**:同卷/同一故事弧内(50-200 页内回收)。例:第 1 章提到的"父亲的旧钥匙" → 第 8 章开门。 +- **长期伏笔**:全书/全系列(30 万字 / 5 本书内回收)。例:第 1 卷"主角的母亲从未出现" → 第 5 卷"母亲身份的揭示"。 +- 完成标准:每个伏笔被标注"短/中/长" + "预计在第 X 章/卷兑现"。 +- 判停条件:如果长篇伏笔跨度 > 30 万字或 > 3 卷,应**显式提示**定期回顾台账(否则就是"线索失踪"失败模式)。 + +### 步骤 3:应用删除测试(决定保留/弱化/删除) + +- 对每个标注为"装饰"的元素,问:"如果删掉它,这个场景/章节/全书是否变轻?" +- 不变轻 → 真的只是装饰 → 删。 +- 变轻 → 隐性债务,要么加强(让它"显著")以进入伏笔台账,要么删除/弱化避免误导读者。 +- 完成标准:能对每个候选元素给出"留 / 删 / 加强"决定,理由是"删除后变轻"还是"不变轻"。 +- 判停条件:不要在初稿阶段用删除测试——它在**修订阶段**最有效(初稿时你不知道哪些元素会"被用上")。 + +### 步骤 4:设计 Hitchcock 变体(选择性,非必须) + +- 问:这个伏笔是否适合**预暴露**?如果答案是"读者提前知道会更有张力"(戏剧反讽),用标题/章名/对话明示。 +- 不适合的场景:核心谜题(读者不知道才能猜)、情感爆点(读者预期外才有冲击)。 +- 适合的场景:读者已经知道"会发生什么"但"不知道会怎么发生"——把悬念从 what 移到 how。 +- 完成标准:能说出"这个伏笔是 Chekhov 经典款(藏)还是 Hitchcock 变体(暴露)"。 + +### 步骤 5:写兑现时间表(章节/卷对应) + +- 输出一张"伏笔台账 → 兑现表"——左边是"埋",右边是"兑现",中间是章节/卷数。 +- 完成标准:表格中所有"短期伏笔"都在同章/同幕内兑现;所有"中期伏笔"在 200 页内有兑现节点;所有"长期伏笔"有显式"最终兑现卷/章"标注。 +- 判停条件:如果某伏笔找不到兑现点,**删除**或**降低显著度**(不要让它成为"承诺但不兑现"——"线索失踪"失败模式)。 + +## 什么时候用这个单元 + +用户会在这些情境下需要"登记与兑现"这套方法: + +1. 长篇写到一半,发现第 3 章埋的某个角色后文没再出现——读者评论"那个 X 怎么了"? +2. 写了一堆"细节马赛克"但分不清哪些是"装饰"哪些是"债务",全留下来导致中段拖沓。 +3. 设计大长篇 30 万字 / 系列小说 5 本,不知道每个伏笔该在哪兑现——想"埋伏"但怕"埋了没收"。 +4. 写悬疑/推理:既想给读者"我猜到了"的满足,又怕"剧透式标题"让悬念全无,问"凶器能不能提前暴露"? +5. 网文连载:每一卷要兑现本卷伏笔 + 保留系列伏笔,问"短/中/长期伏笔怎么分层"? +6. 写完一个场景,觉得"这段描写很美但不知道为什么要写",但又不敢删——想确认它是否"做工"。 +7. 重读自己写的稿子,发现 5 章前一笔带过的细节现在没空间兑现——是该回头补还是删伏笔? +8. 编辑/读者反馈"你前面说的那个事没后文",但作者不记得说过什么——需要"伏笔台账"工具。 + +语言信号(用户的话里出现这些就应激活): + +- "契诃夫之枪" / "chekhov's gun" / "Chekhov 原则" +- "伏笔" / "foreshadow" / "铺垫" / "前情" +- "伏笔如何兑现" / "伏笔怎么收" / "伏笔怎么写" +- "伏笔分层" / "短期伏笔 / 中期伏笔 / 长期伏笔" / "多线伏笔" +- "线索失踪" / "线索埋了没收" / "埋了忘了" +- "显眼的凶器" / "Hitchcock 变体" / "预暴露的伏笔" +- "删除测试" / "这个细节要不要留" / "场景经济" +- "承诺但不兑现" / "前面挖的坑没填" +- "哪里该埋伏笔" / "哪里该回收" + +## 中文落地说明 + +Clark 写的是英文写作语境,迁到中文长篇/网文时注意: + +- **章回体传统天然支持 Hitchcock 变体**:章名/卷名预先点名关键元素("林教头风雪山神庙"式的章名),读者带着等待兑现的预期进入,这正是"预暴露"的中文母体。(中文适配) +- **台账工具本土化**:Clark 没有给网文百万字连载的系统方案,中文长篇需要自己补台账(Notion / Airtable / Excel)、多人合写的"伏笔分配表"、"读者已知 vs 角色已知"的双轨追踪。详见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md) 的盲点一节。(中文适配) diff --git a/framework/catalog/pi/skills/narration-pov/SKILL.md b/framework/catalog/pi/skills/narration-pov/SKILL.md new file mode 100644 index 0000000..634d77c --- /dev/null +++ b/framework/catalog/pi/skills/narration-pov/SKILL.md @@ -0,0 +1,66 @@ +--- +name: narration-pov +description: | + 中文小说写作中选择视角、叙述立场和叙述模式时使用。激活场景:选视角人物并决定向读者透露多少信息;想揭示封闭组织、社区、制度的荒谬而不说教;想写开放式结局、暧昧关系、命运类故事让读者回味;想避免作者跳出来下判断、给简单答案;决定何时暂停主线去做反思、插叙、独白、闪回并落回主线。 + 关键 trigger:视角、POV、全知、限制视角、外来者视角、局外人、叙述立场、怀疑、说教、太直白、开放式结局、不确定性、留白、插叙、倒叙、意识流、内心独白、主线太平、折线落不回去、主线与折线、折线、汽笛站、卡夫卡式、fish out of water、broken line。 + 不适用于:无叙事时间的纯抒情诗或散文;千字以内的单场景小品;推理悬疑等结尾必须给出确定答案的作品;需要明确价值观引导的儿童文学;需要明确立场的议论文、社论;纯对话剧本(对话的功能见 dialogue-craft)。 + 与 theme-and-stance 交接:远距荒诞外来者(布尔加科夫式撒旦访莫斯科)的完整案例与幽默结构归 theme-and-stance;本 Skill 只保留外来者切入机制,案例见 references/outsider-entry.md 第三节指针。 +--- + +# 叙述与视角(narration-pov) + +管三件事:用谁的眼睛看(视角),站在什么立场讲(叙述立场),讲的过程怎么走(确定与不确定的张力、主线与折线的调度)。 + +## 方法索引 + +按创作动作组织。方法细节、操作步骤、判断标准、案例全文、原文摘录都在 references/ 里,本文件只做指针。 + +- **选视角人物、定信息范围**:视角是摄像头——人物看到什么读者才看得到,视角人物的判断就是隐形叙述,视角转换就是真相揭示 → references/pov-camera.md +- **落地视角限制**:五步——主视角设定卡、看世界的滤镜、知情范围与视角数量、视角转换点、用盲区藏秘密;含触发场景、适用边界、常见错误 → references/pov-execution.md +- **用外来者揭开封闭系统**:不直接批判,让一个外来者进入组织/社区/制度/文化;碰壁场景加内部人麻木做对比,荒谬自行呈现 → references/outsider-entry.md +- **立怀疑的叙述立场**:看法会陈旧、事实不会;把看法替换成事实、肯定后跟否定、写表层之下的一层、结尾不收死 → references/skeptical-stance.md +- **构造确定与不确定的张力**:方向 A 从不确定走向确定但始终没走到,方向 B 从确定走向不确定但没成功;锚点与屏障并设,让读者的想象力在两极间徘徊 → references/certainty-uncertainty.md +- **调度主线与折线**:主线运行动,折线停车上意义,折线必须落回场景锚;SCENE/BREAK 标注、比例 2:1、500 字回归、三条判停条件 → references/broken-line.md +- **边界与常见误区**:各方法的适用边界、失败模式、作者盲点、易混淆的邻近方法,随各自方法记在对应 references 文件的末尾各节 +- **执行检查清单**:设定、写作中、修订三阶段的核对清单与快速排错表 → references/narration-pov-checklist.md + +视角人物说出/想到视角之外的信息(知识诅咒逐句检查)归 show-and-omission;伏笔的埋设与回收归 foreshadow-payoff;章末钩子归 narrative-momentum;摄影机距离归 scene-craft;对话的功能归 dialogue-craft。本 skill 只管上述三件事。 + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|---------| +| references/pov-camera.md | 视角 = 摄像头三原则、开篇引文、海明威《杀手》障眼法 R 原文、四案例全文(《杀手》/《故乡》/《布莱克·沃滋沃斯》/《红楼梦》王熙凤(多视角看可卿,标题保留源单元原文))、视角的"重"和"轻"、一句话总结、中文落地 | +| references/pov-execution.md | 视角限制五步执行(主视角 yaml 卡、滤镜三问、知情范围与短篇 1-2 / 长篇每章、转换点设计、盲区藏秘密)、触发场景五条、适用边界(含第二人称慎用)、常见错误五行、跨 skill 链接四条 | +| references/outsider-entry.md | 外来者切入法:熏肉切刀引文全量、三机制(内部人麻木/外来者不适应/自行呈现)、三案例全文(《城堡》K 进村、余华 1983 北京问路、《大师和玛格丽特》撒旦访莫斯科)、六步执行、触发场景、边界三条、失败模式两条、盲点两条、易混淆两条、中文落地 | +| references/skeptical-stance.md | 怀疑主义叙述法:四条引文全量、看法陈旧/事实不陈旧/怀疑优于肯定、三实践、写作改变人、三案例全文(博尔赫斯《沙之书》、蒙田、干渴与对干渴的恐惧)、五步执行(含信号词)、边界三条、失败模式两条(含权威自负引文)、盲点两条、易混淆两条、与 certainty-uncertainty 的合并标注 | +| references/certainty-uncertainty.md | 确定性-不确定性张力:哥廷根演讲引文两段全量、方向 A/B、三案例全文(格奥尔基《悲伤的物理学》粘信封、沙拉莫夫《大夫三死》退后一步向前一步、博尔赫斯迷宫)、五步执行(锚点/屏障/自检)、边界三条、失败模式两条、盲点两条、易混淆两条、与 skeptical-stance 的合并标注 | +| references/broken-line.md | 混合叙事模式:Tool 36 英文原文全量 + 译文、unbroken/broken line 二分与火车比喻、切换三规则、两案例全文(哈姆雷特独白、《Alfie》打破第四面墙)、三步执行含判停条件、边界四条、失败模式三条(含英文引文)、盲点与时代局限四条、易混淆三条、相关 skill 记录全量、中文落地 | +| references/_coverage.md | 覆盖对照表:五个源单元全部方法点的落点核对 | +| references/narration-pov-checklist.md | 执行检查清单:视角设定卡、封闭系统与外来者、看法入侵扫描、确定-不确定张力自检、主线/折线标注诊断(含量化阈值与判停条件)、快速排错表 | + +## 脚本 + +| 脚本 | 用途 | 来源 | +|------|------|------| +| references/narration-pov-checklist.md | 叙述与视角检查清单:按写作进程排列(设定阶段视角设定卡;写作中外来者与看法入侵扫描;修订阶段张力自检、主线/折线标注诊断含 SCENE/BREAK 比例与 500 字回归判停),附快速排错表 | 五个源单元的执行步骤合并 | + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 红线 + +- 只给当前创作阶段的建议,不越权改设定主权、不绕过检测链、不复制粘贴其它 Skill 的 owner 定义。 +- 无用户明确授权不得替用户定稿或提交 Git。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/pi/skills/narration-pov/references/_coverage.md b/framework/catalog/pi/skills/narration-pov/references/_coverage.md new file mode 100644 index 0000000..5249337 --- /dev/null +++ b/framework/catalog/pi/skills/narration-pov/references/_coverage.md @@ -0,0 +1,14 @@ +# narration-pov 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| bifeiyu-novel-skill/bifeiyu-perspective | references/pov-camera.md | +| bifeiyu-novel-skill/bifeiyu-perspective | references/pov-execution.md | +| wo-neng-fou-xiang-xin-zi-ji/certainty-uncertainty-tension | references/certainty-uncertainty.md | +| wo-neng-fou-xiang-xin-zi-ji/certainty-uncertainty-tension | references/skeptical-stance.md | +| wo-neng-fou-xiang-xin-zi-ji/outsider-perspective | references/outsider-entry.md | +| wo-neng-fou-xiang-xin-zi-ji/skeptical-narration | references/skeptical-stance.md | +| wo-neng-fou-xiang-xin-zi-ji/skeptical-narration | references/certainty-uncertainty.md | +| writing-tools-clark/mix-narrative-modes | references/broken-line.md | diff --git a/framework/catalog/pi/skills/narration-pov/references/broken-line.md b/framework/catalog/pi/skills/narration-pov/references/broken-line.md new file mode 100644 index 0000000..961577a --- /dev/null +++ b/framework/catalog/pi/skills/narration-pov/references/broken-line.md @@ -0,0 +1,131 @@ +# 混合叙事模式:主线与折线的调度 + +> 来源单元:《写作工具》(Roy Peter Clark)writing-tools-clark/mix-narrative-modes,Tool 36 · Mix narrative modes。 +> 可执行的标注诊断流程见 [../references/narration-pov-checklist.md](narration-pov-checklist.md) 第五节。 + +## R 原文(英文全量 + 中文译文) + +> The writer tells us a story, then stops the story to tell us about the story, but then +> returns to the story. Imagine this form as a train ride with occasional whistle stops. +> +> Think of its opposite, the unbroken line. Most movies are unbroken narrative lines. +> Frodo takes possession of the ring of power and sets out on a journey to destroy it. +> On occasion, a director will break the line of narrative for some other purpose. In +> the movie Alfie, the main character stops the action, turns to the camera, and speaks +> to the audience. +> +> — Roy Peter Clark, *Writing Tools* (Tool 36)() + +译文:作家给我们讲一个故事,然后停下来讲关于这个故事的事,接着再回到故事本身。可以把这种形式想象成一趟偶尔在"汽笛站"停靠的火车旅程。想想它的反面——不断线。大多数电影就是不断的叙事线:弗罗多拿到至尊魔戒,出发去销毁它。偶尔,导演会为了别的目的打断叙事线:电影《Alfie》里,主角停下动作,转身面对镜头,直接对观众说话。(中文译文;原文) + +## 方法核心:叙事时间结构的两个极端 + +Clark 的核心二分法是关于**叙事时间结构**的两个极端: + +- **unbroken line(主线 / 不断线)**:按事件时间一路推进——Frodo 拿戒指 → 出发 → 毁戒指;James Bond 接任务 → 救世界 → 抱得美人。读者被"运"着走,沉入动作。 +- **broken line(折线 / 断线)**:在主线的某一点"鸣笛停车"——暂停动作去做解释、反思、评论、独白、跳到另一时空(回忆、闪前、意识流),再**落回**主线。 + +Clark 的核心比喻是**一趟带"汽笛站"(whistle stops)的火车**:场景 = 行进,折线 = 停车上货(意义层);列车必须重新启动。 + +何时切换?三条规则: + +1. 主线太单薄 → 加 1-2 个折线段给"altitude gain"(意义高度); +2. 折线过多读者缺氧("too much ozone")→ 立刻落回主线场景给具体人、物、动作; +3. 任何折线**必须"起落"配对**——出去解释/反思/独白,必须回到场景锚(scene anchor)。 + +判断口诀:每段尾读者是否知道"我现在在火车的哪一节、哪一站"?若是,结构正确;否则就是断线事故。() + +## 书中案例 + +### 案例 1:哈姆雷特独白("To be or not to be") + +- **问题**:在最忙乱的动作中,如何揭示人物心理而不打断节奏? +- **方法论的使用**:哈姆雷特在最紧张的剧情中**暂停动作**,长篇独白"生存还是毁灭,这是个问题"——Clark 明示:"does not advance the story, but reveals Hamlet's indecision." 这是**典型折线**:不推进动作,但揭示犹豫、抑郁、哲学化倾向。 +- **结论**:折线 = 主线(动作)中的跳出(自省 / 解释 / 评论 / 独白);节奏由动转静,但读者被"洞察"抓住,不离场。 +- **结果**:成为了"在快速动作中插入人物心理"的西方文学原典。Clark 把它作为"戏剧性折线"的标杆案例引用,与莎翁其他悲剧独白并列。 + +### 案例 2:电影《Alfie》主角对镜头独白 + +- **问题**:如何用比"内心独白"更激进的方式跳出主线? +- **方法论的使用**:主角 Alfie 停下手头动作,**直接转身面对镜头说话**——打破第四面墙,等于把读者/观众当对话者呼告。Clark 描述:"the main character stops the action, turns to the camera, and speaks to the audience. These surprise monologues reveal the corners of his character and foreshadow plot complications." +- **结论**:折线的极端形态 = 跳出"虚构世界契约"本身,把读者/观众当对话者。比哈姆雷特更激进(哈姆雷特仍是在虚构世界内说话)。 +- **结果**:成为了"打破第四面墙"的现代电影/小说标杆;在中文写作里常被类比为**第一人称元叙事**、**小说人物直接对读者说话**。 + +(以上两例均出自) + +## 执行步骤 + +1. **诊断结构 + 标注主线 / 折线** + - 取出章节 / 手稿,把每段标注为 `SCENE(主线,事件在动)` 或 `BREAK(折线:解释 / 反思 / 独白 / 插叙 / 意识流 / 旁白评论)`。 + - 完成标准:每段有清晰标注;读者一眼看出"现在是在火车上,还是停在汽笛站"。 + - 判停条件:若折线段后 500 字内无 SCENE 回归,标记为"断线事故",需补场景锚。 + +2. **检查"起落"平衡** + - 数主线与折线比例:折线 ≤ 30-40%(否则读者缺氧)。一段折线后必须接 1-2 段 SCENE。 + - 完成标准:全章 SCENE ≥ BREAK 比例约 2:1;每个 BREAK 段后 ≤ 500 字回到 SCENE。 + - 判停条件:若 BREAK 段 > 1000 字且无 SCENE 锚回,拆为更小段,或改写为 SCENE 内的对白 / 动作。 + +3. **加 altitude gain(意义层)或落回 scene(场景层)** + - 在每个长 SCENE 段后问:"读者会不会问'so what?'"——若是,加 1 段 nut paragraph 回答(给意义高度)。 + - 在每个 BREAK 段后问:"读者知道我在哪个时间、哪个场景吗?"——若是,落回具体物、人、动作(场景锚)。 + - 完成标准:任何 BREAK 段尾**必须有 scene anchor**(具体物、人物动作、可感的环境);任何长 SCENE 后**至少有 1 段 altitude**(反思、解释、主题意义)。 + - 判停条件:若一段独白/插叙尾只有抽象句而无具体动作,改写为"动作 + 短句反思"或转回 SCENE。 + +() + +## 触发场景 + +1. 写小说主线一路平铺,觉得"太平、太流水账",不知何时插一段解释/反思/独白。 +2. 想做复杂时间线(倒叙、插叙、意识流、多 POV),但写出来读者弃读——折线没"落回"。 +3. 写了一段漂亮的独白/插叙,但段落"出得去回不来"——读者在折线尾迷失"我刚才离开了哪个时间、哪个场景"。 +4. 写非虚构(报告文学、特稿、长报道),故事讲着讲着"信息密度"压垮读者,需要"场景→解释→回到场景"的呼吸。 +5. 多 POV / 多时间线小说,不知"何时切到回忆、何时切回当下、何时停在高空讲主题"。 + +语言信号:"mix narrative modes""broken line""主线 vs 折线""unbroken line""whistle stop""nut paragraph""何时跳出动作""何时回到场景""scene + altitude""意识流 vs 主线""倒叙怎么用""插叙落不回去""独白放在哪里""独白用错位置""打断第四面墙""小说节奏""章节结构""时间线设计""POV 切换""折线太多读者弃读""主线太平""何时解释何时叙事""so what 段落"。() + +## 边界:不要在以下情况使用 + +- **单场景小品 / 千字以内短篇**——没有足够长度玩主线/折线切换,折线会被压成噪音。 +- **纯抒情诗 / 散文诗**——叙事时间不是骨架,Clark 的火车比喻不适用。 +- **纯对话剧本(话剧)**——折线靠独白/旁白完成,话剧默认场内连续时间,改用 dialogue-as-action(归综合 skill dialogue-craft)。 +- **短消息 / 推文 / 短资讯**——没有"主线"载体,谈折线无意义。 + +() + +## 作者在书中警告的失败模式 + +- **bait and switch(诱骗式切换)**:开篇用叙事 lead 假装讲故事,实际通篇是信息密度。Clark 明示:"No reader wants to be fooled by a story lead that promises narrative, only to discover a body dense with information." 机制:折线挤掉了主线,读者在汽笛站下车找不到回程列车。 +- **too much ozone(高空缺氧)**:折线叠折线,读者一直停在"意义层"不见地面。Clark 借 Lemann 之例警告:"too much ozone can leave the reader feeling oxygen deprived." 信号:连续 3 段以上无场景锚(无具体人、物、动作)。 +- **whistle stop without train(汽笛站没有列车)**:一段独白/插叙**只出去不回来**——读者在段落尾不知道"我刚才离开了哪个时间、哪个场景"。机制:折线段落结尾无 scene anchor(具体物、人物动作、可感的环境)。Clark 的隐含标准:折线必须**以场景落回**,不是以抽象反思收尾。 + +() + +## 作者的盲点 / 时代局限 + +- Clark 的 broken line 例子偏**非虚构**(Nicholas Lemann 的《The Promised Land》、WSJ 特稿),小说例子偏**戏剧性独白**(哈姆雷特、Alfie、Our Town、Rocky Horror)。**当代中文长篇小说(多 POV、多时间线、心理现实主义)**的折线模式未深入展开,作者需自己类比——把"soliloquy"换成"意识流 / 内心旁白 / 时空跳转",把"altitude gain"换成"主题反思 / 作者介入"。 +- 时代局限:Clark 写于 2006 年,未涵盖**网文 / 类型小说(穿越、悬疑、多线叙事、意识流)**——这些文体的折线模式(如"现实层 / 系统层 / 记忆层"三线并行)有更激进的结构,需结合原型工具与章内钩子一起用(archetype-toolkit 归 character-design、internal-cliffhanger 归 narrative-momentum)。 +- 文化迁移:"soliloquy / 独白"在西方戏剧传统中是被观众接受的(从莎翁到现代剧);中文小说大量使用"内心独白"会被部分读者视为"作者代笔"——折线在中文写作中**密度需更低**,且落回场景的速度需更快。 +- 反例:Clark 引用的"古董色情片白大褂治疗师"做"redeeming social value"说明("so I've been told"),在中文语境下既不常见也容易触发审查,迁移时**改用哈姆雷特 / Our Town / 红楼梦判词**等更贴近中文读者的例子。 + +() + +## 容易混淆的邻近方法论 + +- 与 "show, don't tell"(Tool 27):那个管"用动作和细节显示",这个管"何时用动作、何时用解释"——前者是"如何写一个画面",后者是"何时停在画面外去讲意义"。(show, don't tell 归综合 skill show-and-omission) +- 与 "active verbs"(Tool 3):那个管"动词的力度",这个管"段落级时间结构"。(active verbs 是《写作工具》同书工具,未入本技能库) +- 与 "inciting incident"(Tool 55):那个管"开篇钩子",这个管"全程模式切换的呼吸"。(inciting incident 归综合 skill story-structure) + +() + +## 与相邻方法的区分和配合(源单元相关 skill 记录全量) + +- 与 cinematic-distances 的区别:那个管**"摄影机物理距离"**(鸟瞰到特写,Tool 34),这个管**"叙事时间结构"**(主线 vs 折线、何时离开当下动作)。一个改"看得见多近",一个改"何时离开/回到当下"。(cinematic-distances 归综合 skill scene-craft) +- 与 sentence-rhythm 的区别:那个管**"句法节奏"**(句长、停顿、对仗,Tool 18),这个管**"叙事单元时间结构"**(场景 vs 解释、独白 vs 动作的来回)。一个在句子层,一个在篇章/章节层。(sentence-rhythm 归综合 skill prose-craft) +- 与 write-toward-ending 的区别:那个管**"结尾策略"**(Tool 39,如何收束、闭合意义圆),这个管**"中段叙事模式混合"**(场景与解释、独白与动作的全程调度)。一个在末段,一个在全程。(write-toward-ending 归综合 skill story-ending) +- 与 internal-cliffhanger 的区别:那个管**"章末钩子"**(单点张力),这个管**"全程模式切换"**(段与段、章与章)。(internal-cliffhanger 归综合 skill narrative-momentum) +- 与 dialogue-as-action 的区别:那个管"对话作为单一模式的功能",这个管"对话 / 独白 / 旁白 / 场景作为模式之间的切换"——后者是更大的时间结构框架。(dialogue-as-action 归综合 skill dialogue-craft) +- 源单元相关 skill 记录:contrasts-with cinematic-distances、sentence-rhythm、write-toward-ending;composes-with dialogue-as-action(折线内的对话如何"做事")、internal-cliffhanger(折线切换点作为张力钩)、archetype-toolkit(原型决定折线的功能);depends-on:无。() + +## 中文落地说明 + +Clark 是英文书,中文落地的要点源单元已经给出:一是折线密度放低、落回场景更快——中文读者把大段"内心独白"当"作者代笔";二是把西方戏剧独白的例子换成中文读者熟悉的对应物(哈姆雷特可换《红楼梦》判词、戏曲背供),把 soliloquy 类比成意识流 / 内心旁白 / 时空跳转,把 altitude gain 类比成主题反思 / 作者介入;三是网文类型(穿越、系统、多线)的"现实层 / 系统层 / 记忆层"三线并行是比 Clark 例子更激进的折线结构,需与章内钩子配合使用。(中文落地;方法本体) diff --git a/framework/catalog/pi/skills/narration-pov/references/certainty-uncertainty.md b/framework/catalog/pi/skills/narration-pov/references/certainty-uncertainty.md new file mode 100644 index 0000000..09dc587 --- /dev/null +++ b/framework/catalog/pi/skills/narration-pov/references/certainty-uncertainty.md @@ -0,0 +1,128 @@ +# 确定性-不确定性张力构造法 + +> 来源单元:《我能否相信自己》(余华)wo-neng-fou-xiang-xin-zi-ji/certainty-uncertainty-tension,出自《不确定性》演讲(2025,哥廷根大学)。 + +## R 原文 + +> "任何不确定性的对面都存在着确定性, 不确定性的出现, 是为了阻挡我们走向确定性。有时候我们走到了确定性, 有时候我们永远走不到确定性。" +> +> "这正是文学带给我们的魅力, 能够充分发挥我们的想象力, 让我们的想象力在不确定性和确定性之间徘徊, 去考虑到这些可能性的因素。" +> +> — 余华, 哥廷根大学演讲《不确定性》() + +## 方法核心 + +文学叙述的核心张力来自**确定性与不确定性之间的动态关系**。不确定性不是"没有答案",而是"阻挡我们走向确定性"——它让读者的想象力在两极之间徘徊,考虑各种可能性。 + +两种基本叙述方向: + +1. **从不确定性走向确定性,但始终没走到**:读者隐约感觉到真相,但叙述永远不给确认。格奥尔基《悲伤的物理学》中,"漂亮"这个匈牙利单词引发奶奶对爷爷的怀疑,爷爷确实有一个匈牙利女人,但奶奶永远没有抵达这个确定性——她宁愿带着不确定性死去,也不愿承担确定性带来的风险。 +2. **从确定性走向不确定性,但没成功**:结果似乎是确定的(医生要被处决),但叙述试图走向一个不确定的结局(医生救活监狱长妻儿,似乎可以不死),最终仍然回到确定性。沙拉莫夫《大夫三死》中医生第二天仍被处决。 + +好的叙述不是给出确定答案,而是让读者在确定性与不确定性之间徘徊。当不确定性比确定性更安全时,人物(和读者)会选择停在不确定性中。() + +**合并说明**:"好的叙述不是给出确定答案"与 [skeptical-stance.md](skeptical-stance.md) 的"不给出确定答案"是同一条规则——本文件管叙述结构(确定与不确定的张力怎么走),skeptical-stance.md 管叙述立场(怀疑而非肯定),立场决定结构。博尔赫斯案例两个文件都保留,角度不同:本文件取结构角度(在两极间来回走动,读者身处迷宫),skeptical-stance.md 取立场角度(怀疑、《沙之书》答案消失在无限中)。(合并标注; + skeptical-narration) + +## 书中案例 + +### 案例 1:格奥尔基《悲伤的物理学》——从不确定到确定但没走到 + +- **问题**:爷爷从匈牙利带回七个单词,其中"漂亮"让奶奶怀疑他在匈牙利有女人。 +- **方法论的使用**:爷爷确实有一个匈牙利女人(确定性),但奶奶永远没有确认——她收到一封来自匈牙利的信,看了以后什么也没说,"只是认真地又把信封粘好, 交给了她丈夫"。她宁愿带着不确定性死去,也不愿承担确定性带来的风险。 +- **结论**:叙述从不确定性(怀疑)走向确定性(真相),但人物主动停下,永远没走到。 +- **结果**:读者的想象力在"奶奶知道吗?""她为什么不确认?"之间徘徊。 + +### 案例 2:沙拉莫夫《大夫三死》——从确定到不确定但没成功 + +- **问题**:医生被判决处决,这是确定的结果。 +- **方法论的使用**:医生被拉去枪毙时,监狱长妻子难产,医生被救活监狱长妻儿,似乎可以不死(走向不确定性)。但医生认为监狱长是恶棍,退后一步宁愿去死;然后"想活下来, 哪怕再活一天一夜"又向前一步。最终第二天早上仍被处决——不确定性的尝试失败,回到确定性。 +- **结论**:从确定性(处决)出发,试图走向不确定性(不死),但没成功。 +- **结果**:读者在"他会不会死?"的悬念中经历了整个故事,最终回到确定的死亡。 + +### 案例 3:博尔赫斯——永远无法确定的叙述 + +- **问题**:博尔赫斯如何让叙述充满文学魅力? +- **方法论的使用**:博尔赫斯的叙述"总是假装地要确定下来了, 可是永远无法确定。我们耐心细致地阅读他的故事, 终于读到了期待已久的肯定时, 接踵而来的立刻是否定。" +- **结论**:博尔赫斯在确定性与不确定性之间来回走动,让读者永远在徘徊。 +- **结果**:读者身处迷宫之中,找不到出口,这正是博尔赫斯乐意看到的。 + +(以上三例均出自;案例 3 与 skeptical-stance.md 的博尔赫斯案例为同一作品、不同角度,两处都保留) + +## 执行步骤 + +1. **选择叙述方向** + - 方向 A:从不确定性走向确定性,但始终没走到(适合人物关系、秘密、真相类故事) + - 方向 B:从确定性走向不确定性,但没成功(适合命运、死亡、不可抗拒的结局类故事) + - 完成标准:明确故事采用哪种方向 + +2. **设置确定性的锚点** + - 方向 A:让读者隐约感觉到真相(通过细节、暗示),但叙述永不确认 + - 方向 B:让结局在开头就确定(如"他被判了死刑"),然后叙述试图推翻它 + - 完成标准:读者能感觉到确定性的存在,但无法抓住它 + +3. **设置不确定性的屏障** + - 方向 A:让人物主动选择不确认(像奶奶那样粘好信封),或让关键证据缺失 + - 方向 B:让人物试图改变命运(医生救人、越狱、反抗),给读者"也许会不一样"的希望 + - 完成标准:不确定性有明确的来源,不是"作者没写清楚" + +4. **让想象力在两极间徘徊** + - 不要给出最终答案 + - 可以在结尾给出一个暗示,但暗示本身应该是多义的 + - 完成标准:读者读完后会想"到底是怎么回事?"并开始自己想象 + +5. **检查张力是否有效** + - 问自己:读者能同时感觉到确定性和不确定性吗? + - 如果只有不确定性(完全没线索),读者会困惑而非回味 + - 如果只有确定性(答案太明显),读者会觉得无聊 + - 完成标准:两者并存,读者在其间徘徊 + +() + +## 触发场景 + +1. 写的故事读完就忘,没有回味空间 +2. 想写开放式结局但不知道怎么处理 +3. 想提升作品的文学性和深度 +4. 悬念设置太直白,读者一眼看穿 +5. 想让读者在阅读中主动思考和想象 +6. 写人物关系时,想保留暧昧和模糊性 + +语言信号:"故事没深度""读完就忘""开放式结局怎么写""怎么留白""怎么设置悬念""想让读者回味""文学性不够""太直白了""不确定性""暧昧""模糊"。() + +## 边界:不要在以下情况使用 + +- **推理小说/悬疑小说**:这类作品最终必须给出确定答案(谁是凶手),不确定性只存在于阅读过程中,不能在结尾保留。 +- **需要明确信息的场景**:如小说中的规则说明、世界观设定,必须确定。 +- **初学者的第一篇作品**:先学会把故事写清楚,再尝试不确定性的张力。 + +() + +## 作者在书中警告的失败模式 + +- **不确定性 = 没写清楚**:很多初学者把"留白"和"没写完"混淆。有效的不确定性是"有线索但不确认",不是"什么都没给"。 +- **为了不确定而不确定**:如果不确定性没有情感或主题的支撑,只是故弄玄虚,读者会觉得被戏弄。 + +() + +## 作者的盲点 / 时代局限 + +- 余华主要从纯文学角度讨论不确定性,没有讨论类型小说中如何平衡不确定性与读者满足感。 +- 演讲中用的例子(保加利亚小说、俄罗斯小说)较为小众,对大众读者的参考性有限。 + +() + +## 容易混淆的邻近方法论 + +- **"悬念"(suspense)**:悬念是"接下来会发生什么",本方法是"真相到底是什么"——前者是情节层面的,后者是存在层面的。 +- **"开放式结局"**:开放式结局是本方法的一种应用,但本方法也可以用在故事中间,不只是结尾。 + +() + +## 与相邻方法的区分和配合 + +- 与 [skeptical-stance.md](skeptical-stance.md):本方法是叙述结构技巧(确定性与不确定性的张力),skeptical-stance.md 是叙述立场(怀疑而非肯定)。两者经常配合——怀疑主义立场自然产生不确定性的叙述。() +- 与细节驱动高潮(detail-driven-climax)的区别:detail-driven-climax 关注情节高潮的驱动机制,本方法关注整体叙述的张力结构。一个是局部技巧,一个是全局结构。细节驱动高潮给出确定的情节转折,本方法保留不确定性,两者形成对比。(detail-driven-climax 归综合 skill foreshadow-payoff; 相关 skill 记录:composes-with skeptical-narration、contrasts-with detail-driven-climax) + +## 中文落地说明 + +方法本身无语言差异,中文写作直接可用。两个方向的中文现成参照:方向 A(有线索但不确认)接近中国古典小说的"春秋笔法"与志怪笔记里"其事可疑、不置一词"的收法,也接近当代家庭叙事里藏着不揭破的秘密(如奶奶粘信封式的动作收场);方向 B(结局开头定死、叙述试图推翻)在余华《活着》式的命运叙事里常见——读者早知道人要一个个死去,仍抱着"也许会不一样"的希望读下去。类型写作注意:悬疑推理结尾必须给确定答案,不确定性只能放在阅读过程中。(中文落地;方法本体) diff --git a/framework/catalog/pi/skills/narration-pov/references/narration-pov-checklist.md b/framework/catalog/pi/skills/narration-pov/references/narration-pov-checklist.md new file mode 100644 index 0000000..93eff2b --- /dev/null +++ b/framework/catalog/pi/skills/narration-pov/references/narration-pov-checklist.md @@ -0,0 +1,85 @@ +# 叙述与视角检查清单 + +> 汇总五个源单元的可执行检查项,按写作进程排列:设定阶段 → 写作中 → 修订阶段。 +> 每条注明来源;方法细节与案例见 references/ 对应文件。 +> 视角人物说出/想到视角之外信息的逐句检查(知识诅咒)不在此表,见 show-and-omission/references/show-omission-checklist.md 第六节(一句话指针)。 + +## 一、设定阶段:视角设定卡 + +选定视角人物前逐条核对(/bifeiyu-perspective): + +- [ ] 主视角卡已填:他能看到的(列具体内容)/ 他看不到的(列具体内容)/ 他的判断标准(他怎么看世界) +- [ ] 主视角必须有限——他不能看到一切 +- [ ] 知道他看世界的"滤镜":恐惧(看到的都是威胁)/ 好奇(看到的都是机会)/ 厌倦(看到的都是无聊) +- [ ] 知情范围已划:能知道的只有他能观察到的、能推断的、别人告诉他的;对方的真实想法、历史、未来发展都在盲区 +- [ ] 视角数量受控:短篇 1-2 个主视角;长篇可流动,但不频繁(每章换视角读者会累) +- [ ] 每次视角转换都先定好要揭示什么:视角 A 看表面/误导/一面,视角 B 看另一面/真相/立体;揭示不出新东西就不换 +- [ ] 秘密有藏处:主视角不知道、但读者通过线索(飞白)能猜到——视角限制 = 戏剧张力 +- [ ] 没有用全知视角——全知视角 = 没秘密 = 没戏 +- [ ] 没有用第二人称,除非明确要做实验(主流读者不易接受) + +## 二、设定与写作中:封闭系统与外来者 + +要揭示组织/社区/制度/文化的荒谬或本质时执行(/outsider-perspective): + +- [ ] 要揭示的封闭系统已明确:它是什么(公司/社区/制度/文化/家庭),不合理性/独特性在哪里 +- [ ] 外来者角色有明确冲突点:来自哪里、为什么进入、什么习惯/价值观与系统冲突 +- [ ] 安排了 3-5 个碰壁/困惑场景,每个场景展示系统的一处不合理/独特之处 +- [ ] 只描写外来者的反应和系统的反应,没有作者跳出来解释"这个制度有多荒谬" +- [ ] 至少有一处内部人与外来者的反应对比:内部人习以为常,嫌外来者"大惊小怪""不懂规矩" +- [ ] 外来者与系统的关系有发展和结局:逐渐理解但保持批判距离,或始终被拒绝(像 K 永远进不了城堡),两种都有效 +- [ ] 外来者没有太顺利适应——适应太顺利就变成系统导游,失去揭示荒谬的功能 +- [ ] 外来者没有直接说"这个制度真荒谬"——他的不适应本身就是批判 +- [ ] 确认过系统本身确实有不合理性,不是"外来者无知"冒充"制度荒谬" + +## 三、写作中:看法入侵扫描(怀疑立场) + +通读草稿,逐条执行(/skeptical-narration): + +- [ ] 全文标出作者直接给判断/评价/结论的地方,信号词:"这说明…""由此可见…""真正的…是…""我们应该…"(中文叙述腔里的"这正是人性的悲哀""可见命运弄人"类总结句一并扫描)(后半句为中文适配补充) +- [ ] 每处看法已替换为事实:"他是个虚伪的人" → 说一套做一套的具体细节;"这个社会很冷漠" → 具体的冷漠场景(路人无视摔倒的老人) +- [ ] 至少有一处"肯定→否定"的反转:给出看似确定的结论后,跟上反面的可能(博尔赫斯式:肯定后立刻否定跟进) +- [ ] 至少有一处抵达"表层之下":不只写干渴,还写干渴后面更可怕的对干渴的恐惧;问过"这个事实背后还有什么?这个情绪的底层是什么?" +- [ ] 结尾没收死:不给确定答案,用一个多义的细节/意象/对话收尾,读者读完会继续思考 +- [ ] 怀疑没有变成虚无:怀疑是对"看法"局限性的清醒,事实仍然可靠;没有借怀疑之名什么都不呈现 + +## 四、修订阶段:确定性与不确定性张力 + +故事要让读者回味、在确定与不确定之间徘徊时执行(/certainty-uncertainty-tension): + +- [ ] 已选定叙述方向:方向 A(从不确定走向确定,但始终没走到,适合人物关系、秘密、真相类)/ 方向 B(从确定走向不确定,但没成功,适合命运、死亡、不可抗拒类) +- [ ] 确定性锚点在:方向 A 用细节、暗示让读者隐约感觉到真相但叙述永不确认;方向 B 让结局在开头就确定(如"他被判了死刑"),叙述试图推翻它 +- [ ] 不确定性屏障在:方向 A 让人物主动选择不确认(像奶奶那样粘好信封)或关键证据缺失;方向 B 让人物试图改变命运(救人、越狱、反抗),给读者"也许会不一样"的希望 +- [ ] 不确定性有明确来源,不是"作者没写清楚"——有效的不确定性是"有线索但不确认",不是"什么都没给" +- [ ] 不确定性有情感或主题支撑,不是为不确定而不确定、故弄玄虚 +- [ ] 结尾暗示是多义的,读者读完会想"到底是怎么回事?"并开始自己想象 +- [ ] 张力自检:读者能同时感觉到确定性和不确定性吗?只有不确定(无线索)→ 读者困惑;只有确定(答案太明显)→ 读者无聊 +- [ ] 确认不是推理/悬疑题材——这类结尾必须给出确定答案,不确定性只能放在阅读过程中 +- [ ] 世界观设定、规则说明等需要明确信息的地方没有误用不确定性 + +## 五、修订阶段:主线 / 折线标注诊断 + +手稿主线平铺、折线落不回去、独白插叙用错位置时执行(/mix-narrative-modes): + +- [ ] 每段已标注 `SCENE`(主线,事件在动)或 `BREAK`(折线:解释/反思/独白/插叙/意识流/旁白评论) +- [ ] 比例合格:全章 SCENE:BREAK 约 2:1,折线不超过全篇 30-40%;一段折线后接 1-2 段 SCENE +- [ ] 每个 BREAK 段后 500 字内回到 SCENE;超出 500 字未回即"断线事故",补场景锚 +- [ ] 判停:BREAK 段超过 1000 字且无 SCENE 锚回 → 拆为更小段,或改写为 SCENE 内的对白/动作 +- [ ] 任何 BREAK 段尾都有 scene anchor(具体物、人物动作、可感的环境);独白/插叙尾只有抽象句的,改写为"动作 + 短句反思"或转回 SCENE +- [ ] 任何长 SCENE 后至少有 1 段 altitude(反思、解释、主题意义)回答读者的"so what?"(nut paragraph) +- [ ] 每段尾读者都知道"我现在在火车的哪一节、哪一站"——答不上就是断线事故 +- [ ] 没有诱骗式切换(bait and switch):开篇许诺讲故事,通篇塞信息密度 +- [ ] 没有高空缺氧(too much ozone):连续 3 段以上无场景锚(无具体人、物、动作) +- [ ] 中文语境适配:内心独白密度放低、落回场景更快——大段独白会被中文读者当成"作者代笔"(中文适配;源单元文化迁移节) + +## 快速排错表 + +| 症状 | 诊断 | 处方 | +|------|------|------| +| 信息太多、没有秘密 | 视角太全知 | 限制主视角,用盲区藏秘密(一、)() | +| 批判读起来像说教 | 作者直接下判断 | 换外来者的碰壁与反应呈现(二、)() | +| 读者反馈"太直白""作者跳出来说话" | 看法入侵 | 看法替换为事实,加"肯定→否定"反转(三、)() | +| 读完就忘、没有回味 | 只有确定性没有张力 | 选方向 A/B,设锚点和屏障(四、)() | +| 读者困惑"发生了什么" | 只有不确定性没有线索 | 补确定性锚点:有线索但不确认(四、)() | +| 读者在插叙/独白尾迷路 | 折线没落回场景 | 500 字内回 SCENE,段尾补场景锚(五、)() | +| 主线太平、像流水账 | 缺意义层 | 长 SCENE 后加 1 段 altitude(五、)() | diff --git a/framework/catalog/pi/skills/narration-pov/references/outsider-entry.md b/framework/catalog/pi/skills/narration-pov/references/outsider-entry.md new file mode 100644 index 0000000..cd55599 --- /dev/null +++ b/framework/catalog/pi/skills/narration-pov/references/outsider-entry.md @@ -0,0 +1,130 @@ +# 外来者切入法:用一个外来者揭开封闭系统 + +> 来源单元:《我能否相信自己》(余华)wo-neng-fou-xiang-xin-zi-ji/outsider-perspective,出自《卡夫卡和K》(1999)。 + +## R 原文 + +> "那些在已有制度里出生并且成长起来的村民, 制度的一切不合理性恰恰构成了它的合理。面对这至高无上的权威, 村民以麻木的方式保持着他们世代相传的恐惧和世代相传的小心翼翼。而K的来到, 使其制度的不合理性得到了呈现。外来者K就像是一把熏肉切刀, 切入到城堡看起来严密其实漏洞百出的制度之中, 而且切出了很薄的片, 最后让它们一片片呈卷状飞了出去。" +> +> — 余华, 《卡夫卡和K》() + +## 方法核心:三个机制 + +揭示一个封闭系统(组织、社区、制度、文化)的荒谬或本质,最有效的方式不是作者直接批判,而是**让一个外来者进入这个系统**,通过他的不适应让系统的不合理性自行呈现。 + +1. **内部人的麻木**:在已有制度中出生成长的人,制度的一切不合理性恰恰构成了它的合理。他们习惯了,不觉得有问题。 +2. **外来者的不适应**:外来者因为不适应系统的规则,能看到内部人看不到的荒谬。他的困惑和碰壁本身就是对系统的批判。 +3. **自行呈现**:作者不需要解释"这个制度有多荒谬",只需要描写外来者的不适应,读者自然会感受到系统的问题。 + +卡夫卡《城堡》是最经典的例子:K 作为土地测量员来到村子,他试图进入城堡(权威),但整个官僚制度让他处处碰壁——电话接通后听到无数声音,村长翻箱倒柜找文件,克拉姆先生仿佛生活在传说中。K 的外来者身份让城堡制度的荒谬层层暴露。() + +## 书中案例 + +### 案例 1:卡夫卡《城堡》——K 进入村庄 + +- **问题**:如何描写一个荒诞而压迫的官僚制度,而不变成政治控诉? +- **方法论的使用**:卡夫卡让土地测量员 K 在厚厚的积雪中来到村庄,他的身份本身就是模糊的(城堡说没雇过土地测量员,但又似乎雇了)。K 试图接近城堡,但整个制度让他处处碰壁:电话接通后听到无数声音(因为所有电话同时接通),村长家翻箱倒柜找有关 K 的文件,克拉姆先生仿佛生活在传说中,村民对城堡权威的敬畏到了麻木的程度。 +- **结论**:K 的外来者身份让城堡制度的荒谬自行呈现——不需要作者解释,读者通过 K 的碰壁感受到制度的不合理。 +- **结果**:《城堡》成为官僚制度批判的巅峰之作。 + +### 案例 2:余华 1983 年第一次去北京 + +- **问题**:如何呈现不同城市文化的差异? +- **方法论的使用**:余华(浙江人)第一次去北京,问路时北京人用"向南走""向北走"指路,而他习惯了浙江人的"向左转""向右转"。一个外地人在北京根本不知道东南西北。"明明可以用一种确定的方式指引你, 但是你所遇到的指引总是具有不确定性。" +- **结论**:外来者的不适应(分不清东南西北)让北京的指路文化成为一个有趣的文化观察。 +- **结果**:成为余华谈"确定性与不确定性"的生活案例。 + +### 案例 3:远距荒诞外来者(布尔加科夫式) + +- **问题**:如何用外来者揭封闭系统,而不变成直接批判? +- **方法论的使用**:引入终极外来者(如魔鬼访问一座城市),让荒谬自行呈现;叙述距离与幽默结构见 `theme-and-stance` 的 [humor-as-stance.md](../../theme-and-stance/references/humor-as-stance.md)(撒旦访莫斯科全文案例 owner 在该文件,此处不重复)。 +- **结论**:外来者机制管"谁在看";荒诞幽默的距离与结构管"什么态度在讲"——两者配合,但案例正文只保留一份。 + +(以上三例均出自) + +## 执行步骤 + +1. **确定要揭示的封闭系统** + - 这个系统是什么?(公司/社区/制度/文化/家庭) + - 它的不合理性/独特性在哪里? + - 完成标准:明确要揭示的系统及其核心特征 + +2. **设计外来者角色** + - 外来者的背景:来自哪里?为什么进入这个系统? + - 外来者的特征:天真?固执?好奇?有目的? + - 外来者与系统的冲突点:他的什么习惯/价值观与系统冲突? + - 完成标准:有一个与系统有明确冲突的外来者角色 + +3. **让外来者经历系统的规则** + - 设计 3-5 个场景,让外来者在系统中碰壁或困惑 + - 每个场景展示系统的一个不合理/独特之处 + - 不要让作者解释,只描写外来者的反应和系统的反应 + - 完成标准:有足够的场景让系统的特征自行呈现 + +4. **利用内部人的麻木做对比** + - 描写内部人对系统不合理性的习以为常 + - 内部人可能觉得外来者"大惊小怪""不懂规矩" + - 这种对比本身就是批判 + - 完成标准:至少有一处内部人与外来者的反应对比 + +5. **让外来者逐步深入(或被拒绝)** + - 外来者可能逐渐理解系统(但仍保持批判距离) + - 也可能始终被拒绝(像 K 永远进不了城堡) + - 两种走向都有效,取决于故事主题 + - 完成标准:外来者与系统的关系有发展和结局 + +6. **检查是否说教** + - 通读全文,是否有作者直接跳出来批判系统? + - 如果有,替换为外来者的经历和反应 + - 完成标准:系统的问题全部通过外来者的视角呈现,没有作者直接说教 + +() + +## 触发场景 + +1. 想写一个组织/公司/社区的故事,揭示其内部文化或问题 +2. 写批判题材但不想显得说教 +3. 想写文化冲突/文化冲击的故事 +4. 设定了一个独特的世界观/制度,不知道如何向读者展示 +5. 写"鱼离开水"(fish out of water)类型的故事 +6. 想学习卡夫卡式的叙述方式 + +语言信号:"揭示制度荒谬""组织批判""外来者视角""陌生人进入""文化冲击""fish out of water""不想说教""怎么批判不生硬""世界观怎么展示""设定怎么呈现""卡夫卡式""局外人""outsider"。() + +## 边界:不要在以下情况使用 + +- **已经以内视角展开的故事**:如果故事已经从内部人的角度写,强行加入外来者可能破坏叙事。 +- **纯个人成长故事**:如果故事核心是个人情感成长,不需要揭示系统本质,外来者视角可能多余。 +- **需要内部人专业知识的场景**:如医疗/法律/科技题材,外来者可能不懂专业内容,无法有效揭示。 + +() + +## 作者在书中警告的失败模式 + +- **外来者变成导游**:如果外来者太顺利地适应了系统,他就不再是外来者,变成了系统的导游——失去了揭示荒谬的功能。 +- **作者借外来者之口说教**:外来者不应该直接说"这个制度真荒谬",他的不适应本身就是批判。直接说教会破坏效果。 + +() + +## 作者的盲点 / 时代局限 + +- 余华主要讨论极权/官僚制度下的外来者,没有讨论日常/普通组织(如公司、学校)中如何使用外来者视角。 +- "外来者让制度不合理性自行呈现"假设制度确实有不合理性,如果系统本身是合理的,外来者的不适应只是因为他不了解——需要区分"制度荒谬"和"外来者无知"。 + +() + +## 容易混淆的邻近方法论 + +- **"鱼离开水"(fish out of water)**:这是一种喜剧类型,主要目的是搞笑。本方法的目的是揭示系统本质,幽默可能是副产品但不是主要目的。 +- **"侦探视角"**:侦探进入一个封闭社区调查案件,也是外来者。但侦探的目的是解谜,本方法的外来者目的是揭示系统——可能没有案件,只是存在本身就是批判。 + +() + +## 与相邻方法的区分和配合 + +- 与怀疑叙述(skeptical-stance.md)的区别:外来者视角是通过外来者的眼睛呈现,怀疑叙述是通过怀疑的立场呈现。外来者天然带有怀疑(因为不适应),两者有重叠但角度不同,经常配合使用。() +- 与幽默作为结构(humor-as-structure)的区别:外来者视角是叙述视角技巧(用外来者揭示系统),幽默作为结构是叙述态度(用幽默处理沉重)。两者经常配合——外来者的不适应往往产生幽默效果。(humor-as-structure 归综合 skill theme-and-stance;) + +## 中文落地说明 + +方法本身无语言差异,中文写作直接可用。中文语境里"封闭系统"的现成素材很多:单位大院、宗族村落、机关科室、寄宿学校、行业圈子。落地时注意两点:一是中文读者对"制度批判"的直白表述敏感,本方法"只写反应、不做解释"的纪律恰好是最安全的写法;二是余华的案例(北京问路)说明外来者视角不一定用于揭露荒谬,也可以用于呈现文化差异的温和观察。(中文落地;方法本体) diff --git a/framework/catalog/pi/skills/narration-pov/references/pov-camera.md b/framework/catalog/pi/skills/narration-pov/references/pov-camera.md new file mode 100644 index 0000000..663b287 --- /dev/null +++ b/framework/catalog/pi/skills/narration-pov/references/pov-camera.md @@ -0,0 +1,93 @@ +# 视角是摄像头:谁在看,决定一切 + +> 来源单元:《小说课》(毕飞宇)bifeiyu-novel-skill/bifeiyu-perspective,第 2、3 章;分类:叙事·结构,难度:★★★★,主要元素:智商、直觉。案例素材:《杀手》视角转换 + 鲁迅《故乡》象征主义。 +> 视角限制的落地五步、触发场景、适用边界、常见错误见 [pov-execution.md](pov-execution.md)。 + +## 开篇原文 + +> 「人物的眼睛就是作家的眼睛。人物在'看',作家在'看',但作家不能比人物多'看'到任何东西。」() + +## 方法核心 + +**视角 = 小说里的"摄像头"。** + +- 谁在看 = 决定读者看到什么 +- 谁在看 = 决定读者看不到什么 +- 谁在看 = 决定"事实"的样貌 + +核心原则: + +1. **视角人物决定信息范围**——他看不到的,读者看不到。 +2. **视角人物的判断 = 隐形叙述**——他说"那个人可怕",读者就觉得可怕。 +3. **视角的转换 = 真相的揭示**——多个视角 = 多层真相。 + +() + +## R 原文:海明威《杀手》的障眼法 + +《杀手》开头,海明威写两个杀手进门,**通过顾客尼克的视角**: + +- 马克斯(第二人进门)被尼克看到 → **尼克忽略了阿尔**(第一人) +- **这是海明威的"障眼法"**——读者第一遍读也会忽略阿尔 + +**但是**,到中段,**通过服务员乔治的视角**: + +- 乔治送餐时先问阿尔 → **阿尔是更可怕的那个** +- **视角的转换让真相显露** + +() + +## 书中案例 + +### 案例 1(指针):海明威《杀手》(POV 轻重) + +> 对白白描角度见 `prose-craft` → [plain-description.md](../../prose-craft/references/plain-description.md)。本处只取 POV:尼克视角忽略阿尔,乔治视角让阿尔显形。 + +``` +视角 1:尼克(顾客) + → 看到马克斯,没看到阿尔 + → 读者跟着忽略阿尔 + +视角 2:乔治(服务员) + → 看到阿尔的可怕 + → 真相显露 +``` + +**视角的"重"和"轻"**——不同视角让人物重要度变化:尼克眼里马克斯重要,换到乔治的视角,阿尔才被重新称出分量。() + +### 案例 2:鲁迅《故乡》 + +- 第一人称"我"的视角 +- 视角的限制 = 思想的限制 +- "我" 看到的"故乡" = 中国的象征 + +**鲁迅的"象征主义"恰恰来自于视角的"克制"**——他不用全知视角,他只用"我"。() + +### 案例 3:奈保尔《布莱克·沃滋沃斯》 + +- 第一人称孩子视角 +- 孩子的天真 = 视角的局限 = 诗意的诞生 +- 孩子看芒果树 = 读者跟着看芒果树 = 爱情用"树"被表达 + +() + +### 案例 4:红楼梦可卿(宝玉/贾珍/凤姐三视角) + +- 多视角流动:宝玉看可卿 / 贾珍看可卿 / 凤姐看可卿 +- 不同视角下的"可卿" = 不同的形象 +- **可卿 = 多重视角的合集**——她的"死"才反逻辑 + +(;标题保留源单元原文,案例内容为宝玉/贾珍/凤姐三视角看可卿,王熙凤为三个视角人物之一;可卿之死"反逻辑"的那一面归 show-and-omission/references/anti-logic.md,此处只取多视角这一面) + +## 一句话总结 + +> **不是作家在看,是人物在看。人物看到什么决定一切。**() + +## 与相邻方法的区分和配合 + +- 视角人物在段落里说出、想到视角之外的信息(知识诅咒),逐句检查与修复归 show-and-omission/references/pov-knowledge-boundary.md;本文件管设定端——选谁看、看多少、怎么换。(跨 skill 一句话指针) +- 反逻辑经常通过"视角人物的盲点"实现;视角是"水面"和"水下"的控制器——这两条配合关系见 show-and-omission/references/anti-logic.md 与 iceberg.md。( 跨 skill 链接,落点归 show-and-omission) + +## 中文落地说明 + +本方法出自中文小说家的《小说课》,案例已含《故乡》《红楼梦》等中文作品,海明威、奈保尔两例为译作,方法本身无语言差异。中文写作要留意一个传统:古典小说"话说""且说"是说书人的全知腔,属于全知传统。作品一旦选了限制视角,就按本方法严格执行——视角人物看不到的,读者看不到;选了全知,则不必机械套用,但"全知 = 没秘密 = 没戏"的警告仍然成立。(中文落地;方法本体) diff --git a/framework/catalog/pi/skills/narration-pov/references/pov-execution.md b/framework/catalog/pi/skills/narration-pov/references/pov-execution.md new file mode 100644 index 0000000..b15de99 --- /dev/null +++ b/framework/catalog/pi/skills/narration-pov/references/pov-execution.md @@ -0,0 +1,119 @@ +# 视角限制的落地:五步执行 + +> 来源单元:《小说课》(毕飞宇)bifeiyu-novel-skill/bifeiyu-perspective,第 2、3 章。 +> 方法原则与案例全文见 [pov-camera.md](pov-camera.md)。 + +## 步骤 1:选"主视角" + +```yaml +主视角:[人物 A] + 他能看到的:[列具体内容] + 他看不到的:[列具体内容] + 他的判断标准:[他怎么看世界] +``` + +**主视角必须有限**——他不能看到一切。() + +## 步骤 2:视角人物"看"的方式 + +不是"他看到了什么"——是"他怎么看": + +``` +尼克看马克斯:这是威胁我的人 +乔治看阿尔:这是更可怕的人 +→ 同一个人(阿尔)→ 两种看法 → 视角决定意义 +``` + +**检验**:你的视角人物看世界时带着什么"滤镜"? + +- 恐惧(看到的都是威胁) +- 好奇(看到的都是机会) +- 厌倦(看到的都是无聊) + +() + +## 步骤 3:限制主视角的"知情范围" + +**主视角不知道的事**: +- 对方的真实想法 +- 对方的历史 +- 未来的发展 + +**主视角能知道的事**: +- 他能观察到的 +- 他能推断的 +- 别人告诉他的 + +**短篇的视角**:1-2 个主视角。 +**长篇的视角**:可以流动,但不能太频繁(每章换视角读者会累)。 + +() + +## 步骤 4:设计"视角的转换点" + +视角的**转换** = 真相的**揭示**。 + +``` +视角 A 看:表面 / 误导 / 一面 +视角 B 看:另一面 / 真相 / 立体 +``` + +**海明威的转换**: +- 视角 A(尼克)看:马克斯重要 +- 视角 B(乔治)看:阿尔更可怕 +- 转换的瞬间 = 读者的"啊原来如此" + +**检验**:你的小说里有没有这样的转换点?如果没有,读者读到的只有"单面真相"——那不够。() + +## 步骤 5:用视角藏"秘密" + +**秘密** = 主视角不知道,但读者可以猜到: + +```yaml +秘密:王熙凤和贾蓉的关系 +视角人物:秦可卿的婆婆(不知情) +读者:通过其他线索(飞白)能猜到 +→ 视角限制 = 戏剧张力 +``` + +**不要全知视角**——全知视角 = 没秘密 = 没戏。(;"飞白"手法本身见 show-and-omission/references/anti-logic.md) + +## 触发场景 + +1. 你的小说"信息太多" → 加视角限制 +2. 你的小说"看起来全知" → 限制一个视角 +3. 你的小说"该揭示真相"了 → 转换视角 +4. 你想写"复杂人物" → 多个视角看他 +5. 你想隐藏秘密 → 视角人物的"盲点"就是秘密 + +() + +## 适用边界 + +- **适合**:所有虚构叙事 +- **短篇推荐用**单一视角(清晰) +- **长篇可以用**多视角流动(复杂) +- **慎用**:第二人称(实验性,主流读者不易接受) + +() + +## 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 全知视角 | 没秘密 | 限制主视角 | +| 视角频繁转换 | 读者混乱 | 短篇 1-2 个,长篇每章 1 个 | +| 主视角太"通透" | 假 | 视角人物要有局限 | +| 视角转换无意义 | 浪费 | 每次转换都要"显示新东西" | +| 主视角没判断 | 假 | 视角人物的判断 = 隐形叙述 | + +() + +## 跨 skill 链接(综合 skill 归属对照) + +- 与反逻辑配合:反逻辑经常通过"视角人物的盲点"实现 → show-and-omission/references/anti-logic.md +- 与冰山同源:视角是"水面"和"水下"的控制器 → show-and-omission/references/iceberg.md +- 与人物关系配合:多视角下看同一对关系 = 立体关系 → character-presentation/references/relationship-web.md +- 与篇幅系统配合:短篇视角简,长篇视角可繁 → story-structure/references/length-system.md + +( 跨 skill 链接四条全量;落点为综合 skill 层归属) diff --git a/framework/catalog/pi/skills/narration-pov/references/skeptical-stance.md b/framework/catalog/pi/skills/narration-pov/references/skeptical-stance.md new file mode 100644 index 0000000..fea197c --- /dev/null +++ b/framework/catalog/pi/skills/narration-pov/references/skeptical-stance.md @@ -0,0 +1,139 @@ +# 怀疑主义叙述法:看法会陈旧,事实不会 + +> 来源单元:《我能否相信自己》(余华)wo-neng-fou-xiang-xin-zi-ji/skeptical-narration,出自《我能否相信自己》(1997)/ 博尔赫斯专题。 + +## R 原文 + +> "看法总是要陈旧过时, 而事实永远不会陈旧过时。" — 艾萨克·辛格的哥哥 +> +> "命运的看法比我们更准确。" — 古希腊人 +> +> "我喜欢怀疑不亚于肯定。" — 但丁 +> +> "按自己的能力来判断事物的正误是愚蠢的。" — 蒙田 +> +> — 余华, 《我能否相信自己》() + +## 方法核心 + +作家的叙述立场应是**怀疑主义**,而非急于给出看法(opinion)。核心洞察: + +- **看法总是陈旧过时**:任何人的看法都会被时间淘汰,权威的看法尤其容易成为笑料(IBM 董事长说五台计算机够全世界用)。 +- **事实永远不会陈旧**:事实比看法更持久,更有力量。 +- **怀疑优于肯定**:"我喜欢怀疑不亚于肯定"——怀疑让叙述保持开放,肯定让叙述封闭。 + +怀疑主义叙述的实践: + +1. **不给出确定答案**:博尔赫斯的叙述"总是假装地要确定下来了, 可是永远无法确定。读到肯定时接踵而来是否定。" +2. **只呈现事实, 不给出判断**:让读者在事实中自己得出结论,而非作者告知。 +3. **呈现更深层的真实**:不只是写"干渴",还要写"干渴后面更可怕的对干渴的恐惧"——怀疑让叙述抵达表层之下的真实。 + +写作会改变一个人:"作家长时期的写作, 会使自己变得越来越软弱、胆小和犹豫不决"——因为思维的训练将人推到深深的怀疑之中。这不是缺点,而是作家的必要品质。() + +**合并说明**:实践 1"不给出确定答案"与 [certainty-uncertainty.md](certainty-uncertainty.md) 的核心主张是同一条规则的两面——本文件管叙述立场(怀疑而非肯定),certainty-uncertainty.md 管叙述结构(确定性与不确定性的张力)。立场决定结构:怀疑主义立场自然产生不确定性的叙述结构。博尔赫斯案例两个文件都保留,角度不同:本文件取立场角度(怀疑、《沙之书》答案消失在无限中),certainty-uncertainty.md 取结构角度(在两极之间来回走动)。(合并标注; + certainty-uncertainty-tension) + +## 书中案例 + +### 案例 1:博尔赫斯——永远无法确定的叙述 + +- **问题**:如何让叙述有深度而不说教? +- **方法论的使用**:博尔赫斯的叙述充满怀疑——"总是假装地要确定下来了, 可是永远无法确定。我们耐心细致地阅读他的故事, 终于读到了期待已久的肯定时, 接踵而来的立刻是否定。"《沙之书》中一本无始无终的书,最后被藏在图书馆九十万册书中——答案消失在无限中。 +- **结论**:怀疑不是不给出答案,而是给出答案后立刻质疑它,让叙述保持开放。 +- **结果**:博尔赫斯成为"迷宫的创造者",读者找不到出口但乐在其中。 + +### 案例 2:蒙田——怀疑一切看法 + +- **问题**:如何避免被自己的看法局限? +- **方法论的使用**:蒙田说"按自己的能力来判断事物的正误是愚蠢的",因为"我们自己的看法常常充满矛盾? 多少昨天还是信条的东西, 今天却成了谎言?" 他选择怀疑主义立场,相信"任何一个命题的对面, 都存在着另外一个命题"。 +- **结论**:怀疑不是虚无,而是对"看法"的局限性的清醒认识。 +- **结果**:蒙田的随笔成为几百年后仍有生命力的经典,而他同时代人的"看法"早已过时。 + +### 案例 3:余华谈作家的看法——干渴与对干渴的恐惧 + +- **问题**:作家应该有什么样的"看法"? +- **方法论的使用**:余华引用博尔赫斯《永生》中的句子——"我一连好几天没有找到水, 毒辣的太阳、干渴和对干渴的恐惧使日子长得难以忍受。" 他指出这个句子令人赞叹,因为在"干渴"后面,博尔赫斯告诉我们还有更可怕的"对干渴的恐惧"。 +- **结论**:作家的看法不是给出答案,而是呈现比表层更深的真实——不只是干渴,还有对干渴的恐惧。 +- **结果**:这成为余华自己写作的追求——呈现事实而非看法,抵达更深层的真实。 + +(以上三例均出自) + +## 执行步骤 + +1. **识别"看法"入侵点** + - 检查文本中是否有作者直接给出的判断/评价/结论 + - 常见信号:"这说明…""由此可见…""真正的…是…""我们应该…" + - 完成标准:标出所有作者直接给出看法的地方 + +2. **将看法转化为事实** + - 把"他是个虚伪的人"转化为描写他的具体行为(说一套做一套的细节) + - 把"这个社会很冷漠"转化为描写具体的冷漠场景(路人无视摔倒的老人) + - 让事实自己说话,作者不做判断 + - 完成标准:所有看法都被替换为事实描写 + +3. **引入怀疑和反向思考** + - 对每个看似确定的结论,提出反面的可能性 + - 可以通过角色之口提出不同看法,或通过情节发展质疑初始判断 + - 博尔赫斯式:给出肯定后立刻用否定跟进 + - 完成标准:叙述中至少有一处"肯定→否定"的反转 + +4. **呈现更深层的真实** + - 不只是写表层现象(干渴),还要写表层之下的东西(对干渴的恐惧) + - 问自己:这个事实背后还有什么?这个情绪的底层是什么? + - 完成标准:至少有一处抵达"表层之下"的描写 + +5. **保留开放性** + - 结尾不给出确定答案,让读者自己思考 + - 可以用一个多义的细节/意象/对话收尾 + - 完成标准:结尾是开放的,读者读完会继续思考 + +() + +## 触发场景 + +1. 写社会/人性题材时,忍不住说教或给出简单答案 +2. 作品被反馈"太直白""作者跳出来说话了" +3. 想提升作品的思想深度和回味空间 +4. 写议论文/评论时想避免独断 +5. 不知道如何处理复杂的道德/伦理问题 +6. 想学习博尔赫斯/蒙田式的叙述方式 + +语言信号:"避免说教""不想说教""作品没深度""太直白了""作者跳出来说话了""复杂问题怎么写""道德困境""怀疑主义""博尔赫斯""不给简单答案""开放式思考"。() + +## 边界:不要在以下情况使用 + +- **需要明确立场的写作**:议论文、社论、评论需要明确的观点,不能用怀疑主义模糊立场。 +- **儿童文学**:需要明确的价值观引导,过度怀疑会让儿童困惑。 +- **纯娱乐性类型小说**:读者期待明确的善恶和结局,怀疑主义会破坏阅读快感。 + +() + +## 作者在书中警告的失败模式 + +- **权威的自负**:"权威往往是自负的开始, 就像得意使人忘形一样, 他们开始对未来发表看法了。"——作家不要以为自己的看法就是真理。 +- **怀疑变成虚无**:怀疑不是什么都不相信,而是对"看法"的局限性保持清醒。事实仍然是可靠的。 + +() + +## 作者的盲点 / 时代局限 + +- 余华主要从纯文学角度讨论怀疑主义,没有讨论在商业写作/类型小说中如何平衡"深度"和"读者满足感"。 +- "写作使人软弱、胆小和犹豫不决"是余华的个人经验,不是所有作家的必然结果。 + +() + +## 容易混淆的邻近方法论 + +- **"客观叙述"**:客观叙述是不偏不倚地呈现,本方法是主动引入怀疑和反向思考——不是中立,而是质疑。 +- **"反讽"**:反讽是说反话,本方法是真诚地怀疑——不是讽刺,而是认知上的开放。 + +() + +## 与相邻方法的区分和配合 + +- 与 [certainty-uncertainty.md](certainty-uncertainty.md) 的区别:本方法是叙述立场(怀疑而非肯定),certainty-uncertainty.md 是叙述结构(确定性与不确定性的张力)。立场决定结构——怀疑主义立场自然产生不确定性的叙述结构,两者经常配合。() +- 与"事实先于看法"(fact-over-opinion)的关系:源单元记录为 depends-on,且该方法点已在抽取阶段合并入 skeptical-narration 本单元——怀疑主义的基础是重视事实甚于看法,本文件"看法转化为事实"一节即其落点。( 相关 skill 记录全量) +- 与外来者视角(outsider-entry.md)的配合:外来者天然带有怀疑(因为不适应),用外来者揭示封闭系统时,本方法的"只呈现事实、不下判断"是其叙述纪律。(配合关系见) + +## 中文落地说明 + +方法本身无语言差异,中文写作直接可用,且执行步骤里的信号词("这说明""由此可见""真正的""我们应该")和改写例("他是个虚伪的人""这个社会很冷漠"/路人无视摔倒的老人)本来就是中文语境的原样。中文写作里"看法入侵"还有一个高发形态:借叙述腔讲大道理("这正是人性的悲哀""可见命运弄人"这类总结句),修订时可与信号词一并扫描。(中文落地;方法本体) diff --git a/framework/catalog/pi/skills/narrative-momentum/SKILL.md b/framework/catalog/pi/skills/narrative-momentum/SKILL.md new file mode 100644 index 0000000..ac4fb71 --- /dev/null +++ b/framework/catalog/pi/skills/narrative-momentum/SKILL.md @@ -0,0 +1,83 @@ +--- +name: narrative-momentum +description: | + 写或改长篇小说、网文连载、章节体故事遇到动力问题时激活:情节推不动、事件之间接不上、中段塌陷读者弃读、 + 章末平淡翻不下去、高潮不爆。三台发动机:给事件接因果推力链(造势)、沿途埋小奖励(金币)、 + 在断点挂未解问题(内悬念)。 + 关键 trigger:造势 / 势 / 推力 / 情节推不动 / 情节跳跃 / 高潮不爆 / 中段无力 / + 中段塌陷且读者弃读 / sagging middle / 读者弃读 / 金币 / 沿途埋金 / gold coin / + 章末钩子 / 段末悬念 / 卷末悬念 / internal cliffhanger / 内悬念 / 钩子 / 怎么让读者翻下去 / 付费点钩子。 + (裸「中段塌陷」无弃读/钩子语境时先查 story-structure) + 不适用于:抒情散文与诗(没有叙事路径和断点);意识流、反悬念的实验叙事(靠情绪流,不靠势与钩子); + 新闻报道(倒金字塔结构)。沿途埋金不适用于 1 万字以下短篇(没有中段可埋);造势与断点钩子对短篇仍适用 + (势链要短要密)。 + 与 story-structure 交接:中段塌陷若来自里程碑错位/赌注不升,先查 story-structure;本 Skill 只管读者动力(势/金币/钩子)。 +--- + +# 叙事动力(narrative-momentum) + +读者的动力有三个来源:事件内部不可逆的推力链(势)、沿途不断捡到的小奖励(金币)、每个断点上挂着的未解问题(钩子)。势解决"情节为什么必须往前走",金币解决"读者为什么愿意继续走",钩子解决"读者为什么不得不翻页"。 + +## 方法索引 + +按创作动作组织;方法细节、案例、原文引文都在 references/,不进本文件。 + +**情节推不动、事件接不上、高潮不爆 → 造势** + +- 把事件接成 A→必然B→必然C 的不可逆链条,有势的小说情节自己跑,作者拽不动 → references/build-momentum.md +- 势的起点必须是有具体动作的事件,不是心理 → references/build-momentum.md +- 链条每一环配齐处境、心理、动作三要素:只有处境则势弱,只有动作则势假 → references/build-momentum.md +- 势要递进不能平行(轻→中→重→爆发);高潮前累足势能、力度逐级递增 → references/build-momentum.md +- 写完做删环检验:删掉任何一环还成立,这一环就没用 → references/build-momentum.md + +**中段塌陷、读者弃读 → 沿途埋金** + +- 读者不是被"意义"驱动,是被"小奖励"驱动;在开头、中段、结尾前放 surprise / insight / beauty 三类金币 → references/midway-rewards.md +- 中段(30%-70%)是塌陷高危区:每 1 万字至少 1 枚小而具体、不必推进主线的金币,连续 3 万字无金立刻补 → references/midway-rewards.md +- 随时自问"这一段给读者的当下奖赏是什么",答不出来就是平地 → references/midway-rewards.md + +**章末平淡、翻不下去 → 断点内悬念** + +- 悬念是放置问题:在句末、段末、章末、卷末、全书末之前放一个未解决的小戏剧性元素 → references/breakpoint-hooks.md +- 钩子不必是生死悬崖,具体的好奇就够,且要从叙事内部自然生长 → references/breakpoint-hooks.md +- 强化疑问、弱化答案:最后一句是问题或动作中断,不是答案总结 → references/breakpoint-hooks.md + +**三台发动机的配合与相邻方法区分** + +- 金币给满足(推力),钩子造焦虑(拉力),节奏上先给金币、再抛内悬念 → references/alternation-and-distinctions.md +- 与伏笔(长期债务)、触发事件(全局赌注)、情节反转、朝终局写等的区分,以及三法适用范围对照 → references/alternation-and-distinctions.md + +## 脚本 + +- references/momentum-checklist.md —— 动力自查三关:势链删环检验、中段金币台账、断点悬念检查;写完初稿或改稿前使用。 + +## 引用索引 + +| 文件 | 覆盖内容 | +|---|---| +| references/build-momentum.md | 造势全量:势的定义与《促织》原文解读、四案例(《促织》/林冲/《项链》/沃滋沃斯)、可执行六步、适用边界与常见错误表、一句话总结、与其他方法的关系(跨 skill 链接四条,与 alternation-and-distinctions.md 重复落点) | +| references/midway-rewards.md | 沿途埋金全量:原文摘录、三时点机制与三类金币、莎剧第 3 幕与《Huck Finn》第 21 章案例、诊断三步(含判停条件)、失败模式、盲点与中文适配 | +| references/breakpoint-hooks.md | 内悬念全量:原文摘录、五时点断点与判断标准、电视剧插播与章末诊断案例、执行三步、失败模式、盲点与中文适配 | +| references/alternation-and-distinctions.md | 推拉交替节奏、三法对照、与伏笔/触发事件/朝终局写等相邻方法的区分(各书原话保留)、势的同源方法与跨 skill 链接、适用范围对照、跨域指针 | +| references/_coverage.md | 覆盖对照表(唯一追溯文件):源单元 → 落点小节 → 方法点,含逐点明细 | +| references/momentum-checklist.md | 可执行自查:势链检验七步、中段金币台账模板、断点悬念检查四步 | + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 红线 + +- 只给当前创作阶段的建议,不越权改设定主权、不绕过检测链、不复制粘贴其它 Skill 的 owner 定义。 +- 无用户明确授权不得替用户定稿或提交 Git。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/pi/skills/narrative-momentum/references/_coverage.md b/framework/catalog/pi/skills/narrative-momentum/references/_coverage.md new file mode 100644 index 0000000..a2bbcdb --- /dev/null +++ b/framework/catalog/pi/skills/narrative-momentum/references/_coverage.md @@ -0,0 +1,12 @@ +# narrative-momentum 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| bifeiyu-novel-skill/bifeiyu-momentum | references/build-momentum.md | +| bifeiyu-novel-skill/bifeiyu-momentum | references/alternation-and-distinctions.md | +| writing-tools-clark/gold-coins | references/midway-rewards.md | +| writing-tools-clark/gold-coins | references/alternation-and-distinctions.md | +| writing-tools-clark/internal-cliffhanger | references/breakpoint-hooks.md | +| writing-tools-clark/internal-cliffhanger | references/alternation-and-distinctions.md | diff --git a/framework/catalog/pi/skills/narrative-momentum/references/alternation-and-distinctions.md b/framework/catalog/pi/skills/narrative-momentum/references/alternation-and-distinctions.md new file mode 100644 index 0000000..3482bbc --- /dev/null +++ b/framework/catalog/pi/skills/narrative-momentum/references/alternation-and-distinctions.md @@ -0,0 +1,106 @@ +# 推拉交替与相邻方法区分 + +> 势、金币、钩子三法的推拉交替节奏、三法对照,以及与伏笔、触发事件、朝终局写等相邻方法的区分;同一方法点有多种表述的,均保留。 + +## 三台发动机:推力、推力、拉力 + +- **势**解决"情节为什么必须往前走":事件之间不可逆的推力,A 发生 → 必然 B → 必然 C。 +- **金币**解决"读者为什么愿意继续走":段中 / 段后给予**满足 / 惊喜**,是推力(来自已得到)。 +- **钩子**解决"读者为什么不得不翻页":段末 / 章末制造**焦虑 / 好奇**,是拉力(来自未满足)。 + +## 推拉交替:先给金币,再抛内悬念 + +同一条节奏规则有两种表述,均保留: + +- 表述一:"那个管'段末 / 章末制造**焦虑 / 好奇**(让读者不得不翻页)',是拉力(来自未满足);这个管'段中 / 段后给予**满足 / 惊喜**(让读者愿意再走一段)',是推力(来自已得到)。一个制造问题,一个给奖赏。" +- 表述二:"那个是'沿途给读者奖励'(满足),这个是'在末尾制造悬念'(焦虑)。两者在节奏上交替使用:**先给金币,再抛内悬念**。"另一处表述:"那个是'给予满足'(读者读下去的动力 = 奖励),这个是'制造焦虑'(读者读下去的动力 = 解答)。两者是节奏上的'推-拉'交替。" + +组合关系: + +- 与沿途埋金:推-拉交替。 +- 与镜头距离:镜头距离末端的钩子(今属 scene-craft 场景执行)。 +- 与句子节奏:句末的 micro-cliffhanger(今属 prose-craft 语言修辞)。 +- 与故事引擎:引擎是整体拉力,金币是局部推力(今属 concept-design 概念与前提)。 +- 与朝终局写:结局是终点,金币是沿途的灯(今属 story-ending 结尾设计)。 +- 与折线叙事:折线可作为"金币"的容器(今属 narration-pov 叙述与视角)。 + +## 三法对照 + +| 方法 | 动力来源 | 作用位置 | 兑现时点 | +|---|---|---|---| +| 势 | 事件间不可逆的推力 | 整条因果链(处境/心理/动作三环相扣) | 每一步都是下一步的必要条件,环环即兑 | +| 金币 | surprise / insight / beauty 小奖励 | 段中 / 段后,重点是中段(30%-70%) | 当下即兑,"读者捡到一颗金的高兴瞬间" | +| 钩子 | 未解决的小问题 | 断点前:句末、段末、章末、卷末、全书末 | 短期兑现:1 章内或 1 段内 | + +## 与相邻方法的区分 + +同一区分多书出现的合并一条,各书原话都保留。 + +### 金币 vs 伏笔 + +《写作工具》:"那个管'埋下**未来要兑现的承诺**'——是债务;这个管'埋下**当下就回报读者的小奖赏**'——是礼物。契诃夫之枪是'种下树',沿途埋金是'种下花让读者现在就闻到香'。" + +### 钩子 vs 伏笔 + +《写作工具》:"那个是'埋伏笔'(长期债务),这个是'放钩子'(短期未答)。伏笔是 10 章后兑现,内悬念是 1 章内或 1 段内兑现。" + +三层合起来:金币是当下就兑现的礼物;钩子是 1 章或 1 段内兑现的短期未答问题;伏笔是 10 章后才兑现的长期债务。三者不要混用。 + +### 金币 vs 触发事件 + +《写作工具》:"那个管'启动故事的那一击'(大爆炸,在开头 5%-15%),是赌注;这个管'沿途持续给读者小奖励',是糖。触发事件只来一次,金币要埋 3-5 次。" + +### 钩子 vs 触发事件 + +《写作工具》两处表述: + +- "那个是'启动故事的大事件'(全局赌注),这个是'局部断点的钩子'(具体好奇)。" +- "那个是'启动故事的全局事件',这个是'维持叙事的局部钩子'。一个是开关,一个是节拍器。" + +### 金币 vs 朝终局写 + +《写作工具》:"那个管'朝终局写'的全局方向感(结局已知);这个管'中段持续给奖赏'的局部节奏。倒推向结局是'在终点放灯塔',沿途埋金是'在路上放小灯笼'。" + +### 钩子 vs 镜头距离 + +《写作工具》:"那个是'摄影机距离'在叙事中的调度,这个是'断点前的张力放置'。" + +### 金币 vs 情节反转(plot twist) + +《写作工具》:"那个管'主线的反转',是事件;这个管'中段的小奖赏',是阅读体验。曲折是 plot 层,金币是 pacing 层。" + +### 金币 vs 展示不说教 + +《写作工具》:"那个管'用具体场景替代抽象断言',是微观手法;这个管'在中段放具体的小奖赏',是宏观节奏。一枚金币可以是展示不说教的产物,但'用具体场景'不等于'埋金币'——后者必须在'读者当下能感受到奖赏'的时点。" + +### 金币 vs 细节马赛克 + +《写作工具》:"那个管'用具体物拼出人物',是人物构造;这个管'在中段用小而具体的奖赏',是结构节奏。两者都用'具体',但用途不同——一个是拼人物,一个是奖赏读者。" + +## 势的同源方法(跨 skill 链接) + +- 与莎士比亚化同源:势 = 逻辑推演的速度感(今在 theme-and-stance 主题与立场)。 +- 与铺垫术关联:铺垫 = 给势铺路(今在 foreshadow-payoff 伏笔与回收)。 +- 与反常即戏关联:反常是势的转折点(今在 character-presentation 人物呈现)。 +- 与短中长篇三种体制配合:短篇势要密要短,长篇势可慢可散(今在 story-structure 故事结构)。 + +## 适用范围对照 + +| 方法 | 适合 | 不适用 / 慎用 | +|---|---|---| +| 势 | 所有叙事;短篇特别需要,链条要短但要密 | 慎用:意识流、纯抒情(靠"情绪流"不靠"势") | +| 金币 | 长篇小说(10 万字以上)、网络小说长篇连载、报告文学长篇、非虚构长篇、系列故事 | 短篇小说(<1 万字)、散文 / 抒情随笔、新闻报道 / 通讯、诗 / 短诗 | +| 钩子 | 长篇 / 网络小说 / 章节结尾 / 段末钩子 / 卷末悬念 | 短抒情诗 / 散文、实验文学 / 反叙事、学术论文 / 说明文、刻意反悬念的开放式叙述 | + +## 跨域指针(各一句话) + +- foreshadow-payoff:契诃夫之枪管伏笔的登记与兑现(长期债务);铺垫术管铺垫给势铺路。 +- story-structure:触发事件管启动故事的那一击(全局赌注);短中长篇三种体制管短篇势密、长篇势散。 +- story-ending:朝终局写管结局已知的全局方向感。 +- concept-design:故事引擎管故事整体的拉力。 +- narration-pov:折线叙事可作金币的容器。 +- scene-craft:镜头距离管摄影机距离在叙事中的调度。 +- prose-craft:句子节奏可承载句末的 micro-cliffhanger。 +- show-and-omission:展示不说教管用具体场景替代抽象断言。 +- character-presentation:细节马赛克管用具体物拼出人物;反常即戏管反常作为势的转折点。 +- theme-and-stance:莎士比亚化与势同源(逻辑推演的速度感)。 diff --git a/framework/catalog/pi/skills/narrative-momentum/references/breakpoint-hooks.md b/framework/catalog/pi/skills/narrative-momentum/references/breakpoint-hooks.md new file mode 100644 index 0000000..da7777b --- /dev/null +++ b/framework/catalog/pi/skills/narrative-momentum/references/breakpoint-hooks.md @@ -0,0 +1,105 @@ +# 内悬念:在断点挂上未解问题 + +> 本文件全量来自《Writing Tools: 55 Essential Strategies for Every Writer》(Roy Peter Clark,中文通译《写作工具》),原书 Tool 30 · To generate suspense, use internal cliffhangers。 +> 适用:长篇 / 网络小说 / 章节结尾 / 段末钩子 / 卷末悬念。 + +## 原文摘录 + +> We don't think of the cliffhanger as an internal device. We associate it with serialized film or +> television adventures with big endings. ... Any dramatic element that comes right before a break in +> the action is an internal cliffhanger. +> +> — Roy Peter Clark, *Writing Tools* (Tool 30) + +## 方法骨架 + +Clark 把"悬念"重新框架为**一个放置问题**——不是"发生了什么大事",而是"在哪里放"。 + +传统 cliffhanger = 电视连续剧的"to be continued",大生死、大爆炸,显得套路。 +**Internal cliffhanger(内悬念)** = 在**任何叙事断点**(句末、段末、章末、卷末)前**放一个未解决的小戏剧性元素**。 + +判断标准:读者此刻有一个"想知道答案"的小问题吗?如果有,强化它;如果没有,加一个。 + +关键洞见: + +- 不必是"悬崖"——可以是"他看起来什么样?"(好奇) +- 不必是"to be continued"——可以从叙事内部自然生长 +- 5 个时点:句末、段末、章末、卷末、全书末 +- 核心机制:在断点前抛"问题未答",让读者"被迫"翻下去 + +这是**节奏放置框架**——决定"在哪里制造张力"。 + +## 案例全文 + +### 案例 1:Clark 引用电视剧商业插播前的钩子 + +- **问题**:商业插播前 5 秒,如何让观众不换台? +- **方法论的使用**:电视剧编剧在每个广告前放一个"未解决的小戏剧性元素"——不是"她会死吗"(太套路),而是"他的信会怎么写?"(具体好奇)。 +- **结论**:网文章末钩子、长篇卷末悬念、段末 micro-cliffhanger 都可以借鉴此机制。 +- **结果**:成为了"内悬念 vs 外悬念"的金标准对照——内悬念是从叙事内生出的钩子,不是编剧强行加的。 + +### 案例 2:长篇小说"X 章节末尾"诊断 + +- **问题**:写完一章后,如何判断章末是否有效? +- **方法论的使用**:Clark 给出诊断——读章末最后一句,问"读者此刻有未解决的疑问吗?"如果有,这一章的结尾是有效的;如果没有,加一个。 +- **结论**:章末钩子不必"大事件",可以是"她看到桌上那封信的署名是 X"(引发好奇)。 +- **结果**:成为了长篇小说节奏管理的工具——网文作者可以每章做此诊断。 + +## 何时使用(触发场景) + +### 用户会在什么情境下需要这个方法 + +1. 写完一章后觉得"章末平淡",读者翻过去就忘了。 +2. 写网文章节需要"付费点钩子",但不想用"to be continued"套路。 +3. 写到段末不知道怎么收——"该用句号还是省略号?" +4. 长篇中段节奏失速,需要"卷末悬念"维持读者追读。 +5. 短篇需要一个"最后一句"——想给读者留个问号。 + +### 语言信号(用户的话里出现这些就应激活) + +- "内悬念" / "internal cliffhanger" +- "章末钩子" / "章末平淡" +- "段末悬念" / "段末怎么收" +- "hook" / "钩子" +- "读者翻下去" / "让读者继续读" +- "付费点钩子" +- "章节结尾怎么写" +- "卷末悬念" + +## 可执行步骤 + +1. **诊断当前断点** + - 找出章节末 / 段末 / 卷末等所有"叙事断点"。 + - 完成标准:列出所有断点位置。 + - 判停条件:若该断点是"短抒情 / 散文 / 实验文学",跳过此方法。 + +2. **检验"未解决的疑问"** + - 对每个断点,问"读者此刻有未解决的小问题吗?" + - 完成标准:每个断点都有 1 个明确的"疑问"(可以是"他看到什么?" / "她接下来怎么做?" / "X 是什么?")。 + - 判停条件:若无疑问,加一个;若有疑问但"读者不在意",调整疑问的具体性。 + +3. **强化疑问,弱化答案** + - 检查断点前一段:是否"问题抛得够具体" + "答案没给"。 + - 完成标准:最后一句 / 最后一段是"问题"或"动作中断",不是"答案总结"。 + +## 边界:不要用在此处 + +- **短抒情诗 / 散文**——抒情节奏不靠悬念推进,反而靠"留白"。 +- **实验文学 / 反叙事**——故意打破阅读期待的项目不需要"钩子"。 +- **学术论文 / 说明文**——信息传递不需要制造悬念。 +- **刻意反悬念的开放式叙述**——开放式结局 = 反向操作,不是"用错"。 + +## 失败模式(作者在书中警告) + +- **"to be continued"套路化**:失败模式是依赖"大事件中断"(她跳下悬崖)而非"内生小好奇"。信号:所有章末都是"生死未卜"或"反派出现"。机制:读者对大事件脱敏,内悬念失效。预警:章末读起来像"电视剧宣传片"。 +- **钩子过密**:失败模式是每段都抛疑问。信号:读者疲劳,问号太多反而麻木。机制:人脑对"问题未答"有承受上限,过密反而抑制翻页欲。预警:每 500 字一个钩子,密度过高。 +- **疑问但读者不关心**:失败模式是"X 的鞋带是什么颜色"这种与人物/情节无关的细节。信号:读者跳过疑问不回头。机制:读者只关心"主角命运"和"主题进展",无关细节无法制造悬念。 + +## 盲点与时代局限(含中文适配) + +- 【中文适配】Clark 写于 2006 年(英文版),电视剧模型主要指美国 22 集周播剧。中文网文"日更 1 万字"+"付费章节"的钩子模式需要单独讨论——核心是"问题未答",但密度可更高。 +- 【中文适配】短视频 / 直播时代,读者的注意力曲线更短,内悬念的"时点"需要更密集(网文可以每 200-500 字一个 micro-hook)。 + +## 相邻方法区分指针 + +内悬念与金币、伏笔、触发事件、镜头距离的区分,以及金币-钩子的推拉交替,见 references/alternation-and-distinctions.md。 diff --git a/framework/catalog/pi/skills/narrative-momentum/references/build-momentum.md b/framework/catalog/pi/skills/narrative-momentum/references/build-momentum.md new file mode 100644 index 0000000..1eab269 --- /dev/null +++ b/framework/catalog/pi/skills/narrative-momentum/references/build-momentum.md @@ -0,0 +1,197 @@ +# 造势:给小说内部装上"发动机" + +> 本文件全量来自《小说课》(毕飞宇)。原书第 7 讲,核心文本为蒲松龄《促织》。 + +## 原文摘录 + +毕飞宇讲"势"字: + +> 「什么叫'势'?'势'的本意是什么?你们学过汉语,看看这个字的组合就知道了,是我们男人的两只'丸'子。没了这两个'丸'子,你就坐怀不乱了,事情到此为止……但小说的内部是没有这两只'丸子'的,一切要靠作家去给予,这就叫'造势'。」 + +蒲松龄写《促织》,在斗蛐蛐之前,写了一句看似闲笔的话: + +> "将献公堂,惴惴恐不当意,思试之斗以觇之。"(《促织》) + +毕飞宇解读: + +> "这一句话是**左腿**,迈出去了,斗蛐蛐就是**右腿**。你不迈出去是不行的。" + +- **没有这一句**:斗蛐蛐就突兀、不自然。 +- **有这一句**:斗蛐蛐是必然——成名必须先试一试。 + +**这就是"势"**:小说内部有一股推力,把情节向前推。 + +## 方法骨架:势 = 小说内部的推力 + +**势 = 小说内部的推力。** + +- **没有势的小说**:作者拽着情节走,每一段都靠作者安排。 +- **有势的小说**:情节自己跑,作者都"说不上话"。 + +**"势"的本质**:**事件之间有不可逆的推力**。A 发生 → 必然 B → 必然 C。 + +## 案例全文 + +### 案例 1:蒲松龄《促织》"思试之斗以觇之" + +``` +将献公堂(要交差) → 惴惴恐不当意(怕不合要求) → 思试之斗以觇之(先试试看) +``` + +**三步造势**: + +- 处境(要交) +- 心理(怕不合) +- 行动(先试) + +→ 斗蛐蛐是必然的 + +### 案例 2:施耐庵 林冲的"步步紧逼" + +``` +高俅陷害(误入白虎堂) → 刺配沧州道 → 路上被欺 → 草料场 → 风雪 → 石头靠门 → 听到阴谋 → 杀人 +``` + +每一步都是下一步的"势"——**没有一步是多余的,也没有一步是突变的**。 + +### 案例 3:莫泊桑《项链》"项链丢失" + +``` +舞会出风头(势) → 回家路上丢失(势) → 借的钱不够赔(势) → 必须买真的还(势) → 10 年艰辛(势) +``` + +**每个环节都在加势**——读者无法停下。 + +### 案例 4:奈保尔 沃滋沃斯的"五个反常" + +``` +反常 1:等待(势) → 反常 2:请吃芒果(势) → 反常 3:讲故事(势) → 反常 4:临死前透露(势) +``` + +**反常累加 = 势累加**——读者无法不读下去。 + +## 何时使用(触发场景) + +1. 你的情节"读不下去" → 检查势 +2. 你的情节"该推进了但推不动" → 造势 +3. 你的情节"突然跳到下一段" → 缺势 +4. 你的高潮"不够高潮" → 高潮前没累足势 +5. 你的结尾"突然结尾" → 结尾的势没到位 + +## 可执行步骤 + +### 步骤 1:识别"势的起点" + +势从**事件 A** 开始——这是势的源头: + +```yaml +势的起点:将献公堂 +势的推力:惴惴恐不当意 +势的结果:思试之斗以觇之 → 斗蛐蛐 +``` + +**关键**:势的起点必须是**有具体动作的事件**,不是心理。 + +### 步骤 2:设计"势的链条" + +**A → B → C → D**,每个都是下一步的"必要条件": + +``` +A:处境(要交) +B:心理(怕不合要求) +C:行动(先试) +D:结果(斗蛐蛐) +``` + +**检验**: + +- 删 A,B 还能发生吗?→ 不能,A 是必要 +- 删 B,C 还能发生吗?→ 不能,B 是必要 +- 删 C,D 还能发生吗?→ 不能,C 是必要 + +**全是必要** → 势到位 + +### 步骤 3:势的"三要素" + +每个势的环节要包含: + +```yaml +处境:人物此时面对什么? +心理:人物此时怎么想? +动作:人物此时做什么? +``` + +**只有处境** = 势弱(读者无感) +**只有动作** = 势假(读者不信) +**三要素齐** = 势足 + +### 步骤 4:势的"递进" + +势不能"平行"——必须**递进**: + +``` +平行的势: + A → B → C → D(每个力度一样) + +递进的势: + A(轻)→ B(中)→ C(重)→ D(爆发) +``` + +**林冲的势**:误入白虎堂(中等)→ 刺配(中等)→ 路上被欺(中等)→ 草料场(升级)→ 听到阴谋(爆发) + +**前三个是"中势"——蓄力**;最后是"大爆发"。 + +### 步骤 5:检验"删掉一个还成立" + +写完所有势的环节后: + +> "删掉中间任何一环,故事还成立吗?" + +- 删掉 A 还成立 → A 没用,删 +- 删掉 A 不成立 → A 是必要,留 +- **全删都不成立** → 势到位 + +### 步骤 6:高潮的"势能" + +高潮必须**前期累足势**。 + +**检验**: + +> "高潮前我有多少个'势'在累?" +> "每个'势'的力度递增了吗?" +> "高潮瞬间的'势'是否最大?" + +蒲松龄的斗蛐蛐:3 步势 + 多次险情 + 鸡来袭 = 高潮势足 + +## 边界与常见错误 + +### 适用边界 + +- **适合**:所有叙事 +- **短篇特别需要**:短篇篇幅短,势的链条要短但要密 +- **慎用**:意识流、纯抒情(它们靠"情绪流"不靠"势") + +### 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 势的链条断 | 情节跳跃 | 检查"删 A 还成立吗" | +| 势不递进 | 高潮不爆 | 加大高潮前的势 | +| 势太多太散 | 节奏乱 | 选 1-2 个主势 | +| 势靠巧合 | 假 | 势要靠"性格 + 现实"驱动 | +| 势变成啰唆 | 累 | 简洁是势的灵魂 | + +## 一句话总结 + +> **没有势的小说靠作者拽着走;有势的小说情节自己跑——找到那个"必然的下一步"。** + +## 与其他方法的关系 + +跨 skill 链接(各一句话指针): + +- 与莎士比亚化同源:势 = 逻辑推演的速度感(今在 theme-and-stance 主题与立场)。 +- 与铺垫术关联:铺垫 = 给势铺路(今在 foreshadow-payoff 伏笔与回收)。 +- 与反常即戏关联:反常是势的转折点(今在 character-presentation 人物呈现)。 +- 与短中长篇三种体制配合:短篇势要密要短,长篇势可慢可散(今在 story-structure 故事结构)。 + +势与金币、钩子三台发动机的推拉配合、与伏笔等相邻方法的区分,见 references/alternation-and-distinctions.md。 diff --git a/framework/catalog/pi/skills/narrative-momentum/references/midway-rewards.md b/framework/catalog/pi/skills/narrative-momentum/references/midway-rewards.md new file mode 100644 index 0000000..0cc6608 --- /dev/null +++ b/framework/catalog/pi/skills/narrative-momentum/references/midway-rewards.md @@ -0,0 +1,114 @@ +# 沿途埋金:让读者在中段不弃读 + +> 本文件全量来自《Writing Tools: 55 Essential Strategies for Every Writer》(Roy Peter Clark,中文通译《写作工具》),原书 Tool 32 · Place gold coins along the path。 +> 适用:长篇小说(10 万字以上)、网络小说长篇连载、报告文学长篇、非虚构长篇、系列故事。 + +## 原文摘录 + +> Imagine you are walking on a narrow path through a deep forest. You stroll a mile, and there at +> your feet you find a gold coin. You pick it up and put it in your pocket. You walk another mile, and, +> sure enough, you see another gold coin. What will you do next? You walk another mile in search of +> another coin, of course. … The easiest thing for a reader to do, argued famed editor Barney Kilgore, +> "is to quit reading." With no gold coins for motivation, the reader may drift out of the forest. +> +> — Roy Peter Clark, *Writing Tools* (Tool 32) + +## 方法骨架 + +Clark(借 Don Fry / Barney Kilgore 的比喻)的核心洞察:**读者不是被"意义"驱动的,是被"小奖励"驱动的。** + +长篇最容易塌陷的不是开头(有 hook)和结尾(有 payoff),而是**中段**——读者热情降温、人物命运已知、情节推进乏力。在这三段"林中窄路"上,作者必须**沿途撒下金币**——surprise(惊奇)、insight(洞见)、beauty(美感)三类小奖赏,让读者每走一段就"捡到一次"。 + +Clark 给出三时点的金币机制: + +- **开头(Opening)**:Hook 不够 = 读者不进森林;开头第一枚金币 = "为什么我要走这条路"。 +- **中段(Middle)**:这是 10 万字长篇的"塌陷高危区",**必须**埋 3-5 枚"小而具体"的金币——逸事、惊人事实、机智引语、出彩金句、突然的小戏剧性时刻;**不必是 plot twist**(那是伏笔、内悬念的事),而是"读者捡到一颗金的高兴瞬间"。 +- **结尾前(Pre-Climax)**:读者已猜到结局、动力最低,需要"再次加码的金币"——重新加赌注(up the ante)、给一个意外视角、出乎意料的小场景。 + +判断标准:作者应自问"这一段给读者的**当下奖赏**是什么"。没奖赏,就是平地——读者会走出森林。 + +## 案例全文 + +### 案例 1:Shakespeare 悲剧第 3 幕的"巨大金币" + +- **问题**:5 幕悲剧从开场到结局,中段(第 3 幕)是"读者最易弃读"的——观众已经知道"主角要死",动力最低。 +- **方法论的使用**:Clark 指出 Shakespeare 在第 3 幕设计"巨大的金币"——往往是关键独白 / 突然的转折 / 戏剧性高峰(如哈姆雷特的"生存还是毁灭"、麦克白的"明日明日明日"、李尔王的暴风雨独白)。这枚金币**不是结局**(那是第 5 幕),但足以让观众"再走两英里"。 +- **结论**:伟大悲剧的"中段"不靠情节推进,而靠"读者当下能捡到的金"——这些金是**戏剧性的、感官的、可被记忆的**瞬间。 +- **结果**:Clark 用此例证明"中段奖励"不是通俗小说的专利;5 幕悲剧若无第 3 幕的"独白金币",观众会真的离场。 + +### 案例 2:Mark Twain《Huck Finn》第 21 章——拙劣莎剧演员的中段转折 + +- **问题**:42 章的长河小说,在第 21 章(地理意义的中段)如何"奖励读者"? +- **方法论的使用**:Clark 引用 Huck Finn 第 21 章——两个骗子上岸演"莎剧桥段"(the royal family on a barge),演得"拙劣到滑稽"。这不是主线剧情,但**它给读者一颗金**:一节出人意料的喜剧、一个人物间的"小对白"、一个让读者"噗"一下的瞬间。 +- **结论**:中段金币**不必推进主线**——它是给读者的"读到这里的小礼物",一个让阅读继续的理由。 +- **结果**:成为了 Clark 评价"中段不需推进剧情、只需给奖赏"的金案例;展示"逸事 / 喜剧场景 / 风格化的偏离"都是合法的金币类型。 + +## 何时使用(触发场景) + +### 用户会在什么情境下需要这个方法 + +1. 写长篇 10 万字以上,自觉"中段(30%-70%)部分读者弃读率最高"——自我诊断是中段塌陷。 +2. 网文连载写到中段,数据(收藏掉、追读降)显示"读者开始走"。 +3. 写完 5 万字发现"中段全是情节推进,没有任何'停下来的一刻'"——通读像坐长途火车,没景色。 +4. 编辑反馈"中段没高潮"——作者分不清"高潮"和"小奖励"。 +5. 问"为什么别人长篇中段我也读了 / 我的中段就乏味"——要可操作的中段设计。 + +### 语言信号(用户的话里出现这些就应激活) + +- "中段塌陷" +- "中段无力" +- "中段没动力" +- "读者弃读" +- "读者怎么不弃读" +- "写到一半没人看了" +- "sagging middle" +- "mid-novel reward" +- "沿途埋金" +- "gold coin" +- "中段没高潮" +- "故事中段奖励" +- "长篇中段怎么写" + +## 可执行步骤 + +1. **诊断中段塌陷区** + - 找出长篇的"中段"——按字数 = 30%-70% 区间,按章节数 = 中间 1/3。 + - 列出中段每章/每 1 万字的"金币清单"——每章 / 每万字有 1 个 surprise / insight / beauty 吗?没有 = 塌陷。 + - 完成标准:中段每 1 万字至少 1 枚"可被读者当下就捡到"的金币;**金币类型** = surprise(惊奇)/ insight(洞见)/ beauty(美感)三类之一;**金币特征** = 小而具体,不必推进主线。 + - 判停条件:若中段已每 1 万字有 1 枚金,无需再加;若 3 万字连续无金,立刻停下来补。 + +2. **为三时点各设 1 枚"定位金"** + - 开头(0%-10%):第一枚金 = 让读者知道"为什么我要走这条路"——hook + 第一笔奖赏。 + - 中段(30%-70%):至少 3 枚 = 逸事、惊人事实、机智引语、出彩金句、突然的小戏剧性时刻(任选类型)。 + - 结尾前(80%-95%):最后一枚 = "再走一段"的奖赏——重新加赌注、出乎意料的小场景、让读者"没想到"的瞬间。 + - 完成标准:三时点各 1 枚"定位金"已识别,中段 3 枚已就位;不与已有伏笔、触发事件、内悬念重复(它们是"承诺 / 启动 / 焦虑",这里是"奖励")。 + +3. **对每枚金币做"surprise / insight / beauty"分类** + - **surprise(惊奇)**:读者没料到的事实 / 场景 / 引用 / 巧合。 + - **insight(洞见)**:对人物 / 主题 / 世界的"我从未这样想过"的一句话。 + - **beauty(美感)**:一个意象 / 一句话 / 一段描写让读者停下来说"写得真好"。 + - 完成标准:每枚金币被标注类型;中段三类至少各占 1 枚(类型多样化防"全是 surprise"或"全是 beauty")。 + - 判停条件:若一类金币 3+ 次重复(如连续 3 章都是"美句"),改用其他类型,避免读者审美疲劳。 + +## 边界:不要用在此处 + +- **短篇小说(<1 万字)**——中段本身很短(几页),无独立"沿路"可埋;若硬埋会让短篇变松散。 +- **散文 / 抒情随笔**——散文中段是"递进式思考",不是"叙事路径",埋金反而打断沉思节奏。 +- **新闻报道 / 通讯**——报道是"倒金字塔",开头给全部信息,无"中段路径"可言。 +- **诗 / 短诗**——无中段结构。 + +## 失败模式(作者在书中警告) + +- **"中段没金币 = 弃读"**:失败模式是中段没有 surprise / insight / beauty 的小高潮,读者觉得"没东西可捡"而停止前进。Clark 称之为"long, flat, middle, as if the whole thing had been emptied out"。信号:中段连续 3+ 章无"读者会抄下来 / 告诉朋友"的瞬间;朋友的弃读点都在 30%-70%。 +- **"开头没金币 = 不进场"**:Hook 不够强 = 读者不进森林;但 hook 不等于"第一枚金"——hook 是"我看到地上有东西",第一枚金是"我捡起来放进口袋"——两者都要有。 +- **"结尾前没金币 = 烂尾"**:结尾前读者已猜到结局、动力最低,无金 = 草草收场;Clark 把它和"中段塌陷"列为"读者弃读三时点"。 + +## 盲点与时代局限(含中文适配) + +- **Kilgore 是新闻业比喻**:Barney Kilgore 是《华尔街日报》前主编,他的"沿途埋金"是**新闻业**的术语(让读者在长报道中持续得到奖赏)。Clark 把这个比喻迁移到小说,需要**注明**——小说中的"金"不必是"事实"(新闻的奖励),也可以是"人物 / 意象 / 金句"等更文学性的奖励。 +- 【中文适配】**时代局限**:Clark 的英文原版"金"偏指"small scene, anecdote, quote, surprising fact"——偏新闻/非虚构的"事实性奖励"。迁移到中文小说时,需要扩展:**人物的小顿悟、对话中一句出彩台词、意象的一次妙用、风格化的一段偏离**——这些是中文小说更常见的"金"。 +- 【中文适配】**网文 / 连载的特殊性**:Clark 写于 2006 年,网文连载还未成为主流;中文网文有"日更 5000 字"的压力,作者更容易"写完中段没时间埋金"——此方法对网文作者尤其重要,但需要本地化为"每 1 万字自检一次"。 + +## 相邻方法区分指针 + +金币与伏笔、触发事件、内悬念、朝终局写、情节反转(plot twist)、展示不说教、细节马赛克的区分,以及三台发动机的推拉交替,见 references/alternation-and-distinctions.md。 diff --git a/framework/catalog/pi/skills/narrative-momentum/references/momentum-checklist.md b/framework/catalog/pi/skills/narrative-momentum/references/momentum-checklist.md new file mode 100644 index 0000000..a6d4c4c --- /dev/null +++ b/framework/catalog/pi/skills/narrative-momentum/references/momentum-checklist.md @@ -0,0 +1,64 @@ +# 叙事动力自查清单 + +> 由造势、沿途埋金、内悬念三个方法的可执行步骤重排而成。写完初稿或改稿前按关依次过;方法细节与案例原文见 references/ 对应文件。 + +## 第一关:势链检验(情节推不动、跳跃、高潮不爆时) + +对应造势方法(references/build-momentum.md)。 + +1. **找势的起点**:势从事件 A 开始。它是不是**有具体动作的事件**(不是心理)? + - 台账示例——势的起点:将献公堂;势的推力:惴惴恐不当意;势的结果:思试之斗以觇之 → 斗蛐蛐。 +2. **写成链条**:A → B → C → D,每一环都是下一环的必要条件。 +3. **逐环配三要素**:处境(人物面对什么)/ 心理(人物怎么想)/ 动作(人物做什么)。 + - 只有处境 = 势弱(读者无感);只有动作 = 势假(读者不信);三要素齐 = 势足。 +4. **删环检验**:"删掉中间任何一环,故事还成立吗?" + - 删 A 还成立 → A 没用,删;删 A 不成立 → A 是必要,留;全删都不成立 → 势到位。 +5. **递进检查**:势是平行(每环力度一样)还是递进(轻 → 中 → 重 → 爆发)?平行的要改成递进。 +6. **高潮势能三问**:"高潮前我有多少个'势'在累?""每个'势'的力度递增了吗?""高潮瞬间的'势'是否最大?" +7. **错误速查**:链条断(情节跳跃,去查"删 A 还成立吗")/ 不递进(高潮不爆,加大高潮前的势)/ 太多太散(节奏乱,选 1-2 个主势)/ 靠巧合(假,改成"性格 + 现实"驱动)/ 啰唆(累,简洁是势的灵魂)。 + +## 第二关:中段金币台账(长篇 10 万字以上 / 网文连载) + +对应沿途埋金方法(references/midway-rewards.md)。短篇(<1 万字)、散文、新闻报道、诗跳过本关。 + +1. **圈出中段**:按字数 30%-70% 区间,按章节数中间 1/3。 +2. **填台账**(按每 1 万字切段): + +| 段落区间 | 金币内容(逸事 / 惊人事实 / 机智引语 / 出彩金句 / 突然的小戏剧性时刻) | 类型(surprise / insight / beauty) | 读者的当下奖赏 | +|---|---|---|---| +| 30%-40% | | | | +| 40%-50% | | | | +| 50%-60% | | | | +| 60%-70% | | | | + +3. **判停条件**: + - 中段每 1 万字至少 1 枚"读者当下就能捡到"的金币;已每万字 1 枚则无需再加。 + - **连续 3 万字无金,立刻停下来补。** + - 中段三类(surprise / insight / beauty)至少各占 1 枚;同一类型连续重复 3+ 次就换类型,防审美疲劳。 +4. **三时点定位金核对**: + - 开头(0%-10%):第一枚金让读者知道"为什么我要走这条路"。注意 hook ≠ 金币:hook 是"我看到地上有东西",第一枚金是"我捡起来放进口袋",两者都要有。 + - 中段(30%-70%):至少 3 枚已就位。 + - 结尾前(80%-95%):读者已猜到结局、动力最低,最后一枚"再走一段"的奖赏(重新加赌注 / 意外视角 / 出乎意料的小场景)已就位。 + - 金币不与已有伏笔、触发事件、内悬念重复——它们是承诺 / 启动 / 焦虑,金币是奖励。 +5. **当下奖赏自问**:写稿中随时问"这一段给读者的当下奖赏是什么?"答不出来 = 平地。 +6. 【中文适配】中文网文按"每 1 万字自检一次"执行;中文小说的"金"优先从人物小顿悟、对话出彩台词、意象妙用、风格化偏离里找,不必限于事实性奖励。 + +## 第三关:断点悬念检查(章节体 / 连载) + +对应内悬念方法(references/breakpoint-hooks.md)。短抒情诗 / 散文、实验文学 / 反叙事、学术论文 / 说明文、刻意反悬念的开放式叙述跳过本关。 + +1. **列出断点**:句末、段末、章末、卷末、全书末——所有叙事断点的位置。 +2. **逐个检验疑问**:读每个断点的最后一句,问"读者此刻有未解决的小问题吗?" + - 有 → 断点有效,强化它。 + - 无 → 加一个。疑问必须具体,且挂钩主角命运或主题进展("他看到什么?" / "她接下来怎么做?" / "X 是什么?");"X 的鞋带是什么颜色"这类无关细节造不成悬念。 +3. **强化疑问,弱化答案**:断点前一段是否"问题抛得够具体 + 答案没给"?最后一句 / 最后一段必须是"问题"或"动作中断",不是"答案总结"。 +4. **密度与套路速查**: + - 章末全是"生死未卜""反派出现"?→ to be continued 套路化,读者已对大事件脱敏,改用叙事内生长的小好奇("他的信会怎么写?")。 + - 每 500 字一个钩子?→ 过密,超过"问题未答"的承受上限,反而抑制翻页欲。 + - 【中文适配】网文付费章节 / 日更场景密度可更高,可每 200-500 字一个 micro-hook,但仍以读者注意力上限为界。 + +## 三关之后的整体自问 + +- 势(事件推力)、金币(当下奖赏)、钩子(未解问题)是否都就位? +- 节奏是否推拉交替——先给金币,再抛内悬念——而不是一路只拉或一路只奖? +- 势、金币、钩子是否与伏笔(长期债务)、触发事件(全局赌注)区分开,没有互相冒充? diff --git a/framework/catalog/pi/skills/novel-diagnosis/SKILL.md b/framework/catalog/pi/skills/novel-diagnosis/SKILL.md new file mode 100644 index 0000000..7703f8b --- /dev/null +++ b/framework/catalog/pi/skills/novel-diagnosis/SKILL.md @@ -0,0 +1,115 @@ +--- +name: novel-diagnosis +description: | + 激活场景:用户手里有一部写完或在写的小说,感觉不对劲但说不清哪里不对——"我的小说有什么问题"、 + "它缺什么"、"为什么被拒稿"、"虎头蛇尾/高开低走"、"中段疲软"、"人物写扁了"、"全是流水账没有峰值"、 + "读者很兴奋但没理解"、"收尾太硬"、"形式大于内容";或要把自己的作品和参照作品比差距;或交付诊断/ + 评论/书评结论前需要扫描一遍有没有空话。 + 关键 trigger:"诊断作品 / 小说体检 / 我的小说有什么问题 / 缺什么 / 为什么被拒 / 虎头蛇尾 / + 高开低走 / 中段疲软 / 流水账 / 写扁了 / 故事还是情节 / 后来呢 / 为什么 / 有时间没价值 / + 情节和人物谁赢 / 模式还是节奏 / 幻想还是预言 / 六便士 / 难懂 / 奇书 / 六核 / 七侧面 / + 圆桌 / 伪学者 / 怎么系统地看一部小说"。 + 不适用于:请求写作技法而非找毛病;非虚构;纯新闻速报/菜谱等时间流即内容的对象;作者习惯/心理培养问题。 + 症状已落到具体环节时不要停在本 Skill,按下表交接:结构/里程碑→story-structure;弃读/钩子→narrative-momentum; + 建角变量→character-design;登场呈现→character-presentation;对话声音→dialogue-craft;场景执行→scene-craft; + 标签画面→show-and-omission;句段修辞→prose-craft;POV 机制→narration-pov;主题/荒诞幽默→theme-and-stance; + 埋收债→foreshadow-payoff;idea/引擎→concept-design;节拍工作流→story-planning;收尾姿态→story-ending; + AI 味→diagnose-ai-flavor(须先诊断)。 +--- + +# novel-diagnosis 作品诊断 + +对一部小说做整体体检:先把问题落进维度,再用五个透镜查具体病灶,最后清理诊断结论防止空话。 + +## 方法索引 + +按诊断动作组织;方法细节、案例、引文都在 references 里,这里只给一句话和指针。 + +### 第一步 · 把问题落进维度 + +- 写作能力 = 4 元素(概念/人物/主题/结构)+ 2 技能(场景执行/写作声音)共六桶,任何问题都能落桶,任何一桶不及格整本就失败 → references/dimension-frameworks.md +- 小说复杂到无法定义,放弃定义改为看七侧面(故事/人物/情节/幻想/预言/模式/节奏),每个侧面配一种读者素质 → references/dimension-frameworks.md +- 好坏 = 维度间的动态平衡:先定位哪个维度不及格,再说清它向哪个方向失衡 → references/dimension-frameworks.md + +### 第二步 · 五个透镜查病灶 + +- 结构层:标出最近 5 个提问是"后来呢"还是"为什么",判断停在故事层还是进了情节层 → references/story-plot.md +- 意义层:查时间堆积还是价值峰值——找不到读者事后仍会回想的瞬间就是消磨 → references/time-value.md +- 张力层:看守尾处人物是否消失/死亡/沦为工具,判定情节与人物谁赢、代价多大 → references/plot-character.md +- 形式层:问全书能否用一个几何形象概括(模式)、有没有携带变化的重复元素(节奏) → references/pattern-rhythm.md +- 神异层:走六便士测试,判幻想面(戏耍)还是预言面(歌唱),再按中文志怪/神魔/仙侠谱系看接受姿态 → references/fantasy-prophecy.md + +### 第三步 · 比较诊断(有参照作品时) + +- 圆桌论:抹掉年代/流派标签,把自己的稿子和参照作品匿名并置,只比"做了什么"不比"何时写的" → references/round-table.md + +### 第四步 · 清理诊断结论 + +- 伪学者自检:扫描五大症状(没读完就分类、天才崇拜、便携词、挂生平背景、漂亮代替准确)+ 自检三问 + 最小可替换段落 → references/quack-scholar.md + +### 冲突标注 + +- Brooks 主张六桶穷尽一切写作元素;福斯特主张七侧面只是"我感兴趣的方向"、可伸缩。两条立场都保留:用六桶查盲区,用七侧面给特殊作品增补侧面,详见 references/dimension-frameworks.md。 + +## 症状→专精 Skill 路由 + +整体体检后若症状已落到具体环节,**交接给专精 Skill**,本 Skill 不再展开改稿技法。 + +| 症状 / 用户说法 | 优先 Skill | 说明 | +|---|---|---| +| 结构松散、中段塌陷、里程碑错位、赌注不升 | `story-structure` | 四箱/六里程碑/Setup-FPP 成因 | +| 章末平淡、弃读、势链断、缺钩子 | `narrative-momentum` | 势/金币/内悬念;结构成因仍可能需 `story-structure` | +| 人物扁、工具人、没弧、撞型 | `character-design` | 变量/弧线/原型 | +| 登场像形容词清单、关系网、反常瞬间 | `character-presentation` | 呈现给读者看 | +| 对话一个声音、太书面、不推动情节 | `dialogue-craft` | 说话方式 owner | +| 场景薄、使命不清、进出点弱 | `scene-craft` | 场景执行 | +| 太抽象、标签堆情绪、缺画面 | `show-and-omission` | 标签→场景;句段修辞另见 `prose-craft` | +| 句长单调、修辞密度、风格漂移 | `prose-craft` | 句段层修辞 | +| 视角穿帮、POV 切换、外来者切入机制 | `narration-pov` | 视角与叙述模式;荒诞幽默全文案例归 `theme-and-stance` | +| 主题说教、手软、沉重题材幽默/荒诞距离 | `theme-and-stance` | 主题演示与作家立场 | +| 伏笔没收、契诃夫之枪、铺垫突兀 | `foreshadow-payoff` | 仅限埋/收链,不含泛化高潮课 | +| idea 不够、引擎不清、写到一半散 | `concept-design` | 概念层 | +| 节拍表、灵感 vs 计划工作流 | `story-planning` | 概念已定后的规划流程 | +| 烂尾、拖尾、结尾姿态、开放/闭合收束 | `story-ending` | 终局倒推与收尾策略 | +| AI 味、检测链、规则注入 | `diagnose-ai-flavor` / `prevent-ai-flavor` | 须先诊断再改,见写作槽位铁律 | + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|---------| +| references/dimension-frameworks.md | 六核六桶(4 元素 + 2 技能)与七侧面框架合并、动态平衡判断、维度定位执行流程、作者自传 5 部小说与拒稿比例案例、贝内特 vs 托尔斯泰与《使节》案例、失败模式与盲点、穷尽 vs 可伸缩冲突标注、中文落地 | +| references/story-plot.md | 故事问"后来呢"情节问"为什么"、情节三条件、故事/情节合作、提问切换诊断与执行步骤、司各特《古董商人》/梅瑞狄斯《利己主义者》/贝内特 vs 托尔斯泰案例、失败模式与边界、章回小说中文落地 | +| references/time-value.md | 时间生活 vs 价值生活、双重忠诚、时间轴/价值轴征兆、执行步骤、贝内特《老妇人的故事》/托尔斯泰《战争与和平》/山鲁佐德案例、失败模式与边界、中文网文中文落地 | +| references/plot-character.md | 情节-人物拉锯元模型、三种解决(哈代式/梅瑞狄斯式/反情节式)、虎头蛇尾诊断、执行步骤与代价对策、哈代《无名的裘德》/梅瑞狄斯/纪德《伪币制造者》案例、失败模式与边界、章法中文落地 | +| references/pattern-rhythm.md | 模式 vs 节奏二分、节奏检验公式、模式的代价、节奏的失败、执行步骤、法朗士《泰伊丝》/普鲁斯特小乐句/《使节》案例、失败模式与边界、章回回目章法中文适配 | +| references/fantasy-prophecy.md | 幻想/预言孪生光柱、六便士测试、双向判断、执行步骤、《项狄传》/《白鲸记》/阿斯奎斯案例、失败模式与边界、中文志怪/神魔/仙侠转述与适用边界 | +| references/round-table.md | 圆桌论匿名并置、两两盲文对比、信念前提与代价、执行步骤、伍尔夫 vs 斯泰恩/威尔斯 vs 狄更斯/哈代 vs 司各特案例、失败模式与边界、跨朝代比较中文落地 | +| references/quack-scholar.md | 伪学者五大症状、自检三问、最小可替换段落、执行步骤、加洛韦天气分类/天才崇拜/司各特"会讲故事"案例、失败模式与边界、翻译腔/公文腔/空泛赞美词中文落地 | +| references/_coverage.md | 九个源单元的覆盖对照表 | + +## 脚本 + +| 脚本 | 用途 | +|------|------| +| references/diagnosis-workflow.md | 三步体检台账:维度定位 → 五个透镜查病灶 → 评审纪律清理结论,附征兆速查表,一份填完出诊断 | +| references/quack-scholar-scan.md | 伪学者自检扫描表:五大症状 0/1 扫描 + 自检三问 + 最小可替换段落 + 漂亮词改写 | + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 红线 + +- 只给当前创作阶段的建议,不越权改设定主权、不绕过检测链、不复制粘贴其它 Skill 的 owner 定义。 +- 无用户明确授权不得替用户定稿或提交 Git。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/pi/skills/novel-diagnosis/references/_coverage.md b/framework/catalog/pi/skills/novel-diagnosis/references/_coverage.md new file mode 100644 index 0000000..7cc5cde --- /dev/null +++ b/framework/catalog/pi/skills/novel-diagnosis/references/_coverage.md @@ -0,0 +1,27 @@ +# novel-diagnosis 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| aspects-of-the-novel/fantasy-prophecy-twin | references/fantasy-prophecy.md | +| aspects-of-the-novel/fantasy-prophecy-twin | references/round-table.md | +| aspects-of-the-novel/pattern-vs-rhythm | references/pattern-rhythm.md | +| aspects-of-the-novel/pattern-vs-rhythm | references/dimension-frameworks.md | +| aspects-of-the-novel/plot-character-tug | references/plot-character.md | +| aspects-of-the-novel/plot-character-tug | references/story-plot.md | +| aspects-of-the-novel/plot-character-tug | references/round-table.md | +| aspects-of-the-novel/quack-scholar-check | references/quack-scholar.md | +| aspects-of-the-novel/round-table | references/round-table.md | +| aspects-of-the-novel/round-table | references/fantasy-prophecy.md | +| aspects-of-the-novel/round-table | references/plot-character.md | +| aspects-of-the-novel/seven-aspects | references/dimension-frameworks.md | +| aspects-of-the-novel/seven-aspects | references/time-value.md | +| aspects-of-the-novel/seven-aspects | references/story-plot.md | +| aspects-of-the-novel/seven-aspects | references/pattern-rhythm.md | +| aspects-of-the-novel/story-vs-plot | references/story-plot.md | +| aspects-of-the-novel/story-vs-plot | references/plot-character.md | +| aspects-of-the-novel/time-vs-value-life | references/time-value.md | +| aspects-of-the-novel/time-vs-value-life | references/dimension-frameworks.md | +| aspects-of-the-novel/time-vs-value-life | references/story-plot.md | +| story-engineering/six-core-competencies | references/dimension-frameworks.md | diff --git a/framework/catalog/pi/skills/novel-diagnosis/references/diagnosis-workflow.md b/framework/catalog/pi/skills/novel-diagnosis/references/diagnosis-workflow.md new file mode 100644 index 0000000..fa2dcd9 --- /dev/null +++ b/framework/catalog/pi/skills/novel-diagnosis/references/diagnosis-workflow.md @@ -0,0 +1,115 @@ +# 作品诊断三步体检台账 + +用法:对一部完成或在写的小说做整体体检时从第 0 节顺着填。三段执行:**维度定位 → 五个透镜查病灶 → 评审纪律清理结论**。每节标注判断标准和落点,方法细节与案例见对应 references 文件。填完第 4 节的每条诊断必须配一个改得下去的动作,填完第 5 节才算完成。 + +--- + +## 0. 症状陈述 + +用用户自己的话写症状(不定性、先不归类): + +> ____ + +是整体"感觉不对但说不清",还是已有具体怀疑部位?____ + +## 1. 维度定位(→ references/dimension-frameworks.md) + +先不给结论,把症状逐条对照维度框架,判定问题落在哪个或哪几个维度。 + +六核之桶勾选(): + +| 桶 | 症状像不像落在这里 | 备注 | +|---|---|---| +| Concept 概念 | □ | | +| Character 人物 | □ | | +| Theme 主题 | □ | | +| Structure 结构 | □ | | +| Scene Execution 场景执行 | □ | | +| Writing Voice 写作声音 | □ | | + +七侧面失衡判断():哪个侧面过强、哪个过弱? + +> ____ 侧面过强,表现为 ____;____ 侧面过弱,表现为 ____。 + +判断标准:维度是诊断镜,不是评分表——不给维度打 1-10 分,不把维度拆成独立任务清单。 + +## 2. 五个透镜查病灶 + +对第 1 节怀疑的维度,逐个透镜过一遍。每个透镜都有判停条件,不适用就跳过。 + +### 透镜 1 · 结构层:是故事还是情节(→ references/story-plot.md) + +- 标出最近 5 个关键事件引发的提问,是"后来呢"还是"为什么": + 1. ____(后来呢 / 为什么) + 2. ____(后来呢 / 为什么) + 3. ____(后来呢 / 为什么) + 4. ____(后来呢 / 为什么) + 5. ____(后来呢 / 为什么) +- 判定:全是"后来呢" → 停在故事层;至少 2 个"为什么" → 进入情节层。判定:____ +- 故事层健康吗(读者想不想继续听)?失败征兆:走神、中途弃书、"读了两百页啥也没记住"。答:____ +- 情节层健康吗(至少 2 个"为什么"被揭示、至少 1 处悬念 = 时序断裂 + 重新整合)?答:____ + +### 透镜 2 · 意义层:有时间,有没有价值(→ references/time-value.md) + +- 时间轴症状("我花了 X 时间"、"熬过了 X 分钟"、"流水线/流水账")有没有?列 1 条:____ +- 在全书里找价值峰值(读者读完仍会回想的瞬间):找到几个?分别是?____ +- 判定:找不到任何价值峰值 = 时间堆积(消磨)。时间轴过强 / 价值轴过弱 / 平衡:____ + +### 透镜 3 · 张力层:情节和人物谁赢(→ references/plot-character.md) + +- 看守尾处:人物是否消失、死亡或沦为工具?标出至少 1 处"逻辑压倒自由"或"自由压倒逻辑"的征兆:____ +- 拉锯哪方胜出?胜出代价多大?____ +- 选择解决方式(哈代式人物牺牲 / 梅瑞狄斯式情节胜出但节制 / 反情节取消主线):____,理由("因为本作是 [类型/规模/目的],所以……"):____ +- 对策:对哈代式加 1 个圆形人物;对梅瑞狄斯式加 1 个"言犹未尽"桥段;对反情节加 1 个主线暗示。选定:____ + +### 透镜 4 · 形式层:模式还是节奏(→ references/pattern-rhythm.md) + +- 全书能否用一个几何形象/章法概括(沙漏/大循环/大教堂放射线/对偶回目章法)?是 → 模式型,形象:____;否 → ____ +- 有没有携带变化的重复元素(乐句/主题/意象,如小乐句、重现的意象)?有 → 节奏型,元素:____ +- 判停:两者皆无 → 形式感弱,走其它分析。 +- 模式型:模式阉割了什么(人物类型/情节/幻想预言)?被阉割的是不是最重要的部分?____ +- 节奏型:重复每次是否带来新意?(否则节奏死了,像高尔斯华绥的西班牙猎犬约翰)____ + +### 透镜 5 · 神异层:幻想与预言(→ references/fantasy-prophecy.md) + +- 先查适用边界:规则化类型奇幻(体系化修仙仙侠、系统流、无限流)自带接受规则,不需六便士测试;无神异的自然主义题材不用本透镜。适用吗?____ +- 有没有光柱(横贯一切、自己决定生长方向的东西)?标出至少 1 处:____ +- 走六便士测试:作品要求读者额外接受什么("接受混乱"/"接受死亡在文本外的延续"/"接受动物有灵魂"……)?____ +- 是幻想面(戏谑玩闹、随手即兴)还是预言面(语调"歌唱"的庄严之作)?____ +- 按中文志怪/神魔/仙侠谱系看接受姿态:神怪是否通人情?门槛在意愿还是能力?____ +- 双向判断:作品召唤是否合理(是)+ 读者选择不响应是否合理(是),双方都无错。____ + +## 3. 把失衡写成因果(→ references/dimension-frameworks.md) + +每条诊断写成"X 维度过强/过弱,导致 Y",不说"形式太霸道"这类空话: + +1. ____ 维度过强/过弱,导致 ____。 +2. ____。 + +## 4. 给出具体修改动作 + +每条诊断配至少一个改得下去的动作(落到段落、人物、元素): + +| 诊断 | 修改动作 | +|---|---| +| | 例:加一个圆形人物打破扁平 / 加一段倒叙揭示因果、调动读者头脑 / 插入一个价值峰值(一个让读者愣住的细节)/ 用一个携带变化的重复元素黏合散落事件 / 放宽闭环,给人物一次违背情节的举动 | + +判断标准:动作落到段落、人物、元素;"加强情节""提升深度"不算动作。 + +## 5. 清理诊断结论(评审纪律) + +- 伪学者自检:把诊断交给 references/quack-scholar-scan.md 扫一遍,重点查"最小可替换段落"(把作品名换成另一部,段落若仍成立就是空话,必须重写)。 +- 圆桌复查(仅比较类结论):抹掉年代、流派、思潮标签再看判断是否改变、为什么改变(→ references/round-table.md)。 +- 谦虚声明:在结论末尾加"以上诊断基于对作品的有限阅读,可能有盲点"。 + +## 征兆速查表 + +| 征兆 | 病灶 | +|------|------| +| 读者走神、中途弃书、读完啥也没记住 | 故事层失败:事件流不抓人() | +| 句子漂亮但没逻辑,想不起因果 | 情节层失败:因果网没建立() | +| 只记得"读了两百页",没有可回想的瞬间 | 时间堆积,无价值峰值() | +| 收尾处人物消失、死亡或沦为工具 | 情节压倒人物,拉锯未处理() | +| 重复元素只重现不发展,沦为标语 | 节奏死亡,僵化成符号() | +| 人物清单短,神异维度进不来 | 模式过强,闭环阉割人性内容() | +| 诊断里全是"有灵气/是 X 流派/反映了 X 倾向" | 伪学者式空话,须重写() | diff --git a/framework/catalog/pi/skills/novel-diagnosis/references/dimension-frameworks.md b/framework/catalog/pi/skills/novel-diagnosis/references/dimension-frameworks.md new file mode 100644 index 0000000..3faef1c --- /dev/null +++ b/framework/catalog/pi/skills/novel-diagnosis/references/dimension-frameworks.md @@ -0,0 +1,171 @@ +# 维度框架:先把问题落进维度,再谈别的 + +来源:; + +两家都是"整体维度框架":不急着看具体段落,先把"写作能力"切成若干个诊断维度,让作者能说出"我缺的是哪一块"。Brooks 的六核是穷尽分桶,福斯特的七侧面是并列视角,合并成一套定位工具:六核管"问题属于哪种能力",七侧面管"作品在哪些侧面之间失衡"。 + +## 原文摘录 + +> "There is no element, no aspect of the storytelling process, that doesn't belong in one of the six buckets. Genre is a subset of concept. Setting is a subset of scene execution. Backstory is a subset of character. Subplot is a subset of structure, and unfolds in context to concept. And so on." +> +> — Larry Brooks, *Story Engineering* (2011), Part 1 + +() + +> "我之所以选择它, 是因为这个论题实在有些含糊, 无法以科学方式加以精确剖析, 而它刚好可以为我们保留最大限度的自由, 因为它意味着, 不但我们能以不同的方式来看待同一部小说, 小说作者也能以不同的方式来看待他自己的作品。有鉴于此, 我一共挑选出了七个侧面来加以探讨: 故事、人物、情节、幻想、预言、模式与节奏。" +> +> — E. M. 福斯特, 《小说面面观》第一讲 绪论 + +() + +## 方法规则 + +### A. 六核分桶:4 元素 + 2 技能 + +Larry Brooks 把"写作能力"切成 6 个互不重叠的桶,让作者精确定位"我缺什么"。6 个桶 = 4 元素 + 2 技能:() + +**4 个基本元素(elemental)——故事是"什么":** + +1. **Concept(核心前提/概念)**——故事的 what if? 种子 +2. **Character(角色)**——故事由谁经历 +3. **Theme(主题)**——故事对现实照亮什么 +4. **Structure(结构)**——故事如何按时间排列 + +**2 个执行技能(execution-driven)——故事怎么"被写出来":** + +5. **Scene Execution(场景执行)**——故事被切成场景后的单元技巧 +6. **Writing Voice(写作声音)**——文字的节奏、语调、风格 + +关键洞察:() + +- 这不是"6 种技巧",是"6 个互不重叠的全分类"——任何写作相关元素都能落到一个桶,否则就是写作盲区。 +- 4 元素是"故事要包含什么",2 技能是"故事如何被执行"。 +- 缺一不可,任何一桶不及格 = 整个故事失败。 +- 这是一个**诊断工具**——你不知道故事哪里出问题,问"这属于 6 桶的哪一桶"就能定位。 + +### B. 七侧面姿态:放弃定义,改为识别侧面 + +面对一个无法被"定义"的复杂对象(小说、艺术形式、品牌、研究领域、生活形态),放弃给它一个本质定义,改为识别它可被"侧面地"分析的若干维度。() + +核心操作: + +1. **承认"无法定义"是常态**——复杂对象太软、太杂、太没有一定之规,强行定义只会扭曲它。 +2. **改为列 N 个侧面(aspect)**——选 5-10 个可独立讨论的维度,每个侧面都是对象"被看到的合法方式"。 +3. **每个侧面要求一种读者/操作者素质**——故事的"好奇心"、情节的"头脑与记忆力"、幻想的"额外付 6 便士"——这种"侧面 + 素质"配对让抽象维度变得可诊断。 +4. **判断好坏**——优秀作品不是"满足所有侧面",而是在这 N 个侧面之间**获得动态平衡**;拙劣作品是某一侧面过强(模式阉割人性)或过弱(只剩时间堆叠)。 +5. **允许侧面之间的"光柱"(如幻想/预言)**——某些侧面不是并列的,而是**横贯**其他侧面的更高阶维度(详见 references/fantasy-prophecy.md)。 + +关键认识:七侧面的"七"不是本体论,是方法论选择。读者完全可以列出五侧面、十侧面,但必须满足"每个侧面有独立素质要求"这一硬条件,否则就是伪分类。() + +### C. 合并后的诊断姿态(两书合并点) + +- **先定位维度,再查病灶**:两家框架都不是评分表,是定位镜。不知道作品哪里出问题时,把症状逐条对照六核之桶与七侧面,判定问题落在哪个或哪几个维度。(;) +- **好坏 = 维度间的动态平衡**:Brooks 说任何一桶不及格整本就失败;福斯特说好作品是侧面之间的动态平衡,拙劣作品是某侧面过强或过弱。两家判法合用:先用六核找到不及格的桶,再用七侧面说清这个桶是怎么失衡的(哪个侧面向哪个方向倒)。(;) +- **维度数目可伸缩,但每个维度必须有独立判断标准**:六桶或七侧面可按作品伸缩,两个维度共用一个判断标准就合并。( 的"七非本体论"立场; 的"互不重叠全分类"立场) + +**冲突标注(都保留)**:Brooks 主张六桶是穷尽全分类——"故事写作过程中没有任何元素不属于这六个桶之一";福斯特明确否认完备性——七个侧面是"我感兴趣的方向",不是"小说的全部"。两条立场都保留:做诊断时用 Brooks 的"一切都能落桶"排查有没有漏掉的盲区,用福斯特的"侧面可伸缩"给特殊作品(章回体、散文体小说、类型文)临时增补侧面。不要把六桶当封闭清单去否定新维度。 + +### 判断标准 + +- 任何一桶不及格 = 整个故事失败() +- 优秀 = 侧面之间动态平衡;拙劣 = 某一侧面过强(模式阉割人性)或过弱(只剩时间堆叠)() +- 维度是诊断镜,不是评分表:不给维度打 1-10 分,不把维度拆成独立任务清单( 作者明示的失败模式) +- 每个侧面要有独立的素质要求/判断标准,否则是伪分类() + +## 操作步骤(维度定位的执行流程) + +合并两家的 E 段步骤( 四步; 五步): + +1. **承认对象复杂、无法一句话定义** + - 完成标准:明确说出"这部作品的问题太杂,强行一句话定性会扭曲它,先分维度看"作为开场。() +2. **介绍维度框架** + - 完成标准:用户能用一句话说"故事写作有 6 大能力 = 4 元素 + 2 技能",并知道小说另有七侧面可看。不要照搬英文,翻译成用户语言;用食物/建筑等类比帮助记忆。() +3. **对具体问题做归类** + - 完成标准:用户的问题/故事被归到 6 桶中的某一桶或多桶。问用户:"你的问题最像下面哪个?"然后给出 6 桶的简短解释。() +4. **识别侧面并为侧面配素质** + - 完成标准:列出至少 5 个独立侧面,每个侧面有"该侧面看到什么,隐藏什么"的说明;至少 3 个侧面配对成功(说明"为什么这种素质是这一侧面必需的")。判停条件:如果发现两个侧面要求同一素质,合并它们。不要"7"硬凑,视对象复杂度伸缩。() +5. **诊断失衡** + - 完成标准:对作品做诊断——"X 的故事侧面过强,人物侧面被阉割"或"X 平衡良好"。失衡的反模式:单侧面极致、其他侧面消失(如詹姆斯的模式阉割,见下文案例与 references/pattern-rhythm.md)。() +6. **给出动态平衡的处方,指向下一层透镜** + - 完成标准:至少 1 条"如何修复失衡"的具体建议。不要给空话(如"加强人物")——给可操作建议(如"加入至少一个圆形人物,因为该侧面目前只有扁平人物")。定位完维度就交给五个透镜(故事/情节、时间/价值、情节/人物、模式/节奏、幻想/预言)查病灶,不在维度层深入细节。(;) + - 判停条件:如果用户继续追问某桶/某侧面的细节,引导到对应透镜文件或专精 skill,不在本层继续。 + +## 案例全文 + +### 案例 1:作者自传——5 部小说按 6 桶全检查() + +- **问题**:作者自己 5 部小说,第一本 *Darkness Bound* 如何做到首稿几乎零修改卖给 NY 大出版社? +- **方法论的使用**:5 部小说都按 6 桶全维度自检:Concept(清晰)+ Character(3 维)+ Theme(隐含)+ Structure(4 箱)+ Scene(mission-driven)+ Voice(干净专业)。 +- **结论**:6 桶没有短板,首稿即可投稿。 +- **结果**:8 周写完 *Darkness Bound*;*Bait and Switch* 被 Publishers Weekly 评为 2004 年度最佳 Mass Market 书。 + +### 案例 2:拒稿诊断——失败模式按桶归类() + +- **问题**:无数被拒稿,共同的失败模式是什么? +- **方法论的使用**:把拒稿原因分类到 6 桶:Concept 不够新(10%)/ Character 太工具人(25%)/ Theme 缺失或说教(15%)/ Structure 错位(30%)/ Scene 散漫(15%)/ Voice 抢戏(5%)。 +- **结论**:6 桶框架是出版商判断"这书值不值得"的标准,不是作者的个人理论。 +- **结果**:用 6 桶预检手稿的作者,拒稿率显著下降。 + +### 案例 3:小说本体的七侧面——框架自身的展开() + +- **问题**:小说太复杂,无法被定义。 +- **方法论的使用**:福斯特列出 7 个侧面(故事/人物/情节/幻想/预言/模式/节奏),每个侧面配对一个读者素质要求。 +- **结论**:整本《小说面面观》即此框架的展开,9 讲对应 7 侧面 + 绪论 + 结论。 +- **结果**:该框架被文学评论广泛采用,"七侧面"成为小说分析的经典入口。 + +### 案例 4:贝内特 托尔斯泰《战争与和平》——单侧面过强 vs 多侧面平衡() + +- **问题**:同样写时间,为什么前者"失于伟大",后者"伟大"? +- **方法论的使用**:贝内特只展开"时间"侧面(后来呢 + 时间生活),托尔斯泰同时展开"时间"和"空间"(空间感"类似音乐的力量")。 +- **结论**:单侧面过强(贝内特)vs 多侧面平衡(托尔斯泰)。 +- **结果**:福斯特借此说明——优秀小说的标志是侧面的动态平衡,不是单一侧面的极致。 + +> 同一对比在时间/价值角度下的全文案例见 references/time-value.md(贝内特的时间生活极致、托尔斯泰的空间感 = 价值生活);在故事/情节角度下的简注见 references/story-plot.md。角度不同,多处保留。 + +### 案例 5:亨利·詹姆斯《使节》——模式压倒其他侧面() + +- **问题**:詹姆斯的小说是模式(沙漏)的胜利,但代价巨大。 +- **方法论的使用**:福斯特用七侧面诊断——模式侧面过强,阉割了人物(类型贫乏)、情节(靠关系设计)、幻想/预言(不谈哲学/信仰)。 +- **结论**:"美如期而至, 只是模样太霸道了些",单侧面的极致牺牲了其他侧面。 +- **结果**:借此福斯特区分"戏剧可以(亚里士多德规训),小说不行"。 + +> 同一作品在"模式付出了什么代价"角度下的全文案例见 references/pattern-rhythm.md(人物类型清单、衣服不脱、病不知名),角度不同,两处都保留。 + +## 常见误区与失败模式 + +- **把 6 桶当成"6 个独立任务"而不是"6 个相互交织的能力"**——实际上 6 桶共同决定故事,任何一桶不及格都毁掉整本。() +- **把 6 桶当成"必须 1-10 打分"的形式化**——它们是诊断维度,不是评分表。() +- **亚里士多德式套用**——把"开端—发展—高潮—结局"硬套到所有作品,把小说写成戏剧(戏剧化的小说)。() +- **单侧面极致**——只追求"故事好看"或"模式精美"或"人物深刻",牺牲其他侧面(如詹姆斯的模式压倒人性)。() +- **七侧面被当成"小说本体论"**——误以为福斯特给出了小说的完整本体,而非"我感兴趣的七个方向"。() + +## 边界与盲点 + +不适用场景: + +- 用户的问题已经定位到具体能力(例如"我的 Concept 不够好")——应使用对应专精 skill(concept-design、character-design、story-structure 等)。() +- 非小说写作(诗歌/学术论文/技术文档)——这是小说写作框架。() +- 用户在问"如何写一个 hook"/"如何写一个场景"——用具体创作 skill。() +- 单一因果问题("为什么 X 会发生")、纯事实查询、有明确定义边界的对象(如"什么是 HTTPS 协议")、时间紧迫/决策需要即时答案——七侧面分析需要深度思考,决策可读 references/time-value.md 快速判断。() + +作者盲点(两书都保留): + +- Brooks,2011 年传统出版视角:默认目标 = 卖 NY 出版社或好莱坞;不直接适配自出版、Kindle 时代、有声书等。6 桶未覆盖营销/读者画像/平台策略等出版商业能力。6 桶假设单一主角;群像/POV 切换小说/不可靠叙述者,6 桶需调整。() +- 福斯特,七侧面的完备性:福斯特没论证为什么是这七个,也不是六个、八个;这是"我感兴趣的方向",不是"小说的全部"。() +- 福斯特,白英美欧陆男性中心的视角:引用的作家几乎全是西方男性;19 世纪以来被边缘化的女性作家、非西方作家未被充分纳入。() +- 福斯特,现代主义巅峰期的局限:1927 年的视角,看不到 1960s 后的拉美魔幻现实主义、后现代拼贴、亚非作家群体。() + +## 易混的邻近方法论 + +- **K.M. Weiland 的"Story Structure"5 桶**:5 桶分类(Structure/Character/Scene/Dialogue/Word Choice)重叠度高,但少 Concept 和 Theme。() +- **Save the Cat 的 15 节拍**:是 Structure 一桶的细化,不是 6 桶的替代。() +- **"7 个故事原型"(Christopher Booker)**:主题原型,不构成 6 桶分类。() +- **vs MECE 分类法**:MECE 是"互不重叠,合起来穷尽",追求完备;七侧面是"列多个角度,允许交叠",追求丰富。() +- **vs SWOT / 5W1H / 波特五力**:这些是"分析工具",七侧面是"分析姿态";后者更反思,不假装客观。() +- **vs 思维导图/心智图**:七侧面是**有结构约束**(每个侧面有素质要求)的视角,不是发散联想。() + +## 中文落地 + +- 六桶名字直接中文化使用:概念、人物、主题、结构、场景执行、语言声音。中文小说诊断时,"Writing Voice"一桶要额外纳入汉语特有的语感问题(文白夹杂、翻译腔、网文口癖),见 prose-craft 的语言规则,本包不展开。 +- 七侧面用于中文作品时,"模式与节奏"侧面有本土资源可对:章回小说的对偶回目、章法就是现成的模式/节奏现象,详见 references/pattern-rhythm.md 的"中文适配"节。 +- 中文长篇(尤其网文连载)常是"人物"与"结构"两桶最易不及格:人物工具人化(追更压力下人物让位于桥段)、结构错位(上架节点代替情节节点)。诊断时优先对照这两桶。 diff --git a/framework/catalog/pi/skills/novel-diagnosis/references/fantasy-prophecy.md b/framework/catalog/pi/skills/novel-diagnosis/references/fantasy-prophecy.md new file mode 100644 index 0000000..47a50e3 --- /dev/null +++ b/framework/catalog/pi/skills/novel-diagnosis/references/fantasy-prophecy.md @@ -0,0 +1,135 @@ +# 神异层透镜:戏耍还是歌唱——幻想与预言孪生光柱 + +来源: + +这是福斯特对作品神异层的诊断透镜。幻想与预言不是第八、第九个侧面,而是横贯故事、人物、情节之上的"光柱"——更高阶的维度,彼此孪生。两者都要求读者"额外付 6 便士"(接受神异、接受非理性),但姿态不同:幻想是戏耍,预言是歌唱。 + +## 原文摘录 + +> "我所说的, 是横贯它们的东西, 就像一道光柱 …… 在某一处与它们关联密切, 耐心地照亮它们所有的问题, 而在另一处又径直越过或贯穿它们, 就像它们根本不存在一样。我们应该给这束光起两个名字: 幻想和预言。" + +> "它要求我们给予某种额外的东西。它要求我们能够自我调适, 不同于艺术品所要求的调试, 这是另一种额外的调试能力。" + +> "它的方式方法乃至题材都是奇特的, 就像主展之外的附加小展, 你得在入场费之外额外再付六便士才能看得到。" + +> "我们所说的'预言', 是一种口吻, 一种语调。 …… 重要的是作者声音里的语调, 是他的歌谣。" + +> — E. M. 福斯特, 《小说面面观》第六讲 / 第七讲 + +() + +## 方法规则 + +幻想与预言是横贯故事/人物/情节之上的"光柱",**不是新的侧面,是更高阶的维度**,彼此孪生。两者对读者的要求不同,但都是"额外付 6 便士"——接受神异、接受非理性。() + +核心操作: + +1. **识别"光柱"的存在**——一部作品里,如果有某种"横贯"故事/人物/情节的东西,让你感觉"作品在自己生长,似乎在说我无法控制的事",那就有光柱。 +2. **区分幻想 vs 预言**: + - **幻想(Fantasy)**:召唤"低空/浅水/小丘间的精灵"(法翁/德律阿德斯/潘神/赫耳墨斯),是神话的低端,带着"随意的即兴感"。例:《项狄传》《朱莱卡·多卜森》《魔笛》《尤利西斯》。 + - **预言(Prophecy)**:召唤"彼方的神灵"(路西法/希腊/印度的超越),直面"融合与统一",是"歌者"而非"戏耍者"。例:陀思妥耶夫斯基《卡拉马佐夫兄弟》、梅尔维尔《白鲸记》、劳伦斯《恋爱中的女人》、艾米莉·勃朗特《呼啸山庄》。 +3. **幻想的检验**:它是否"渗透在世界的每一个角落却不能渗入'掌控世界的力量'"?是否有"随意的即兴感"? +4. **预言的检验**:它是否"像一首歌或一种声音"?是否有"粗糙的表面"(具体日常细节)之上某种"光洁柔润"的东西? +5. **6 便士测试**——检测一部作品是否召唤出幻想/预言侧面的**成本测试**:它是否要求读者在"接受常理"之外再多付一份"接受神异/接受非理性"的成本? + +关键认识:幻想和预言是孪生但不等同。幻想更像游戏(允许暂时"假装的非理性"),预言更像皈依(要求谦逊和搁置幽默感)。**不付 6 便士不代表读者无想象力,只代表他不愿响应这一要求**(例:阿斯奎斯对《淑女变狐狸》的反应)。() + +### 判断标准 + +- 检测"光柱"是否存在:标出至少 1 处作品里"横贯其他元素、似乎在说自己生长方向"的现象;如果没有,作品没有进入幻想/预言,走常规分析。( 执行步骤) +- 区分幻想 vs 预言:问"作者在戏耍(幻想)还是在歌唱(预言)?"戏耍 → 召唤"低空精灵",接受"神异作为游戏";歌唱 → 召唤"彼方神灵",接受"神异作为皈依"。( 执行步骤) +- 6 便士测试:明确说出"这部作品要求读者额外付出 X 种素质"(如"接受混乱"、"接受死亡在文本外的延续"、"接受动物有灵魂")。判停条件:如果用户表示"我无法付出 X",尊重选择,不强推。( 执行步骤) +- 检查谦逊与幽默感的暂时搁置(预言面):评估读者是否愿意"暂时不嘲笑 X";如不愿意,预言无效。福斯特明示:"幽默感,在这里很不合时宜,这种有教养者的可贵的附加品质必须被暂时搁置一旁"。( 执行步骤) +- 给出"双向"判断:明确说"作品召唤是否合理(是)+ 读者选择不响应是否合理(是)"——双方都无错。不要再做"你必须读懂它"的教育姿态。( 执行步骤) + +## 操作步骤(执行流程) + +来源: 执行段五步。 + +1. **检测"光柱"是否存在** + - 完成标准:标出至少 1 处作品里"横贯其他元素、似乎在说自己生长方向"的现象。 + - 如果没有,作品没有进入幻想/预言,走常规分析。 +2. **区分幻想 vs 预言** + - 完成标准:问"作者在戏耍(幻想)还是在歌唱(预言)?" + - 戏耍 → 召唤"低空精灵",接受"神异作为游戏";歌唱 → 召唤"彼方神灵",接受"神异作为皈依"。 +3. **应用 6 便士测试** + - 完成标准:明确说出"这部作品要求读者额外付出 X 种素质"(如"接受混乱"、"接受死亡在文本外的延续"、"接受动物有灵魂")。 + - 判停条件:如果用户表示"我无法付出 X",尊重选择,不强推。 +4. **检查谦逊与幽默感的暂时搁置(预言面)** + - 完成标准:评估读者是否愿意"暂时不嘲笑 X";如不愿意,预言无效。 + - 福斯特明示:"幽默感,在这里很不合时宜,这种有教养者的可贵的附加品质必须被暂时搁置一旁"。 +5. **给出"双向"判断** + - 完成标准:明确说"作品召唤是否合理(是)+ 读者选择不响应是否合理(是)"——双方都无错。 + - 不要再做"你必须读懂它"的教育姿态。 + +## 案例全文 + +### 案例 1:斯泰恩《项狄传》——幻想的典型() + +- **问题**:《项狄传》(1759—1767)没有超自然现象,为什么是"幻想"代表? +- **方法论的使用**:福斯特诊断——"混乱神"已经近乎人格化,整个宏大故事中"人物做得越多,得到的就越少 …… 事实趋向邪恶,不是导向未来,而是纠缠于过去"。这是"幻想"对神异的最广义使用——接受"现实可能彻底不连贯"这一前提。 +- **结论**:幻想的本质是"接受神异",不必非有精灵/天使;接受"混乱"本身就是接受神异。 +- **结果**:借此福斯特把"幻想"从"奇幻类型"扩展到"接受非理性的姿态"。 + +> 同一作品(《项狄传》)在圆桌论比较角度下的案例见 references/round-table.md 案例 1(与伍尔夫《墙上的斑点》共享同一束幻想之光),角度不同,两处都保留。 + +### 案例 2:梅尔维尔《白鲸记》——预言的代表() + +- **问题**:《白鲸记》表面是捕鲸传奇,为什么福斯特说它"难读而且无比重要"? +- **方法论的使用**:福斯特诊断——一旦捕捉到其中"飘荡的歌声",就能看到"那音韵铿锵,却断断续续,没有清晰的题解,也绝对没有向后触及怜悯与爱的宇宙,没有'二位,我做了个好梦'"。这是预言的特征:歌,不是戏。 +- **结论**:预言的核心是"语调(tone)",不是题材。梅尔维尔"歌唱"了"恶"的概念,这是小说中"对恶"最强大的处理。 +- **结果**:借此福斯特把"预言"从"宗教预言"扩展到"作者的歌唱"。 + +### 案例 3:阿斯奎斯 vs《淑女变狐狸》——6 便士测试的失败() + +- **问题**:阿斯奎斯(英国前首相)拒绝接受《淑女变狐狸》变不回淑女。 +- **方法论的使用**:福斯特诊断——阿斯奎斯"是一位真诚的文学爱好者,但他并不愿意支付额外的六个便士,又毋宁说,他愿意支付,只是期望在最后能拿回来"。 +- **结论**:拒绝付 6 便士是合法的(阿斯奎斯无错),但书因此"让他觉得不舒服"——书的召唤没生效。 +- **结果**:借此福斯特说明,6 便士测试是"双向"的——作品要求付,读者选择付或不付,双方都不必"错"。 + +## 常见误区与失败模式 + +- **约翰逊博士式"判定怪书不能流传"**——"任何剑走偏锋的东西都不会长久,比如《项狄传》,就没能流传下来!"——用惯例丈量神异。() +- **拒绝付 6 便士但假装喜欢**——阿斯奎斯式,"期望在最后能拿回来"。() +- **幻想/预言的作者自欺**——格特鲁德·斯坦因式"想砸碎时钟",但"她的失败却很有启发意义"。() +- **神秘主义滥用**——把"神异"当成万能解释,不承认只是修辞。() + +## 边界与盲点 + +不适用场景:() + +- **自然主义题材**——没有神异,6 便士测试不适用。 +- **完全日常的写作**——普通新闻、报告、菜谱,没有"光柱"。 +- **儿童文学的常规奇幻**——哈利波特式已经规则化,不需要"付 6 便士"诊断。 +- **学术写作**——要求清晰、理性,不召唤神异。 + +作者盲点:() + +- **1927 年的视角**——没看到 1960s 后的魔幻现实主义(马尔克斯)、新浪潮电影(费里尼、林奇)、后现代拼贴(品钦、巴塞尔姆)。 +- **白英美欧陆男性中心的视角**——引用的作家几乎全是西方男性;非西方的"神异"传统(中国志怪、日本怪谈、阿拉伯神话)未被充分讨论。 +- **对"接受神异"的诊断带有 20 世纪初的阶级偏见**——"高尔夫球手"和"公交车司机"是有教养者 vs 普通人的隐喻;现代的"接受神异"门槛因大众文化普及而部分降低。 + +## 易混的邻近方法论 + +- **vs 类型奇幻(Fantasy Genre)**——类型奇幻是规则化(有自己的"非理性规则"),幻想是接受神异的姿态。() +- **vs 宗教预言(Religious Prophecy)**——福斯特明示"预言"不是宗教的,是"作者声音里的语调"。() +- **vs 神秘主义(Mysticism)**——神秘主义要求皈依,幻想/预言是文学接受;两者姿态相似但目标不同。() +- **与 seven-aspects 的区别**:幻想/预言是**横贯其他侧面的光柱**(更高阶),七侧面是**并列的 N 个侧面**。 +- **与 quack-scholar-check 的区别**:幻想/预言是**作品层面的神异**,伪学者自检是**评论者层面的自检**。 +- **与 mystification 的区别**:蒙蔽是**作者隐藏技巧**,幻想/预言是**作者召唤神异**。 + +## 中文转述:志怪、神魔、仙侠传统与适用边界 + +**[中文适配]** + +福斯特以英国小说的神异传统立论,中文写作换志怪、神魔、仙侠谱系看接受门槛与姿态: + +- **门槛不在"信不信有妖怪"**:志怪有"记异为实"的传统,神怪以事实身份进入叙述,中文读者接受神异几乎不需要铺垫;真正的门槛是**神怪是否通人情**——聊斋传统写鬼狐而有人的情感,只堆奇观和设定的会被拒绝。 +- **幻想面对应《西游记》式的戏谑玩闹、志怪式的随手即兴**:把不连贯当游戏,不必要求读者严肃。 +- **预言面对应语调"歌唱"的庄严之作**:天问式诘问、谶语式预言、《红楼梦》结尾"白茫茫大地真干净"式的神话肃穆;读者付的是读史而叹式的庄重,**门槛在意愿,不在能力**。 +- **适用边界**: + - 规则化的类型奇幻(体系化修仙仙侠、系统流、无限流)自带接受规则,读者按规则付费,**不需要六便士测试**;对这些作品乱用六便士测试是误诊。 + - 无神异内容的自然主义现实题材**不用本透镜**。 + - 六便士测试真正适用的是:在常理叙事里突然引入神异、且要求读者额外接受一份"非理性"的作品(志怪笔法写现实、寓言式神魔、谶语预言体)。 + +中文落地诊断流程:走六便士测试,列出作品要求读者额外接受什么 → 判定是幻想面(戏谑玩闹、随手即兴)还是预言面(语调"歌唱"的庄严之作)→ 再按中文志怪、神魔、仙侠谱系看其接受姿态(神怪是否通人情、门槛在意愿还是能力)→ 给出双向判断(作品召唤合法,读者选择不付也合法)。 diff --git a/framework/catalog/pi/skills/novel-diagnosis/references/pattern-rhythm.md b/framework/catalog/pi/skills/novel-diagnosis/references/pattern-rhythm.md new file mode 100644 index 0000000..9d064fb --- /dev/null +++ b/framework/catalog/pi/skills/novel-diagnosis/references/pattern-rhythm.md @@ -0,0 +1,133 @@ +# 形式层透镜:看画还是听乐——模式 vs 节奏 + +来源: + +这是福斯特对作品形式感的二分诊断:模式(Pattern,借自绘画)是完整可感的几何结构,处处存在;节奏(Rhythm,借自音乐)是重复与变化的结合,不必处处存在,却能从内部黏合整体。模式是"画",节奏是"乐"。小说的血肉(人物、情节、幻想)适合节奏,多过模式。 + +## 原文摘录 + +> "首先要从绘画艺术中借一个词, 称之为'模式'。然后再从音乐艺术中借一个词, 称之为'节奏'。 …… 有时候并非如此。当它不那么完整时, 我会称之为'节奏'。" + +> "模式主要来源于情节, 就像云中的一道光, 二者始终相伴, 即便到最后云消雾散, 散光依然是看得见的。" + +> "小说中的简单节奏问题, 如下阐述应该很充分了: 它或许可以定义为'重复与变化的结合'。" + +> — E. M. 福斯特, 《小说面面观》第八讲 + +() + +## 方法规则 + +小说审美侧面的**二分法**。借自绘画(模式)和音乐(节奏),用来识别作品形式感的两种不同形态。() + +核心操作: + +1. **模式(Pattern)= 完整可感的几何结构,处处存在**: + - 整本书可被一个几何/视觉形象概括(沙漏、大循环、大教堂的放射线条、普洛克路斯忒斯之床) + - 故事从一处出发经一处回到原点 + - 完整统一,处处存在 + - 适合承载美感的明确表达(亨利·詹姆斯《使节》、法朗士《泰伊丝》、卢伯克《罗马风情画》) +2. **节奏(Rhythm)= 重复与变化的结合,不必处处存在**: + - 重复的元素(主题/意象/旋律)在每次出现时携带新意义 + - 拥有自己的生命,与听众和创造者的生命都无关 + - 随盈缺带来惊喜,能在书内部黏合散落的事件 + - 适合承载不必处处存在但能黏合整体的作品(普鲁斯特《追忆似水年华》的凡德伊小乐句、托尔斯泰《战争与和平》的"宏大和弦") +3. **节奏的检验公式**: + - 重复之间是否有变化? + - 那种变化是否能调动"我们脑海中记忆的美化"? +4. **模式的代价**——福斯特明示:"美如期而至,只是模样太霸道了些"——戏剧可以(拉辛),小说不行(因为小说承载了"人性的肥满内容")。模式会"阉割"人物类型、情节、幻想/预言。 +5. **节奏的失败**——纯重复(僵化成符号)像"高尔斯华绥的西班牙猎犬约翰"绊人;梅瑞狄斯的樱花树/小艇"只重现不发展",沦为"标语条幅"。 + +关键认识:模式 vs 节奏不是好坏,是**不同形式感**。模式是"画",节奏是"乐"。但小说的血肉(人物、情节、幻想)适合节奏,不适合模式。() + +### 判断标准 + +- 诊断作品是"模式型"还是"节奏型":至少给出 1 个"几何形象"(沙漏/大循环/大教堂等)或 1 个"重复元素"(乐句/主题/意象);两者都不存在 → 形式感弱,走其它分析。( 执行步骤) +- 模式型评估代价:列出"模式阉割了什么"(人物类型、情节、幻想/预言等);被阉割的是否是你最重要的部分?是 → 模式不合适;否 → 模式可接受。( 执行步骤) +- 节奏型评估节拍:标出至少 1 个"重复 + 变化"的元素;重复是否每次都带来新意?否则节奏就死了(像高尔斯华绥的西班牙猎犬约翰)。( 执行步骤) +- 失衡方向:模式过强(牺牲人性)/ 节奏过弱(无内在节拍)/ 平衡良好。反模式:模式过强 → 普洛克路斯忒斯之床;节奏过弱 → 流水账。( 执行步骤) + +## 操作步骤(执行流程) + +来源: 执行段五步。 + +1. **诊断作品是"模式型"还是"节奏型"** + - 完成标准:至少给出 1 个"几何形象"(沙漏/大循环/大教堂等)或 1 个"重复元素"(乐句/主题/意象)。 + - 判停条件:如果两者都不存在,形式感弱,走其它分析。 +2. **对"模式型"作品评估代价** + - 完成标准:列出"模式阉割了什么"——人物类型、情节、幻想/预言等。 + - 评估:被阉割的是否是你最重要的部分?是 → 模式不合适;否 → 模式可接受。 +3. **对"节奏型"作品评估节拍** + - 完成标准:标出至少 1 个"重复 + 变化"的元素(如普鲁斯特的小乐句,或托尔斯泰的空间和弦)。 + - 评估:重复是否每次都带来新意?否则节奏就死了(像高尔斯华绥的西班牙猎犬约翰)。 +4. **诊断失衡方向** + - 完成标准:明确说"模式过强(牺牲人性)/ 节奏过弱(无内在节拍)/ 平衡良好"。 + - 反模式:模式过强 → 普洛克路斯忒斯之床;节奏过弱 → 流水账。 +5. **给出修复建议** + - 完成标准:至少 1 条具体修改(如"加入一个'小乐句'式重复元素,让散落的事件黏合"或"放宽模式的完美,让人物多面性")。 + - 不要空话(如"加强节奏")——给可操作修改。 + +## 案例全文 + +### 案例 1:法朗士《泰伊丝》——沙漏形模式的首要范例() + +- **问题**:一本沙漏形的书是什么样的? +- **方法论的使用**:福斯特诊断——帕弗纽斯(沙漠禁欲者)和泰伊丝(亚历山大港交际花)两人"相向而行、擦肩而过、交换位置,如数学般精准"。故事是"事件依照时间顺序",情节是"因果",**模式是"沙漏"**——中心相遇,两端交换。 +- **结论**:模式激发美感,模式来自情节,模式能引导我们"以整体的眼光看待这本书"。 +- **结果**:借此福斯特把"沙漏形"作为模式分析的标准入口。 + +### 案例 2:普鲁斯特《追忆似水年华》——节奏的样本() + +- **问题**:《追忆》"混乱无序,结构错乱扭曲,没有外部框架",为什么它仍然是一部完整的作品? +- **方法论的使用**:福斯特诊断——因为它有节奏,凡德伊小乐句"贯穿全书,一次又一次出现,就像一种回声,一段记忆"。这个乐句"有自己的生命,跟它的听众的生命无关,跟创造它的人的生命也无关",**"几乎就是一个独立的角色"**。 +- **结论**:节奏作为"重复与变化的结合",让没有外部框架的作品在内部黏合。 +- **结果**:借此福斯特把"节奏"作为普鲁斯特这种"无框架但完整"作品的形式感来源。 + +### 案例 3:亨利·詹姆斯《使节》——模式压倒人性() + +- **问题**:沙漏形模式的胜利,代价是什么? +- **方法论的使用**:福斯特诊断——詹姆斯"人物类型清单非常短"(观察者、平庸局外人、好心配角、美好女主角、恶棍、年轻艺术家),人物线条简单(只寥寥几笔),衣服不脱,病不知名,收入不提,仆人安静。 +- **结论**:模式为美付出的代价是阉割——"只有亨利·詹姆斯的人物才适合亨利·詹姆斯的小说,尽管他们都是不死的"。 +- **结果**:借此福斯特把"模式"从"美学胜利"翻转为"美学代价"。 + +> 同一作品在七侧面动态平衡角度下的案例见 references/dimension-frameworks.md 案例 5(模式侧面过强阉割人物/情节/幻想预言),角度不同,两处都保留。 + +## 常见误区与失败模式 + +- **模式阉割人性**——亨利·詹姆斯的"普洛克路斯忒斯之床"(詹姆斯式模式压倒人性)。() +- **节奏僵化为符号**——梅瑞狄斯的樱花树/小艇"只重现不发展"(梅瑞狄斯式节奏僵化为符号)。() +- **节拍重复绊脚**——高尔斯华绥的西班牙猎犬约翰"横在我们脚下"(高尔斯华绥式节拍重复绊脚)。() +- **追求完整闭环到伤害人性**——模式强求一律,"普洛克路斯忒斯之床"是其极端。() + +## 边界与盲点 + +不适用场景:() + +- **完全没形式感的对象**——如纯流水账日记,没有可识别的模式/节奏。 +- **真正以"无结构"为目标的实验艺术**——故意拒绝形式,不该被分析。 +- **戏剧/音乐本身**——戏剧本来就该有"模式"(亚里士多德),音乐本来就该有"节奏";这里的"模式 vs 节奏"是小说分析框架。 +- **纯功能对象**——如工具、家具,不需要"美感形式感"。 + +作者盲点:() + +- **小说 / 戏剧的形式感二分过于干净**——实际上现代戏剧(布莱希特、贝克特)早就拒绝亚里士多德模式,与福斯特的论断冲突。 +- **西方文学中心的视角**——引用的几乎全是西方小说;中国章回小说(用对仗、回目、章法作为"节奏")、日本物语(用"调"作为模式)未被充分讨论。 +- **1927 年的视角**——没看到 60 年代后的后现代拼贴、装置艺术、数字媒体的"形式感"。 + +## 易混的邻近方法论 + +- **vs 戏剧结构(三幕剧/五幕剧)**——戏剧结构是"模式"的一种,不是"节奏"。() +- **vs 蒙太奇(Montage)**——蒙太奇是"通过剪辑创造意义",节奏是"重复元素携带新意"。() +- **vs 三段式/起承转合**——这些是"模式"的具体形态,不是"节奏"。() +- **与 expansion-vs-completion 的区别**:模式/节奏是**形式感的类型**,扩展/完成是**作品终点的姿态**;前者管整体,后者管结尾。 +- **与 fantasy-prophecy-twin 的区别**:模式/节奏是**形式层**,幻想/预言是**神异层**;模式强的作品通常不召唤神异(因为已经"完整")。 +- **与"结构主义(Structuralism)"的区别**:结构主义是"找底层结构",模式是"看可感的形式",节奏是"听内在的节拍"。 + +## 中文适配 + +**[中文适配]**: + +- 章回小说的**对偶回目、开篇收场诗、章法是现成的模式资源**。回目本身就是一组组对称的几何期待,章法(起承转合、首尾呼应、草蛇灰线)让整本书可被一个结构形象概括——这就是福斯特说的"模式"。 +- **一个意象或语句每次重现都携带变化,是节奏式手法**。《红楼梦》里反复出现而每次意义不同的意象、判词、戏文,就是凡德伊小乐句式的"重复与变化的结合"。 +- **模式与节奏可以同书并用**:章法管模式(外部框架),意象重现管节奏(内部黏合),二者不冲突。 +- 中文落地诊断时:把"模式"问题问成"全书能不能用一个几何形象/章法概括",把"节奏"问题问成"有没有重复出现的意象/语句,每次是否带来新意"。警惕回目、章法把人物"阉割"成类型(模式过强),也警惕意象沦为只重现不发展的标语(节奏僵化)。 diff --git a/framework/catalog/pi/skills/novel-diagnosis/references/plot-character.md b/framework/catalog/pi/skills/novel-diagnosis/references/plot-character.md new file mode 100644 index 0000000..e6a1617 --- /dev/null +++ b/framework/catalog/pi/skills/novel-diagnosis/references/plot-character.md @@ -0,0 +1,125 @@ +# 张力层透镜:情节和人物谁赢——情节与人物的拉锯战 + +来源: + +这是福斯特对"情节 vs 人物"张力的元模型诊断:情节要"因果收尾",人物要"自由发展",二者必然冲突。福斯特判断小说"虎头蛇尾"是结构必然,因为"情节需要收尾打结"。拉锯不是缺陷,是结构必然;关键不是消灭拉锯,是主动选择拉锯的解决方式。 + +## 原文摘录 + +> "情节是小说中偏于逻辑理性的一面, 它要求有悬念, 但悬念稍后便会解开; 读者可以在未知的世界里寻觅求索, 可小说作者不会迷茫。他游刃有余, 泰然自若, 居高临下总揽全局, 在这里投下一柱光, 那里藏起一个秘密 …… 不断与身为'人口贩子'的自己辩驳协商, 以期达成最佳效果。" + +> "几乎所有小说都有点儿虎头蛇尾。这是因为情节需要收尾打结 …… 若不是还有死亡与婚姻, 我真不知道大多数小说作者要怎么收场。" + +> "小说作者不得不亲力亲为, 劳心劳力, 好按时完成工作。他假装所有人物都围绕自己行动。他不断提起他们的名字, 不断动用引号让他们发声。可他们不是消失了, 就是死了。" + +> — E. M. 福斯特, 《小说面面观》第五讲 情节 + +() + +## 方法规则 + +关于情节-人物张力的**元模型**:情节要求"因果收尾",人物要求"自由发展",二者必然冲突。福斯特的诊断:小说"虎头蛇尾"是结构必然,因为"情节需要收尾打结"。() + +核心操作: + +1. **承认拉锯是结构必然**——任何"逻辑结构 + 自由参与者"的项目都面临这个张力。情节(逻辑)要收尾,人物(自由)要发展,二者必然冲突。 +2. **三种典型处理**: + - **哈代式**(人物为情节牺牲):命运凌驾人物,人物被"耗尽生命力,变得干瘪单薄"。**失败**。 + - **梅瑞狄斯式**(情节胜出):让人物暂时让步,留下"言犹未尽"的优雅。**部分成功**。 + - **反情节式(《伪币制造者》)**(取消单一主线):接受混乱,让"逻辑片段"并列。**另一种成功**。 +3. **虎头蛇尾的诊断**——多数小说在收尾处"人物消失了"或"人物死了"。福斯特明示:"若不是还有死亡与婚姻,我真不知道大多数小说作者要怎么收场"。 +4. **"情节 vs 人物"的检验**: + - 哪一方胜出?胜出的代价是什么? + - 胜出方是否阉割了对方(如哈代式让人物失去"人之为生灵所做出的努力")? +5. **"我假装所有人物都围绕自己行动"**——小说作者亲口承认这是"假装",因此需要主动决定"假装到何种程度"。 + +关键认识:拉锯不是缺陷,是结构必然。**关键不是"消灭拉锯",是"主动选择拉锯的解决方式"**。哈代式(人物牺牲)是合法的失败,梅瑞狄斯式(情节胜出)是合法的优雅,反情节(接受混乱)是合法的另一种选择。() + +### 判断标准 + +- 收尾处"人物死了/消失了"是情节压倒人物的征兆(关注"收尾"和"开头")。( 执行步骤) +- 三种解决方式的代价:选梅瑞狄斯式,人物被节制;选哈代式,人物被阉割;选反情节,读者可能困惑。( 执行步骤) +- 对策:对哈代式,加 1 个"圆形人物"摆脱扁平;对梅瑞狄斯式,加 1 个"言犹未尽"的桥段;对反情节,加 1 个"主线暗示"。( 执行步骤) + +## 操作步骤(执行流程) + +来源: 执行段五步。 + +1. **承认拉锯是结构必然** + - 完成标准:明确说出"任何'逻辑结构 + 自由参与者'的项目都有这个张力,关键不是消灭它,是选择解决方式"。 +2. **诊断拉锯的方向** + - 完成标准:至少标出 1 处"逻辑压倒自由"或"自由压倒逻辑"的具体征兆。 + - 提示:关注"收尾"和"开头"——收尾处"人物死了/消失了"是情节压倒人物的征兆。 +3. **选择拉锯的解决方式** + - 完成标准:明确说"我选哈代式(失败样本)/ 梅瑞狄斯式(节制胜出)/ 反情节(取消问题)"。 + - 理由模板:"因为 X 是 [类型/规模/目的],所以 [方式] 更合适"。 +4. **评估胜出的代价** + - 完成标准:明确说"如果我选梅瑞狄斯式,人物被节制;如果我选哈代式,人物被阉割;如果我选反情节,读者可能困惑"。 + - 给出对策:对哈代式,加 1 个"圆形人物"摆脱扁平;对梅瑞狄斯式,加 1 个"言犹未尽"的桥段;对反情节,加 1 个"主线暗示"。 +5. **设计具体修改** + - 完成标准:至少 1 条具体修改(如"在 X 段让人物做出违背情节的举动,显示自由"或"在收尾处加入'言犹未尽'的桥段")。 + - 不要空话(如"让情节更节制")——给可操作修改。 + +## 案例全文 + +### 案例 1:哈代《列王》《无名的裘德》——拉锯失败的样本() + +- **问题**:哈代是伟大的诗人,但为什么"小说只是审视,并不会发声歌唱"? +- **方法论的使用**:福斯特诊断——哈代"在架构事件时更着重的是因果关系,情节是他的设计图,人物必须服从设计图的要求"。在《无名的裘德》中,"命运的悲剧之中,始终有某个生死攸关的问题不曾得到解答,甚至没能清晰地呈现 …… 人物被迫为情节做出了太多牺牲,以至于他们被耗尽了生命力,变得干瘪单薄"。 +- **结论**:哈代式是"拉锯失败"的范本——情节压倒人物。 +- **结果**:借此福斯特说明,"命运凌驾于我们头上,而非命运借我们之手运转"是哈代小说的根本缺陷。 + +> 哈代"命运凌驾人物"在圆桌论跨时代比较角度下的案例( 司各特《威弗莱》,跨 89 年识别同一失败模式)见 references/round-table.md 案例 3,角度不同,两处都保留。 + +### 案例 2:梅瑞狄斯《利己主义者》——拉锯节制() + +- **问题**:梅瑞狄斯是"英国小说诞生以来最出色的情节设计师",但他的人物呢? +- **方法论的使用**:福斯特诊断——梅瑞狄斯"凭借他精准良好的分寸感,令情节成功胜出"。在《利己主义者》中,雷蒂西亚·黛尔的"情感冷却过程是一定要瞒着我们的",这是情节对人物的暂时让步,但让步节制,留下"言犹未尽"。 +- **结论**:梅瑞狄斯式是"拉锯节制"的范本——情节胜出但节制。 +- **结果**:借此福斯特说明,拉锯中"哪方胜出 + 胜出节制"是写作的高级技巧。 + +> 同一人物(雷蒂西亚·黛尔)在情节设计角度下的案例见 references/story-plot.md 案例 2(心境转变隐藏作为情节设计典范),角度不同,两处都保留。 + +### 案例 3:纪德《伪币制造者》——反情节的样本() + +- **问题**:拉锯可以"取消"吗? +- **方法论的使用**:福斯特诊断——纪德"将旧新两套体系并置",让"逻辑片段"并列,没有"一个'主题'",而是"生活的切片",甚至"手起刀落拦腰截断"。这是拉锯的"取消":取消单一情节主线,让多线并列。 +- **结论**:反情节是"拉锯的另一种解决"——接受混乱,不再要求情节胜出或人物胜出。 +- **结果**:借此福斯特说明,拉锯不止两种解决,还有第三种:**取消问题本身**。 + +## 常见误区与失败模式 + +- **哈代式(命运凌驾人物)**——情节压倒人物,人物被耗尽。() +- **戏剧化的小说(亚里士多德三步骤)**——把小说写成戏剧,强行收尾。() +- **多数小说的"虎头蛇尾"**——情节需要收尾,人物消失或死。() +- **追求完整闭环到伤害自由**——模式强求一律,普洛克路斯忒斯之床。() + +## 边界与盲点 + +不适用场景:() + +- **纯逻辑对象(无自由参与者)**——如数学公式、算法,没有"拉锯"。 +- **纯自由对象(无逻辑结构)**——如纯艺术装置、纯抒情诗,没有"拉锯"。 +- **纯事务性事务**——如预约、报销,不需要张力诊断。 +- **极端短篇**——几条推文,没有足够空间让拉锯显现。 + +作者盲点:() + +- **现代主义巅峰期的视角**——1927 年;当时还没有"交互叙事"(游戏)中的"玩家自由 vs 设计师情节"拉锯作为合法形式。 +- **西方文学中心的视角**——中国章回小说用"章法"作为"拉锯的解决",福斯特未充分讨论。 +- **对"反情节"的诊断有限**——纪德是少数样本,后现代文学(品钦、巴塞尔姆)的"反情节"是更激进的形式。 + +## 易混的邻近方法论 + +- **vs 戏剧冲突(Dramatic Conflict)**——戏剧冲突是"人物 vs 人物 / 人物 vs 命运",拉锯是"情节(逻辑)vs 人物(自由)";前者是戏剧内部张力,后者是小说/虚构的整体张力。() +- **vs 自由 vs 控制(Freedom vs Control)**——这是管理学概念,拉锯是文学/叙事学概念;前者管组织,后者管作品。() +- **vs 主题先行 vs 人物先行(Theme-first vs Character-first)**——这是写作教学概念,拉锯是更基础的元模型。() +- **与 story-vs-plot 的区别**:故事/情节是**单方面的诊断**,情节-人物拉锯是**双方面的张力诊断**。 +- **与 flat-vs-round-character 的区别**:拉锯是**多人物 vs 情节结构**的张力,扁/圆是**单人物**的分类。 +- **与 mystification 的区别**:蒙蔽是**作者姿态**,拉锯是**结构张力**;前者管"自然不自然",后者管"哪种要素占主导"。 + +## 中文落地 + +- 福斯特没讨论的中文资源:章回小说用"章法"作为拉锯的一种解决——分回的节拍承担了情节的收束,人物在回目之间流动,既服从章法又保留单回的鲜活。诊断章回体作品时,看分回收束是否硬把人物"写死/写没"。 +- 长篇连载(网文、连载小说)的"虎头蛇尾"高发,因为情节收尾被上架、完本节点逼着提前打结。诊断时看守尾处人物是否消失、死亡或沦为工具;修复优先用梅瑞狄斯式(情节胜出但节制,留"言犹未尽"的桥段),其次考虑加一个圆形人物摆脱扁平。 +- "反情节式"在中文语境里对应多线并置、生活切片式的小说(如部分世情小说、群像小说),诊断时不要强求它"收尾打结",改问"多线并列是否有主线暗示"。 diff --git a/framework/catalog/pi/skills/novel-diagnosis/references/quack-scholar-scan.md b/framework/catalog/pi/skills/novel-diagnosis/references/quack-scholar-scan.md new file mode 100644 index 0000000..e5d68f0 --- /dev/null +++ b/framework/catalog/pi/skills/novel-diagnosis/references/quack-scholar-scan.md @@ -0,0 +1,61 @@ +# 伪学者自检扫描表 + +用法:任何诊断、评论、书评、咨询报告输出之前(或之后复查)过一遍。判断标准与症状定义全部来自 references/quack-scholar.md();本表只是可填写的扫描骨架。福斯特自承"绝大多数人都是伪学者"——扫描的目的不是证明自己不是伪学者,是诚实承认症状并重写。 + +--- + +## 1. 五大症状扫描(每个标 0/1) + +| # | 症状 | 本次输出是否出现(0/1) | 出现在哪段 | +|---|------|------|------| +| 1 | 还没读完就分类(按时间/题材/地区/天气分) | | | +| 2 | 反复求助"天赋/天才"一词(免除深究的苦役) | | | +| 3 | 用"倾向/时代背景/思潮"等便携词取代真思考 | | | +| 4 | 把对象挂到时代背景/作者生平上(放弃深入对象) | | | +| 5 | 用"漂亮"代替"准确"(很美/有灵气/有格调,说不出具体做了什么) | | | + +判停:5 个症状全部 0 → 输出可能不是伪学者的,但要警惕"不知道自己不知道"。 + +## 2. 自检三问(真诚回答,每个给"是/不是" + "为什么") + +1. 我真的读完/做完要评论的对象了吗? + - 答:____;为什么:____ +2. 我用分类/术语/倾向掩盖了理解吗? + - 答:____;为什么:____ +3. 我是否在用漂亮词逃避追问? + - 答:____;为什么:____ + +不要回避"是",诚实地承认伪学者症状。 + +## 3. 最小可替换段落检查 + +标出至少 1 个段落:把其中"X 是天才" / "X 是 X 流派" / "X 反映了 X 倾向"里的具体词替换成另一部作品,整段若仍然成立 → 这是"伪学者段落",必须重写。 + +- 段落位置:____ +- 替换测试:把 ____ 换成另一部作品,段落还成立吗?____ +- 判定:□ 成立(伪学者段落,重写) □ 不成立(保留) + +## 4. 用"具体做了什么"代替"漂亮词"(至少改写 1 段) + +| 原句(漂亮词) | 改写(具体做了什么 → 产生什么效果) | +|---|---| +| 例:这部小说很有灵气 | 例:第 X 章用 Y 细节做了 Z,让读者产生 W 感受 | +| | | + +判停:改写后句子变长或变得不流畅 → 说明之前在用修辞掩盖空洞。 + +中文常见便携词对照(→ references/quack-scholar.md 中文落地): + +| 类别 | 常见空词 | 落地要求 | +|---|---|---| +| 翻译腔 | "有翻译腔" | 指到具体句式:被字句滥用、"的"字连缀过长、"进行 + 动词"堆砌、机翻式连接词密集 | +| 公文腔 | "官样""套话" | 指到具体词:"进行/开展/予以/进一步/不断/切实"、"以……为抓手/落实/赋能"、排比凑数 | +| 空泛赞美 | 有灵气/有格调/有韵味/大气/细腻/直击心灵 | 改写成"作品在某段做了什么具体动作、产生什么效果" | + +## 5. 谦虚声明 + +在输出末尾加一句: + +> 以上评论基于我对 ____ 的有限阅读,可能有盲点。 + +这是福斯特自承"伪学者"姿态的现代版本。 diff --git a/framework/catalog/pi/skills/novel-diagnosis/references/quack-scholar.md b/framework/catalog/pi/skills/novel-diagnosis/references/quack-scholar.md new file mode 100644 index 0000000..d6eed25 --- /dev/null +++ b/framework/catalog/pi/skills/novel-diagnosis/references/quack-scholar.md @@ -0,0 +1,123 @@ +# 清理诊断结论:伪学者自检 + +来源: + +这是福斯特的评审纪律之二,用于诊断输出的最后一步:扫描自己是否在用"分类 + 引用术语"代替"真正理解"。福斯特自承"绝大多数人都是伪学者",给出可识别的症状清单,让评论者/咨询者/教师在输出的同时主动扫描自己是否落入这些症状。诊断结论必须过这一关,否则就是空话。 + +## 原文摘录 + +> "我们绝大多数人都是伪学者 …… 他袭用了真学者的方法, 却并不具备相应的学识装备。还不曾理解, 甚至还不曾博览群书, 他便开始动手将它们分门别类, 这是他的第一宗罪。" + +> "按照时间分类, 1847 年之前的书, 1847 年之后的书 …… 按照内容、题材什么的分类就更傻了。旅馆文学, 起自《汤姆·琼斯》; 女性运动文学, 始于《雪莉》; 荒岛文学, 自《鲁滨孙漂流记》发端 …… 苏塞克斯文学 …… 异类书籍, 一种严肃却枯燥乏味的分支 …… 与工业主义、航天飞行、手足医疗、天气气象等相关的小说。" + +> — E. M. 福斯特, 《小说面面观》第一讲 绪论 + +() + +## 方法规则 + +识别自己是否正在用"分类 + 引用术语"代替"真正理解"的诊断框架。**福斯特自承"绝大多数人都是伪学者"**,给出可识别的伪学者症状清单,让评论者/咨询者/教师在输出的同时,主动扫描自己是否落入了这些症状。() + +**五大症状**: + +1. **症状 1:还没读完就分类**——拿到一本书/一个产品/一个问题,还没深入读完,就开始"按时间分、按题材分、按地区分、按天气活动分"。这是最常见的伪学者动作。 +2. **症状 2:反复求助"天赋"一词**——"这是 X 天才写的","X 是天才","这种事普通人做不出来"。福斯特诊断:反复说"天赋"是因为这个词**免除了深究意义的苦役**——既然是天才,就不必解释为什么好。 +3. **症状 3:用"倾向"等便携词取代真思考**——"X 反映了 Y 倾向","X 是 Z 时代的产物","X 体现了 W 思潮"。福斯特诊断:用"倾向"一词,评论者"灵魂就升华了",听众"多半抽出铅笔记笔记",但都跳过了具体文本。 +4. **症状 4:把对象跟时代背景/作者生平挂钩**——"X 是在 Y 时代背景下产生的","X 是因为 Z 童年经历才写出来的"。福斯特诊断:这是评论者的"特权",放弃深入对象的借口。 +5. **症状 5:用"漂亮"代替"准确"**——把对象修饰得"很美" / "很有灵气" / "很有格调",但说不出具体做了什么。 + +**自检三问(在做完任何评论/咨询/报告后必问)**:() + +- 我真的读完/做完要评论的对象了吗? +- 我用分类/术语/倾向掩盖了理解吗? +- 我是否在用漂亮词逃避追问? + +### 判断标准 + +- 扫描五大症状,列出本次输出中出现的所有 5 个症状,每个症状标 0/1(是否出现)。判停条件:如果 5 个症状全部 0,说明输出可能不是伪学者的;但要警惕"不知道自己不知道"的情况。( 执行步骤) +- 自检三问,每个问题都有"是/不是" + "为什么"。不要回避"是",诚实地承认伪学者症状。( 执行步骤) +- 找"最小可替换段落":至少标出 1 个段落,这个段落如果把"X 是天才" / "X 是 X 流派" / "X 反映了 X 倾向"中的具体词替换,整段就不成立。这种段落就是"伪学者段落",必须重写。( 执行步骤) +- 用"具体做了什么"代替"漂亮词":至少改写 1 段,把"X 很有灵气"改为"X 在段落 Y 中做了什么具体动作,产生了 Z 效果"。判停条件:改写后句子变长或变得不流畅,说明之前在用修辞掩盖空洞。( 执行步骤) + +## 操作步骤(执行流程) + +来源: 执行段五步。 + +1. **扫描五大症状** + - 完成标准:列出本次输出中出现的所有 5 个症状,每个症状标 0/1(是否出现)。 + - 判停条件:如果 5 个症状全部 0,说明输出可能不是伪学者的;但要警惕"不知道自己不知道"的情况。 +2. **自检三问(真诚回答)** + - 完成标准:三个问题每个都有"是/不是" + "为什么"。 + - 不要回避"是",诚实地承认伪学者症状。 +3. **找"最小可替换段落"** + - 完成标准:至少标出 1 个段落,这个段落如果把"X 是天才" / "X 是 X 流派" / "X 反映了 X 倾向"中的具体词替换,整段就不成立。 + - 这种段落就是"伪学者段落",必须重写。 +4. **用"具体做了什么"代替"漂亮词"** + - 完成标准:至少改写 1 段,把"X 很有灵气"改为"X 在段落 Y 中做了什么具体动作,产生了 Z 效果"。 + - 判停条件:改写后句子变长或变得不流畅,说明之前在用修辞掩盖空洞。 +5. **承认"我读得不够多"** + - 完成标准:在输出末尾加一句"以上评论基于我对 X 的有限阅读,可能有盲点"。 + - 这是福斯特自承"伪学者"姿态的现代版本。 + +## 案例全文 + +### 案例 1:加洛韦的"按天气分类小说"——伪学者的极端样本() + +- **问题**:一本文学小册子《小说素材与方法》按"天气在小说中的作用"分类小说。 +- **方法论的使用**:福斯特把它当作伪学者的极端样本,列出 9 种天气功能:装饰性、实用性、解说性、奠定和谐、反衬情绪、促发行动、产生控制性影响、主角、不存在。 +- **结论**:分类无意义,作者不得不承认"还需要一样东西,那就是天赋——了解九种天气分类对小说作者来说是没有用的,除非他也是个有天赋的人"。 +- **结果**:福斯特用此例说明伪学者的标志——分类学装置构造得越精美,越暴露理解的空。 + +### 案例 2:文学评论中的"天才崇拜"() + +- **问题**:很多人评论 X 作家时说"X 是天才"。 +- **方法论的使用**:福斯特诊断"他们是伪学者的好标本——他们总是热衷于谈论天赋,因为这个词一出口,就免除了深究意义的苦役"。 +- **结论**:"文学是天才们写就的。小说作者都是天才。瞧啊,就是这样,现在,我们开始为他们分类吧。"——这就是他们做的。 +- **结果**:此案例成为"天才崇拜"作为伪学者标志的经典诊断。 + +### 案例 3:司各特"按故事分类"评论() + +- **问题**:评论者说"X 作家是讲故事的高手"。 +- **方法论的使用**:福斯特诊断——"他说的东西或许都很准确,但毫无意义,因为他只是在书堆里打转,而非深入每一本之中,他要么就是根本没读过这些书,要么就是不得读书之法"。 +- **结论**:"会讲故事"是个"便携词",取代了对"讲了什么故事 / 怎么讲 / 为什么这样讲"的具体追问。 +- **结果**:福斯特借此把"会讲故事"从"正面评价"翻转为"伪学者的逃避"。 + +## 常见误区与失败模式 + +- **还没读完就分类**——"1847 年之前的书,1847 年之后的书"。() +- **用天赋逃避深究**——"文学是天才们写就的"。() +- **用"倾向"代替具体分析**——"X 反映了 Y 倾向"。() +- **用作者生平代替作品分析**——"X 因为 Y 童年经历才写出来"。() +- **把对象修饰得"很美"**——"X 很有灵气 / 很有格调"而说不出具体做了什么。() + +## 边界与盲点 + +不适用场景:() + +- **真正的历史/学术研究**——分类是合法的,不必扫描。 +- **初次接触新领域**——分类是脚手架,此时自检会阻碍学习。 +- **被要求快速输出**——自检需要时间,紧急情况不适用。 +- **评论者已经知道自己是新手**——这时扫描会显得居高临下。 + +作者盲点:() + +- **福斯特的"伪学者"自承是反讽姿态**——不要把它当成"我没学问"的谦虚,它是"我知道我的方法不够,但我选择用这种不够的方法换得自由"。 +- **现代主义巅峰期的视角**——1927 年;现代的数据驱动决策、循证医学、A/B 测试已经部分替代了"伪学者"批评。 +- **对"分类"的全盘否定过激**——某些分类(化学元素表、生物分类法)是真学问,不该被一并扫掉。 + +## 易混的邻近方法论 + +- **vs 批判性思维(Critical Thinking)**——伪学者自检更锋利,直接针对"分类学装置",批判性思维更一般化。() +- **vs 怀疑论(Skepticism)**——怀疑论质疑命题真假,伪学者自检质疑"评论姿态本身"。() +- **vs 知识谦逊(Intellectual Humility)**——知识谦逊是美德,伪学者自检是诊断;前者是心态,后者是工具。() +- **与 round-table 的区别**:伪学者自检是**反分类崇拜**的姿态,圆桌论是**反时间崇拜**的姿态。 +- **与 seven-aspects 的区别**:七侧面是**怎么建构分析**,伪学者自检是**怎么识别自己的分析是不是空的**。 + +## 中文落地 + +- 中文评论有自己的一套"便携词",同样要扫描: + - **翻译腔信号**——"被字句滥用""'的'字连缀过长""'进行 + 动词'堆砌""机翻式连接词(然而/因此/此外密集出现)"。诊断语言是否翻译腔,不能只贴"有翻译腔"标签,要指到具体句式和词。 + - **公文腔信号**——"'进行''开展''予以''进一步''不断''切实'等官样动词""'以……为抓手''落实''赋能'等套语""排比凑数、对仗堆砌"。公文腔是用程式化措辞代替具体描写。 + - **空泛赞美词**——"有灵气""有格调""有韵味""大气""细腻""直击心灵"。这些都是"漂亮代替准确",要改写成"作品在某段做了什么具体动作、产生什么效果"。 +- 落地写法(改写示范):把"这部小说很有灵气"改为"第 X 章用 Y 细节做了 Z,让读者产生 W 感受";改写后句子变长,恰好证明之前在用修辞掩盖空洞。 +- 自检三问在中文语境同样适用:我真的读完全文了吗?我在用"流派/倾向/时代背景"掩盖理解吗?我在用漂亮词逃避追问吗? diff --git a/framework/catalog/pi/skills/novel-diagnosis/references/round-table.md b/framework/catalog/pi/skills/novel-diagnosis/references/round-table.md new file mode 100644 index 0000000..6ff3998 --- /dev/null +++ b/framework/catalog/pi/skills/novel-diagnosis/references/round-table.md @@ -0,0 +1,118 @@ +# 比较诊断:抹掉标签再并置——圆桌论 + +来源: + +这是福斯特的评审纪律之一,用于"把自己的作品与参照作品比差距"或"跨时代、跨流派比较"。核心动作:把所有时代、所有流派的样本"同时"放进一间圆形大房间并置阅读,故意切断时间线,让比较基于"做了什么"而非"何时写的"。 + +## 原文摘录 + +> "我们不妨想象所有小说作者是同时坐在一个圆形大房间里工作吧。在展示作品文字之前我不会提及他们的名字, 因为名字总难免附带着年代、传言等等所有我们正打算丢弃的'废牌'。" + +> "我们绝不可凝望时间的长河。另一种场景更适合我们的能力, 也就是说, 让所有小说作者同时提笔写作。" + +> — E. M. 福斯特, 《小说面面观》第一讲 绪论 + +() + +## 方法规则 + +跳出编年/年代视角,把所有时代、所有国籍的样本"同时"放到同一间圆形大房间里并置阅读。**故意切断时间线**,通过"两两成组的盲文对比"逼出概念的边界。() + +核心操作: + +1. **承认"年代视角"是污染源**——当我们说"这本书是 19 世纪的",已经带上了"过气了""经典但陈旧"等光环,这些光环让我们无法纯粹地看它做了什么。 +2. **把所有样本"匿名化"地放在一起**——不提作者名字、年代、流派,只看作品本身的文字。 +3. **两两配对做盲文对比**——福斯特反复使用此技巧:把"两位完全不同的作者"的两段文字并置,让读者先感受共性,再揭示作者(理查森 vs 詹姆斯 / 威尔斯 vs 狄更斯 / 伍尔夫 vs 斯泰恩)。 +4. **"历史滚滚向前,艺术恒久不变"作为隐含前提**——福斯特断言:人性在四百年内不发生质变,因此跨时代比较有合法性。这是此方法论的**信念前提**,不是证明。 +5. **接受代价:严格历史研究做不了**——圆桌论"无法检验传统","也无法维护传统",牺牲了考据能力换得概念穿透力。 + +关键认识:圆桌论是一种**故意"浅薄"的方法论**。福斯特自承"我读得不够多,装备不足",因此选择放弃权威,换得自由。读者模仿此方法时,也要接受"我看到的不是全部"这个限制。() + +### 判断标准 + +- 选 2-5 个跨时代/跨流派的样本,至少 2 个样本来自不同时代或流派;优先选"看起来毫不相关"的,强迫自己找共性。( 执行步骤) +- 摘录 2-3 段关键文字,不署作者、不署年代,单纯并置。判停条件:如果发现"摘录时已经选了对某作者有利的段落",重选。( 执行步骤) +- 让读者先感受共性,再揭示作者。揭示后问:"时间标签改变你的判断了吗?为什么?"( 执行步骤) +- 承认代价:圆桌论放弃严格历史研究,能看到概念穿透,但看不到影响、流派、传承。( 执行步骤) + +## 操作步骤(执行流程) + +来源: 执行段五步。 + +1. **承认"年代视角是污染源"** + - 完成标准:明确说出"我们被'X 时代' / 'X 流派'的标签干扰,让我们先去掉这些标签"。 +2. **选 2-5 个跨时代/跨流派的样本** + - 完成标准:至少 2 个样本来自不同时代或流派。 + - 提示:选样本时优先选"看起来毫不相关"的,强迫自己找共性。 +3. **匿名并置样本的关键段落** + - 完成标准:摘录 2-3 段关键文字,不署作者、不署年代,单纯并置。 + - 判停条件:如果发现"摘录时已经选了对某作者有利的段落",重选。 +4. **让读者先感受共性,再揭示作者** + - 完成标准:问"如果不知道作者是谁,你会怎么比较?" + - 揭示作者后,再问"时间标签改变你的判断了吗?为什么?" +5. **承认圆桌论的代价** + - 完成标准:明确说"圆桌论放弃严格历史研究,我们能看到的概念穿透,但看不到影响、流派、传承"。 + +## 案例全文 + +### 案例 1:弗吉尼亚·伍尔夫 斯泰恩《项狄传》——同一束幻想之光() + +- **问题**:伍尔夫(1917)和斯泰恩(1759)看似毫无关系,凭什么放在一起? +- **方法论的使用**:福斯特匿名并置两段文字,让读者先感受到"两人都从一个小物事开始任意翱翔,然后回归",才揭示作者。 +- **结论**:两人在 150 年间共享同一种"幻想"笔法。 +- **结果**:圆桌论证明——时间标签在这里无意义,"做了什么"是唯一有效的比较单位。 + +> 《项狄传》在幻想典型角度下的案例见 references/fantasy-prophecy.md 案例 1("混乱神"、接受现实不连贯),角度不同,两处都保留。 + +### 案例 2:威尔斯 狄更斯《远大前程》——同一对葬礼() + +- **问题**:两场葬礼,一场 1910,一场 1861,看似无关。 +- **方法论的使用**:福斯特匿名并置两段描述葬礼的段落,让读者看到"两人都用细节引人入胜、都厌恶虚伪、都把幽默与社会批评结合"。 +- **结论**:威尔斯和狄更斯有相同的"视角和技巧"(比较两个花瓶和两个玻璃樽)。 +- **结果**:圆桌论证明——时代相近的两人在 49 年间共享了同样的写作姿态。 + +### 案例 3:哈代 司各特《威弗莱》——同样的命运凌驾人物() + +- **问题**:哈代(1903)和司各特(1814)命运悲剧的处理方式相同还是不同? +- **方法论的使用**:福斯特用圆桌论比较两人的"命运凌驾人物"手法,跨 89 年仍发现同样问题。 +- **结论**:这是"情节的过度胜利"这一失败模式的跨时代存在。 +- **结果**:圆桌论能识别**失败模式的跨时代一致性**,比"哈代学司各特"的简单历史叙事更准确。 + +> 哈代"命运凌驾人物"在拉锯失败角度下的案例见 references/plot-character.md 案例 1,角度不同,两处都保留。 + +## 常见误区与失败模式 + +- **天才崇拜**——"文学是天才们写就的",拒绝并置。() +- **倾向崇拜**——"用'倾向'一词代替真思考"。() +- **编年学家误用**——把"流派的形成"和"创作行为的本质"混淆。() +- **按天气分类**——伪学者把小说按"天气在故事中的作用"分类。() + +## 边界与盲点 + +不适用场景:() + +- **需要严格历史研究**——"X 是怎么影响 Y 的",圆桌论回答不了。 +- **需要时效性建议**——"X 股票明天会涨吗",圆桌论完全不适用。 +- **被比较的样本属于同一时代/流派**——没有跨时代/跨流派时,普通对比即可,圆桌论是杀鸡用牛刀。 +- **对象本身强烈受时间影响**——比如"Unix 哲学在 1970s vs 2020s 的不同",这种时间维度本身就是对象的一部分。 + +作者盲点:() + +- **"人性四百年不变"是信念,不是证明**——福斯特承认"蟹行"运动可能缓慢到两百年内看不到,但他选择"以人性不变为前提"。 +- **圆桌论的"自由"是有限制的**——福斯特读得不够多(他自承),因此"他选择的方法刚好符合他的能力",不一定符合所有人。 +- **现代主义巅峰期的视角**——1927 年;没看到 60 年代后的拉美魔幻、后现代拼贴、亚非作家。 + +## 易混的邻近方法论 + +- **vs 文学比较研究(Comparative Literature)**——圆桌论是"反方法的姿态",比较文学是"有方法论的学科"。() +- **vs 文学史(Literary History)**——圆桌论刻意回避文学史,文学史刻意构建文学史。() +- **vs 经典化(Canonization)**——圆桌论不是"选经典",是"看所有样本"。() +- **与 seven-aspects 的区别**:圆桌论是**怎么比较样本**(方法论),七侧面是**怎么拆解一个样本**(分析框架)。 +- **与 quack-scholar-check 的区别**:圆桌论是**反时间崇拜**的姿态,伪学者自检是**反分类崇拜**的姿态。 +- **与"历史研究"的区别**:圆桌论**明确放弃**严格历史研究能力,换得概念穿透。 + +## 中文落地 + +- 圆桌论特别适合中文语境的诊断:把自己的稿子和《红楼梦》《儒林外史》《金瓶梅》或现代网文、类型小说的段落抹掉年代标签并置,只比"做了什么"(怎么开场、怎么让人物登场、怎么收尾),避免"这是古典的/这是网文的"这类标签先入为主。 +- 中文文学史常被"朝代分期"绑架(唐传奇、宋话本、明清章回、五四新文学、当代网络文学),圆桌论的匿名并置可以穿透这些分期,看具体手法是否真的高下立判。 +- 代价同样适用:圆桌论看不出"谁影响了谁"。中文作品的师承、流派问题(如某作家是否学某家)要靠文学史研究,圆桌论不负责。 diff --git a/framework/catalog/pi/skills/novel-diagnosis/references/story-plot.md b/framework/catalog/pi/skills/novel-diagnosis/references/story-plot.md new file mode 100644 index 0000000..8d792d6 --- /dev/null +++ b/framework/catalog/pi/skills/novel-diagnosis/references/story-plot.md @@ -0,0 +1,123 @@ +# 结构层透镜:是故事还是情节——问"后来呢"还是问"为什么" + +来源: + +这是福斯特对叙事结构层的诊断透镜:一部作品(或一个章节)现在激发的到底是好奇心("后来呢?")还是因果理解("为什么?")。故事层只要好奇心,情节层另要头脑和记忆力。这是一个可主动切换的提问法,既能用来分析别人作品,也能用来自检自己写的章节。 + +## 原文摘录 + +> "'国王死了, 接着王后也死了', 这是故事。'国王死了, 王后悲伤过度, 也死了', 这是情节。时间顺序仍在, 但更凸显的是其中蕴含的因果关系。" + +> "以'王后之死'为例, 如果这是个故事, 我们会问: '然后呢?' 如果是个情节, 我们的问题则是: '为什么?'" + +> "好奇心是人类最低级的本能之一 …… 一个会问你有多少兄弟姊妹的人绝不会是个讨人喜欢的家伙 …… 要掌握'情节', 我们必须调动头脑和记忆力。" + +> — E. M. 福斯特, 《小说面面观》第二讲 / 第五讲 + +() + +## 方法规则 + +区分两个层次的叙事提问:**故事只需要好奇心**(问"后来呢"),**情节还需要头脑和记忆力**(问"为什么")。这是个可主动切换的提问法,不仅用于分析,还用于写作。() + +核心操作: + +1. **故事 = 时间顺序的事件流**——"国王死了,然后王后死了"——只要记住时间线就够,不需要联系。 +2. **情节 = 因果关系的网络**——"国王死了,因此王后悲伤过度也死了"——必须把当下事实与前文联系起来。 +3. **提问切换作为诊断**——当你问"然后呢",你在故事层;当你问"为什么",你在情节层。这个切换不消耗,但能精准告诉你当前在哪一层。 +4. **情节需要三个条件**: + - **头脑**:把事实与前文联系起来看,容许暂时不理解 + - **记忆力**:每个举动、每个词都有意义,无冗余 + - **悬念**:制造时序断裂 + 重新整合 +5. **故事与情节不互相排斥**——优秀小说同时需要两者。先用故事把读者拉进来(激发好奇心),再用情节满足读者(调动头脑)。 + +关键认识:故事是低等但不可或缺的;情节是高等但有代价。"你只想要故事 → 像山鲁佐德的暴君丈夫那样,听完就忘;你只想要情节 → 智力有余但缺入口"。两者平衡是写作的关键。() + +### 判断标准 + +- 标出最近 5 个提问,看是"然后呢"还是"为什么":全是"然后呢"→ 叙事停留在故事层;至少 2 个"为什么"→ 进入情节层。( 执行步骤) +- 故事层健康的标志:读者/听众想继续听下去。失败征兆:读者走神、中途放弃、只记得"我读了 200 页,啥也没记住"。( 执行步骤) +- 情节层健康的标志:至少 2 个关键事实/事件有"为什么"被揭示,至少 1 处"悬念"被设计(时序断裂 + 重新整合)。失败征兆:读者/听众"看完就忘,想不起发生了什么","作者/讲者的话很漂亮但没有逻辑"。( 执行步骤) + +## 操作步骤(执行流程) + +来源: 执行段五步。 + +1. **识别当前叙事的"提问"在哪一层** + - 完成标准:标出最近 5 个提问,至少 3 个是"然后呢"还是"为什么"。 + - 判停条件:如果全部是"然后呢",叙事停留在故事层;如果有至少 2 个"为什么",进入情节层。 +2. **检查故事层是否健康** + - 完成标准:故事层是否做到了"读者/听众想继续听下去"?如果是"听不下去",是故事层问题(事件流不吸引)。 + - 故事层失败的征兆:读者走神、中途放弃、只记得"我读了 200 页,啥也没记住"。 +3. **检查情节层是否健康** + - 完成标准:至少 2 个关键事实/事件有"为什么"被揭示,至少 1 处"悬念"被设计(时序断裂 + 重新整合)。 + - 情节层失败的征兆:读者/听众"看完就忘,想不起发生了什么","作者/讲者的话很漂亮但没有逻辑"。 +4. **诊断失衡** + - 完成标准:判断是"故事过强,情节过弱"(如司各特)还是"情节过强,故事过弱"(如梅瑞狄斯某些篇)。 + - 反模式:故事过强 → 像山鲁佐德丈夫的"暴君",听完就忘;情节过强 → 像纯学术论文,智力有余但缺入口。 +5. **给出修复建议** + - 完成标准:至少 1 条具体修改(如"加入一段倒叙,把'国王为什么死'揭示出来,调动读者的头脑")。 + - 不要空话(如"加强情节")——给可操作修改。 + +## 案例全文 + +### 案例 1:司各特《古董商人》——故事 = 绦虫式时间叙述() + +- **问题**:司各特为什么会讲故事。 +- **方法论的使用**:福斯特逐句分析《古董商人》开篇,说明故事靠"然后呢"运作,每个新人物(埃迪·奥奇特里、亚瑟·沃德杜尔、格里兹尔小姐)都被引入只是为了"让事件一个接着一个发生"。 +- **结论**:司各特是"故事"大师,但牺牲了"激情"和"思想"。 +- **结果**:借此福斯特区分"故事高手"和"小说家"——前者只满足好奇心,后者同时满足好奇心和头脑。 + +### 案例 2:梅瑞狄斯《利己主义者》——情节设计的高手() + +- **问题**:梅瑞狄斯为什么被称为"英国小说诞生以来最出色的情节设计师"。 +- **方法论的使用**:福斯特用雷蒂西亚·黛尔的"心境转变隐藏"作为情节设计的典范——她的心理过程不能提前揭示,否则"高雅喜剧"就毁了。 +- **结论**:情节的胜利要求"瞒着读者",让人物为情节暂时让步。 +- **结果**:与哈代形成对比——哈代让人物为情节做出太多牺牲,人物被耗尽;梅瑞狄斯懂得节制。 + +> 同一人物(雷蒂西亚·黛尔)在情节-人物拉锯角度下的案例见 references/plot-character.md 案例 2(拉锯节制),角度不同,两处都保留。 + +### 案例 3:贝内特 托尔斯泰《战争与和平》——故事/情节角度简注() + +- **问题**:两本都写时间,为什么后者伟大,前者"失于伟大"? +- **方法论的使用**:福斯特比较——贝内特只展开"时间生活"(故事 + 时间维度),托尔斯泰同时展开"时间生活"和"空间感"(情节的因果 + 空间的张力)。 +- **结论**:贝内特"有时间,没价值";托尔斯泰"有时间,有价值,有空间"。 +- **结果**:借此说明——优秀小说不是单侧面(时间故事)的极致,而是多侧面的平衡。 + +> 同一对比的动态平衡角度全文案例见 references/dimension-frameworks.md 案例 4,时间/价值角度全文案例见 references/time-value.md 案例 1、2。角度不同,多处保留;本处是故事/情节结构层的简注。 + +## 常见误区与失败模式 + +- **故事 → 情节的胜利代价**——梅瑞狄斯式的"情节胜出"必须节制,否则人物被耗尽(夏洛蒂·勃朗特式偷走人物"知无不言")。() +- **情节 → 命运的过度胜利**——哈代式,人物被命运凌驾,失去"人之为生灵所做出的努力"(哈代式命运凌驾)。() +- **戏剧化的小说**——把亚里士多德三步骤硬套到所有小说,牺牲小说的开放性。() +- **只想要故事**——山鲁佐德的暴君丈夫,听完就忘(高尔夫球手式"故事 > 一切")。() + +## 边界与盲点 + +不适用场景:() + +- **纯新闻速报**——时间流本身就是内容(如"今天发生了 X、Y、Z"),不需要因果。 +- **菜谱/操作指南**——步骤本身就是内容,不需要因果(除非涉及"为什么先放盐后放糖"等原理)。 +- **纯娱乐八卦**——八卦就是要"然后呢"的故事层,情节太重反而无趣。 +- **紧急通知**——"X 系统挂了,请立即重启"——故事就是内容。 + +作者盲点:() + +- **现代主义巅峰期的视角**——1927 年;当时还没有"信息图/视频/数据可视化"等更现代的叙事形态,故事/情节二分以文字为基础。 +- **对"悬念"的诊断不够展开**——福斯特用"悬念"作为情节的关键,但没深入讨论"悬疑小说"(Whodunit)这种特殊形态。 +- **西方文学中心的视角**——引用的案例几乎全是英美欧陆小说;东方文学(如中国章回小说、日本物语)的"故事 vs 情节"结构未被充分讨论。 + +## 易混的邻近方法论 + +- **vs 戏剧结构(Dramatic Structure:三幕剧/起承转合)**——福斯特明确反对硬套戏剧结构到小说。() +- **vs 5W1H / 金字塔原理**——这些是"如何组织汇报"的工具,不区分"故事"和"情节"。() +- **vs Hero's Journey(英雄之旅)**——这是个特定的"情节模型",不涵盖"故事"层。() +- **与 time-vs-value-life 的区别**:故事/情节二分是**叙事结构层**,时间/价值二分是**生活/意义层**;前者管"读起来的感觉",后者管"活起来的感觉"。 +- **与 plot-character-tug 的区别**:故事/情节是**单方面的诊断**,情节-人物拉锯是**双方面的张力诊断**。 + +## 中文落地 + +- 章回小说天然强在故事层:"欲知后事如何,且听下回分解"的回末套语就是"后来呢"的钩子,故事层资源是现成的。诊断中文古典式作品先别急着骂"只有故事",要问故事层是否健康(读者想不想听下去)。 +- 中文作品的情节层("为什么")常藏在对偶回目、草蛇灰线的伏笔里,不在显性因果句里。诊断时把回末悬念逐个标记,区分"只勾'后来呢'的"和"勾'为什么'的",再看两类钩子的比例。 +- "故事过强"在中文语境里的典型症状是章回体式的连环事件堆叠(一个接一个桥段,读者只记"后来呢");"情节过强"的典型症状是推理化、概念化的小说——因果讲得滴水不漏,但读者进不了门。 diff --git a/framework/catalog/pi/skills/novel-diagnosis/references/time-value.md b/framework/catalog/pi/skills/novel-diagnosis/references/time-value.md new file mode 100644 index 0000000..5cc11c6 --- /dev/null +++ b/framework/catalog/pi/skills/novel-diagnosis/references/time-value.md @@ -0,0 +1,122 @@ +# 意义层透镜:有时间,有没有价值——时间生活 vs 价值生活 + +来源: + +这是福斯特对叙事意义层的诊断透镜:一部作品(乃至一次体验、一场会议、一段关系)处于"时间堆积"(低强度的时间堆叠,如流水账)还是"价值峰值"(高强度的体验,即使短暂也值得)。故事/情节透镜管"读起来的感觉",这个透镜管"活起来的感觉"。 + +## 原文摘录 + +> "无论日常生活的真实面目如何, 它其实都是由双重生活所构成的, 亦即, 时间维度的生活与价值维度的生活。我们的行为泄露了我们的双重忠诚。'我只看了她五分钟, 可那是值得的。'在这么一个简单的句子里, 你便表达了双重的忠诚。" + +> "所谓'故事', 就是讲述时间维度里的生活。扩展到完整的'小说', 则同时还应当包含价值维度的生活, 需要用到的工具我们将在以后谈到。它同样提供双重的忠诚。" + +> — E. M. 福斯特, 《小说面面观》第二讲 故事 + +() + +## 方法规则 + +日常生活/叙事/产品/关系的**二元分解**:时间生活(按"分钟/小时"测量,关心"在什么之前/之后"——线性序列)与价值生活(按"强度/高度"测量,关心"我看了她五分钟,可那是值得的"——非线性,摆脱暴君式的时钟)。() + +核心操作: + +1. **承认"双重生活"是常态**——任何体验/叙事/产品,都同时处于时间轴和价值轴上。两者不是非此即彼,是**双重忠诚**。 +2. **时间轴的可诊断征兆**: + - "我花了 X 时间"(不带任何价值判断) + - "我熬过了 X 分钟" + - "X 天都在做 Y" + - "流水线 / 流水账 / 同样的事情一遍又一遍" +3. **价值轴的可诊断征兆**: + - "X 真的值得" + - "我看了她五分钟,可那是值得的" + - "那一瞬间我感到..." + - "改变了我对 Y 的看法" +4. **小说/叙事的"双重忠诚"**——好的叙事既给读者时间享受(故事),又给读者价值享受(情节、人物、幻想、预言、模式、节奏)。单侧面的极致是失衡。 +5. **"价值生活"≠ 主观偏好**——它有客观成分,如"我愿意为它付出代价(哪怕短暂)"/"它让我在事后还回想"。 + +关键认识:价值生活不能脱离时间生活存在(你必须花时间才能有体验),但时间生活可以脱离价值生活存在(无意义的时间堆积)。后者是消磨,前者是体验。() + +### 判断标准 + +- 时间轴过强的征兆:单纯堆叠事件,没有强度/高度变化。( 执行步骤) +- 价值轴过弱的征兆:体验平淡,事后不回想,没有"超越'当然'的底蕴"。( 执行步骤) +- 失衡方向三分:时间轴过强(消磨)/ 价值轴过强(稀缺)/ 平衡良好(双重忠诚)。( 执行步骤) + +## 操作步骤(执行流程) + +来源: 执行段五步。 + +1. **承认"双重生活"是起点** + - 完成标准:明确说出"任何体验都同时处于时间轴和价值轴,我们做的是双重忠诚的诊断"。 +2. **诊断时间轴** + - 完成标准:列出"我花了 X 时间在 Y 上"等时间堆积症状,至少 1 条。 + - 时间轴过强的征兆:单纯堆叠事件,没有强度/高度变化。 +3. **诊断价值轴** + - 完成标准:列出"我感到...","那一刻...","X 改变了我"等价值峰值征兆,至少 1 条。 + - 价值轴过弱的征兆:体验平淡,事后不回想,没有"超越'当然'的底蕴"。 +4. **判断失衡方向** + - 完成标准:明确说"时间轴过强(消磨)/ 价值轴过强(稀缺)/ 平衡良好"。 + - 反模式:时间轴过强 → 消磨;价值轴过强 → 短暂但不可持续;平衡 → 双重忠诚。 +5. **给出修复建议** + - 完成标准:至少 1 条具体修改(如"在长会议中加 1 个'价值峰值'瞬间——一个故事 / 一个对比 / 一个让听众愣住的细节")。 + - 不要空话(如"提高会议质量")——给可操作修改。 + +## 案例全文 + +### 案例 1:贝内特《老妇人的故事》——时间生活的极致() + +- **问题**:贝内特写索菲亚和康斯坦斯从童年到老年的消亡,时间成为真正的主角。 +- **方法论的使用**:福斯特诊断——这本书"有力、真挚、悲伤,却依旧不免失于伟大",因为"它没有'当然'之上的底蕴",只有时间生活,没有价值生活。 +- **结论**:贝内特的"时间生活"做到了极致(索菲亚死、康斯坦斯死、老狗艰难爬去看食盆),但缺乏"超越'当然'的底蕴"。 +- **结果**:借此福斯特区分"健全完整的真实"(贝内特)vs "伟大的真实"(托尔斯泰)。 + +### 案例 2:托尔斯泰《战争与和平》——空间感 = 价值生活() + +- **问题**:为什么托尔斯泰不让人沮丧,贝内特让人沮丧? +- **方法论的使用**:福斯特诊断——托尔斯泰在时间维度外**拓展出了空间维度**,"空间感是令人振奋的,它拥有类似音乐的力量";贝内特只有时间。 +- **结论**:空间感 = 价值生活的一个具体形态,它让读者"穿行在俄罗斯大地"时"和弦宏伟嘹亮"。 +- **结果**:借此福斯特把"价值生活"具象化为"空间 / 音乐 / 美感"。 + +### 案例 3:山鲁佐德的"故事" vs "情节"——时间/价值的实际例子() + +- **问题**:山鲁佐德为什么能活下来? +- **方法论的使用**:福斯特诊断——山鲁佐德的故事"只是为了活下去"的时间序列("后来呢?然后呢?还有吗?"),但她故事的"价值"在于"她的言辞优雅细腻、观点开明宽容、情节巧妙新颖、德行高尚美好"。 +- **结论**:山鲁佐德"用故事(时间生活)喂饱暴君的好奇心,用情节(价值生活)真正打动他"。 +- **结果**:借此说明,即使在"最底层的讲故事"场景中,价值生活也已经存在——没有纯粹的"时间"。 + +> 贝内特 vs 托尔斯泰这对案例在动态平衡角度下见 references/dimension-frameworks.md 案例 4,在故事/情节角度下的简注见 references/story-plot.md 案例 3。角度不同,多处保留。 + +## 常见误区与失败模式 + +- **只有时间生活**——贝内特式,"失于伟大"(贝内特式只有时间维度)。() +- **试图彻底砸碎时间**——格特鲁德·斯坦因式,失败(斯坦因式彻底打碎时间)。() +- **强行让时间生活 = 价值生活**——伪学者的"按时间分类"。() + +## 边界与盲点 + +不适用场景:() + +- **真正需要时间记录的对象**——如工作时长、专注度计时,时间本身就是数据。 +- **完全没时间投入的"白嫖"判断**——"我 X 都没花过时间,凭啥评价"——此时时间/价值二分不适用。 +- **必须以时间为唯一指标的场景**——如工作薪酬计算,时间就是钱的单位。 +- **紧急事件**——"X 系统挂了",时间就是全部。 + +作者盲点:() + +- **"双重生活"的二分太干净**——现代神经科学发现"价值感"和"时间感"在脑中相互调制,不是两个独立维度。 +- **以小说为原型,未必适用所有叙事**——短视频、播客、信息图、互动叙事等新形态的"时间/价值"关系可能更复杂。 +- **未充分讨论"价值生活"的多样性**——福斯特把"价值"具象化为"空间/音乐/美感",但"道德价值"/"实用价值"/"情感价值"等未被分别讨论。 + +## 易混的邻近方法论 + +- **vs 体验经济/体验设计**——Pine & Gilmore 的"体验经济"以"消费体验"为单位,时间/价值二分更基础。() +- **vs 心流/巅峰体验**——Csikszentmihalyi / Maslow 的"高峰体验"是个体心理状态,时间/价值二分是"诊断工具"。心流是"完全沉浸"的状态,时间/价值二分是"体验是否有意义"的诊断;心流常落入价值峰值,但也有不进入心流的价值峰值。() +- **vs 工作-生活平衡**——后者是"工作 vs 私人时间"的比例,时间/价值二分是"任何时间是否有价值"的诊断。() +- **与 story-vs-plot 的区别**:时间/价值二分是**意义层**,故事/情节二分是**结构层**;前者管"活起来的感觉",后者管"读起来的感觉"。 +- **与 expansion-vs-completion 的区别**:时间/价值是**对体验的诊断**,扩展/完成是**对作品终点的姿态**;前者管中间,后者管结尾。 + +## 中文落地 + +- 时间/价值两轴在中文叙事里同样适用。章回小说的"且听下回分解"是时间轴的牵引(让人想知道后来呢),价值峰值则常出现在"停下来不走"的段落:诗词、曲赋、即景联句、一场戏的工笔细描。诊断中文作品时问:"除了事件流,有没有让人事后回想的段落?" +- 中文网文连载天然拉长"时间轴"(日更、追更),诊断时尤其要警惕时间堆积——"我追了三百章"本身不是价值;要找出全书的价值峰值(读者事后仍会引用的场面、台词、意象),找不到即时间堆积。 +- 修复方向在中文语境里可落地为:在长事件流中插入一个价值峰值瞬间——一个让读者愣住的细节、一段停下来细写的场面、一句能被引用的话。不要空喊"提升深度"。 diff --git a/framework/catalog/pi/skills/prose-craft/SKILL.md b/framework/catalog/pi/skills/prose-craft/SKILL.md new file mode 100644 index 0000000..1eb9605 --- /dev/null +++ b/framework/catalog/pi/skills/prose-craft/SKILL.md @@ -0,0 +1,76 @@ +--- +name: prose-craft +description: | + 中文小说的语言与修辞领域:写稿或改稿时调整句子层与段落层的文本。激活场景:段落读起来单调催眠,句长或主谓位置需要诊断;满纸抽象,读者既看不见也摸不着,怀疑卡在官僚话、套话、公文腔;重大场景(死亡、战争、重病)用力过猛,或日常场景没有文气;抒情太直白变滥情;想用白描立人物;文本或人物温度不稳、没有辨识度;风格漂移,想逐根杠杆诊断声音。 + 关键 trigger:"句法节奏" / "主谓先行" / "右分支句" / "句长" / "模式转折" / "boom boom bang" / "翻译腔" / "抽象梯子" / "太抽象" / "能给我个例子吗" / "给我个例子" / "由抽象到具体" / "怎么写得有深意" / "用力过猛" / "修辞密度" / "克制" / "back off" / "show off" / "抒情" / "滥情" / "白描" / "基础体温" / "声音均衡器" / "graphic equalizer" / "风格漂移" / "风格诊断" / "找到自己的声音" / "三十个杠杆"。 + 不适用于:诗歌;实验文学与故意打破语法的项目;翻译文本(应保留原语节奏);纯动作戏(无抽象层与修辞校准需求);公文、教科书、工具书、学术论文、商业文案等非叙事文体。 + 与 show-and-omission 交接:「太抽象 / 读者看不见」若主要是情绪/性格标签堆叠,归后者做标签→场景;本 Skill 管句段修辞、句长、修辞密度与声音杠杆。 +--- + +# 语言修辞(prose-craft) + +给中文小说的语言装上一组可调的旋钮:句子节奏、抽象层级、修辞密度、情感出口、白描立人、文本体温、声音杠杆,每个方法都落到可执行的操作与判断标准。 + +## 方法索引 + +### 调整句子节奏 +- **主谓先行**:默认主谓放句首当火车头拉车厢,主谓远置只留给悬念、发现、庄重场景。 → references/sentence-rhythm.md +- **句长控速**:长句载着读者走,短句踩刹车,五种句长各有战略目的,相邻五句不许单轨。 → references/sentence-rhythm.md +- **翻译腔检测**:查"是"字句、被动语态、长定语后置三个信号,英语方法按"先动作后修饰"和逗号节奏在中文落地。 → references/sentence-rhythm.md + +### 安放抽象与具体 +- **下梯子**:问"能给我一个例子吗",从抽象词下到看得见摸得着的物。 → references/abstraction-ladder.md +- **上梯子**:问"那是什么意思",从琐碎的物上到一句能被引用的判断。 → references/abstraction-ladder.md +- **中段自检**:官僚话、套话、四字格、意境堆叠都是困在梯子中段,读者既看不见也摸不着。 → references/abstraction-ladder.md + +### 校准场景修辞 +- **退一步与进一步**:修辞密度与主题温度成反比,重场景克制、轻场景炫技,用 1-10 温度计评分并以广岛幸存者检验自查。 → references/rhetoric-density.md +- **先建模式再打破**:平行铺陈后在结尾换一词,通篇克制后破例靠近一次,句法层与情感层是同一门手艺。 → references/pattern-and-break.md + +### 处理情感 +- **抒情不抒发**:不写"我多么 X",写一个动作,小说家只传递情感不宣告。 → references/lyric-restraint.md +- **情感段密度**:冷段七成、温段两成、热段一成,热段不连续超过两段。 → references/lyric-restraint.md + +### 用最少字立人 +- **白描**:不写"他很 X",写一个等于 X 的动作,删虚词,检验动作代表性与动态密度。 → references/plain-description.md + +### 诊断与调校风格 +- **基础体温**:文本写最惨与最美的事时的默认温度就是辨识度,人物各有体温,温度反差即戏。 → references/base-temperature.md +- **声音均衡器**:风格是约三十根杠杆的合成设定而不只是用词,逐根标注、对照基线、一次只调一到三根。 → references/voice-equalizer.md + +## 引用索引 + +| 文件 | 覆盖内容 | +|---|---| +| references/sentence-rhythm.md | 句法节奏三轴:主谓先行、句长控速、模式转折(轴 2 指针),翻译腔检测与中文落地,失败模式 | +| references/abstraction-ladder.md | 抽象梯子上下爬、中段陷阱、Matalene 诊断、中文中段信号(文言腔、四字格、公文腔、意境陷阱) | +| references/rhetoric-density.md | 修辞密度与主题温度成反比、主题温度计、广岛/Koch/斯皮尔伯格对照、中文三家对照与网文规则并存 | +| references/pattern-and-break.md | 先建稳模式再打破一处:句法层模式转折 + 情感层克制中的破例,两书合并一条 | +| references/lyric-restraint.md | 抒情不抒发、抒情信号词、情感翻译成动作、情感段密度 70/20/10、用"懂"代替"说" | +| references/plain-description.md | 白描:拒绝形容词、虚词清理、动作代表性、动态密度,蒲松龄/鲁迅/海明威案例 | +| references/base-temperature.md | 基础体温:作家体温分类表、人物体温、温度一致性、温度反差即戏、温度定位技法 | +| references/voice-equalizer.md | 声音均衡器:三十杠杆清单、E.B. White 与海明威/菲茨杰拉德案例、调音三步、中文杠杆补充 | + +## 脚本 + +- references/revision-checklist.md —— 语言修辞改稿清单:句子、梯子、温度、情感、白描、体温、杠杆七遍逐项自查,附三十杠杆基线台账模板。 + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 红线 + +- 只给当前创作阶段的建议,不越权改设定主权、不绕过检测链、不复制粘贴其它 Skill 的 owner 定义。 +- 无用户明确授权不得替用户定稿或提交 Git。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/pi/skills/prose-craft/references/_coverage.md b/framework/catalog/pi/skills/prose-craft/references/_coverage.md new file mode 100644 index 0000000..7ae0157 --- /dev/null +++ b/framework/catalog/pi/skills/prose-craft/references/_coverage.md @@ -0,0 +1,15 @@ +# prose-craft 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| bifeiyu-novel-skill/bifeiyu-base-temp | references/base-temperature.md | +| bifeiyu-novel-skill/bifeiyu-lyric-pass | references/lyric-restraint.md | +| bifeiyu-novel-skill/bifeiyu-lyric-pass | references/pattern-and-break.md | +| bifeiyu-novel-skill/bifeiyu-paiban | references/plain-description.md | +| writing-tools-clark/back-off-show-off | references/rhetoric-density.md | +| writing-tools-clark/ladder-of-abstraction | references/abstraction-ladder.md | +| writing-tools-clark/sentence-rhythm | references/sentence-rhythm.md | +| writing-tools-clark/sentence-rhythm | references/pattern-and-break.md | +| writing-tools-clark/voice-equalizer | references/voice-equalizer.md | diff --git a/framework/catalog/pi/skills/prose-craft/references/abstraction-ladder.md b/framework/catalog/pi/skills/prose-craft/references/abstraction-ladder.md new file mode 100644 index 0000000..3df5f73 --- /dev/null +++ b/framework/catalog/pi/skills/prose-craft/references/abstraction-ladder.md @@ -0,0 +1,123 @@ +# 抽象梯子:在"看见"与"理解"之间上下爬 + +> 来源:《写作工具》(Roy Peter Clark《Writing Tools》)ladder-of-abstraction —— Tool 22 "Climb up and down the ladder of abstraction",借用 S. I. Hayakawa《Language in Thought and Action》的抽象梯子模型。 +> 中文中段信号(文言腔、四字格、公文腔、意境陷阱)为中文适配内容,单独成节。 + +## 原文摘录(全量) + +以下引文均出自。 + +> Beware of the middle, the rungs of the ladder where bureaucracy and technocracy lurk. Halfway up, +> teachers are referred to as full-time equivalents, and school lessons are called instructional +> units. … Carolyn Matalene taught me that when I write prose that the reader can neither see nor +> understand, I'm probably trapped halfway up the ladder. +> +> — Roy Peter Clark, *Writing Tools* (Tool 22, quoting S. I. Hayakawa's *Language in Thought and Action*) + +> Two questions will help you make this tool work. "Can you give me an example?" will drive the +> speaker down the ladder. But "What does that mean?" will carry him aloft. +> +> — Roy Peter Clark, *Writing Tools* (Tool 22) + +## 方法骨架 + +Clark 借 Hayakawa 的"抽象梯子"作为最核心的认知模型之一: + +- **梯子是垂直的**——从底部**感官可触的具体物**("沾血的刀"、"啤酒拉环"、"念珠")到顶部**指向意义的抽象词**("自由"、"尊严"、"审美体验"),语言分布在一条连续的梯子上。 +- **两个方向的操作问题**: + - **"能给我一个例子吗?"** → 把说话者/作者**往下推**,从抽象滑到具体,把概念翻译成读者能看见的物。 + - **"那是什么意思?"** → 把说话者/作者**往上推**,从具体升到抽象,把分散的物拢成一个可被引用为格言的意思。 +- **中段是雷区**——官僚话、套话、新词(中文里也包括"系统化方案"、"全方位提升"、"教学单位"、"赋能"、"抓手")都集中在梯子中段。读者**既看不见**(缺具体物)**也摸不着**(缺概念),只感到"言之无物"。 +- **健康写作 = 反复上下爬**——好作者一段中既给具体场景(下梯)又给一句能记住的判断(上梯)。坏写作**困在中段**,既不诱人也无深意。 + +这是"显示 vs 告诉"的**操作版**:不是"哪个对",而是"上下都做、配比恰当"。 + +## 书中的案例 + +### 案例 1:Carolyn Matalene 的"既看不见也摸不着"诊断() + +- **问题**:一段散文读者读后无感——既不"被感动"(没有具体物)也不"被说服"(没有概念判断)。 +- **方法的使用**:Matalene 教 Clark——**读者既看不见也理解不了**,几乎一定是困在了梯子中段。这是一条**诊断式启发法**:不分析修辞、不分析结构,先问"读者此刻看到什么?理解到什么?"两者都缺 = 卡中段。 +- **结论**:给写作者一个"自检三问"——这一段我给出**哪个能看见的物**?给出**哪个能引用的判断**?两个都缺或两者皆糊 = 立刻下梯或上梯补救。 +- **结果**:Clark 把这条作为 Tool 22 的核心警告;Carolyn Matalene 因此成为中段陷阱的"命名者"。 + +### 案例 2:Hayakawa 的"show-and-tell"与 Mickey Mantle 棒球卡() + +- **问题**:怎么向 5 岁小孩讲清"梯子"? +- **方法的使用**:Clark 借用童年回忆——**展示** 1957 年 Mickey Mantle 棒球卡 = 梯子底部(一个具体的物,一个能触摸的卡片);**讲述** Mickey 1956 年有多伟大 = 梯子往上爬(从"这张卡"到"伟大"这个意思)。一次"show-and-tell"既演示了下梯也演示了上梯。 +- **结论**:任何一段好散文都是一场微型"show-and-tell"——给一个具体物 + 把它提升为一个意思。抽象梯子不是"工具",是**所有写作的默认结构**。 +- **结果**:成为"显示-告诉配比"理论的童年原型;说明梯子不是抽象思辨,是写作者每天的肌肉动作。 + +## 操作步骤 + +1. **下梯——"能给我一个例子吗?"** + - 找一段被诊断为"太抽象"的文字(议论文段落、主题句、人物观点段)。 + - 问作者(或自己代作者问):"**能给我一个例子吗?**" + - 强制产出**至少 1 个能看见/能触摸的具体物**(物件、动作、场景、感官片段)。 + - 完成标准:段落里出现至少 1 个"只有这里才有"的具象细节;读者能闭上眼睛"看见画面"。 + - 判停条件:若作者继续用抽象词("自由"、"尊严")回答,把抽象词本身当成"物"再问一次——"自由的什么?哪一刻的尊严?穿什么衣服?在哪个房间?",直到给出具体物。 +2. **上梯——"那是什么意思?"** + - 找一段被诊断为"太散"或"只是描述"的文字(纯景物、纯对话、纯情节)。 + - 问作者(或自己代作者问):"**那是什么意思?**" + - 强制产出**至少 1 句能脱离上下文仍能成立的判断**——读者可以摘抄、引用、记住的"格言句"。 + - 完成标准:段落里出现至少 1 句**能脱离本段仍站得住**的命题(像 Tolstoy "幸福的家庭都是相似的"那种抽象判断的硬度,但不一定是 5 字)。 + - 判停条件:若作者继续描述("然后他看见……"),问"为什么这个细节重要?它指向什么?",直到给出一句可被引用的判断。 +3. **中段自检——"读者此刻既看不见也摸不着吗?"** + - 取出写完的一段,做**两项扫描**: + - **看**扫描:删去所有抽象名词后,还剩几个能看见的物?≥ 1 个 → 至少触底;0 个 → 卡中段偏顶。 + - **摸**扫描:删去所有具体描写后,还剩几句能引用的判断?≥ 1 句 → 至少触顶;0 句 → 卡中段偏底。 + - 完成标准:任何一段都至少"触底一次 + 触顶一次"——可分别在不同位置触(底部+顶部),不要求同一句同时完成。 + - 判停条件:触底触顶都不及格 = 全段卡中段 = 重写或加具体物 + 加抽象判断。 + +## 中文落地【中文适配】 + +Clark 的抽象梯子写于 2006 年美国语境,迁移到中文小说时需要本地化: + +1. **中文的"中段陷阱"更隐蔽**——中文有一套自带的"中段化"路径,Clark 未涵盖: + - **文言/半文言化**:写作者一认真就滑向"其情可悯"、"悲夫"、"呜呼"等四字/六字短语(既不具体到"父亲的手在抖"也不抽象到"存在的焦虑",而是困在文言的中段)。 + - **四字格 / 套话堆叠**:"感人至深"、"催人泪下"、"气势恢宏"等四字格是中文自带的中段;表面上"凝练",其实两边都不着地。 + - **党政公文腔入侵小说**:这是 2010 年后中文小说的**新型陷阱**——党政干部小说、行业小说里"系统化推进"、"闭环管理"、"压实责任"等新词泛滥,Clark 时代(2006)的英文没有这套。 + - **过度抒情 / "意境"陷阱**:中文写作者容易"为意境而意境"——堆叠意象(月亮/古井/白发)却从不落到一个具体动作或一个清晰判断,这恰是中段。 +2. **时代局限**:Clark 写于 2006 年,未涵盖 2010 年后兴起的**网文/微博/微信文体**——这些文体的中段陷阱形态不同(emoji 堆叠、口号化短句、梗词循环),需要单独分析。 +3. **与"语言华丽"的混淆**:中文写作者常把"抽象梯子"误读为"语言要朴素";实则**梯子与辞藻无关**——华丽辞藻(明喻、排比、骈文)同样可以下梯到具体,也可以困在中段;判断标准是**读者能看见什么 / 能记住什么**,不是词藻繁简。 + +## 失败模式(作者在书中警告) + +1. **抽象梯子"卡在中段"(ce08)**——失败模式:写作时既不"上梯"也不"下梯",一直停在"教学单位"、"全方位学习"、"系统化方案"等灰色官僚话。信号:**满纸抽象名词 + 模糊动词**;既没有任何"看得见/摸得着"的具体物,也没有任何"可被引用为格言"的高层抽象。机制:Hayakawa 抽象梯子中段是"既不诱人也无深意"的区域——读者既不被具体物抓住,也不被判断说服。**自检信号**: + - 句子充满"系统化"、"全方位"、"解决方案"、"赋能"等词; + - 删掉所有抽象词后,没有任何一个具体物; + - 也没有任何一句脱离上下文仍能成立的判断。 +2. **显示-告诉配比失调**——失败模式:整章只有"显示"(景物清单)或整章只有"告诉"(议论);读者读后**没东西可记住**(没有可摘抄的判断)或**没东西可感受**(没有可想象的画面)。机制:显示-告诉是梯子两端,**好散文是一场微型 show-and-tell**——只做一端 = 体验缺损。 + +## 边界(不适用场景) + +- **抒情诗 / 极简写作**——诗的合法位置**就在中段之上**;纯意象堆叠、拒绝下梯是诗的标准姿态。如果你写的是诗,ladder 不适用,只适用 ladder 的"上梯"动作。 +- **工具书 / 教科书**——教科书的合法位置**就在中段**("教学单位"在教育学里**就是**该被称呼的);ladder 的"中段陷阱"是针对**小说和叙事散文**的警告,不是普适铁律。 +- **极简动作戏(无抽象层需求)**——纯打斗、纯追逐、纯感官场面,ladder 没有着力点;改用镜头距离(scene-craft 域 cinematic-distances)控节奏。 +- **政府公文 / 工作报告(本就是中段)**——如果写作者**就是**要写公文(而不是想写小说),不要拿"中段陷阱"去批评;ladder 警告的是**小说里**出现公文话。 + +## 容易混淆的邻近方法 + +- 与 "show, don't tell"(Tool 27):那个管"用动作和细节显示人物",强调**不要用性格形容词**;这个管"语言在梯子上的垂直位置",既包括下梯(显示)也包括上梯(判断/格言)。**Show-don't-tell 是 ladder 的下梯部分,不是 ladder 的全部**。相关方法点归 show-and-omission 域。 +- 与 "Get the name of the dog"(Tool 14):那个管"用一个极具体的感官细节替代一千个形容词";是 ladder 下梯操作的**最锐利**版本,但只负责下梯,不负责上梯。 +- 与 "Mission statement"(Tool 40):那个是动笔前的"对内承诺书"——内容层;ladder 是单段写作的"上下爬"操作——句子层。两者不重叠。 +- 与 "Theme" / 主题:主题是**全文级**的抽象命题;ladder 是**段落级**的抽象-具象切换。主题写不好通常也卡在 ladder 中段,但**主题是 ladder 的目标**,ladder 是**到达主题的脚手架**。 +- 与声音均衡器(本包 `voice-equalizer.md`):那个管"作者声音的均衡器旋钮"(句长、人称、距离、典故、隐喻密度等 30+ 杠杆)。这个管"语言在抽象-具象之间的**垂直位置**"——是 voice 的其中一个旋钮,但有自己的独立操作逻辑(上下爬)。ladder 是 voice 的一个**重要分量**,不是全部。 +- 与退一步/进一步(本包 `rhetoric-density.md`):那个管"严肃度 × 作者在场度"的校准(广岛幸存者要克制,Koch 市长的胡闹可以炫技)。这个管"语言层级的垂直位置",**与严肃度无关**——严肃的死亡场景照样需要具体物(下梯),轻佻的喜剧照样可以有格言(上梯)。 +- 与细节马赛克(character-presentation 域 mosaic-of-detail):那把"具体到 9 类的细节"作为人物搭建的零件;ladder 是**何时下梯**的工具(需要细 → 用 mosaic);mosaic 是 ladder 下梯时的**物料来源**。 +- 与叙事模式混合(narration-pov 域 mix-narrative-modes):那个管"主线 / 折线 / 蒙太奇"等叙事模式调度;ladder 的"果仁段落"模式恰好是 mix-narrative-modes 的"上梯子"版本。 +- 与句法节奏(本包 `sentence-rhythm.md`)的搭配:上梯产出的格言句配短句刹车;抽象句与具体句的交替,就是梯子的上下爬在句子层的体现。 +- 与镜头距离(scene-craft 域 cinematic-distances)的搭配:梯子中段在哪个镜头距离上暴露最明显,中段自检就重点看哪里。 +- **本方法的地位**:抽象梯子**几乎是基础工具**——它的"两个方向提问"几乎每个场景都需要自我诊断。**先于** voice-equalizer / mosaic-of-detail 使用。 + +## 激活场景与信号 + +场景: + +1. **主题句 / 议论文体段落**——写一段"关于自由"、"关于爱"、"关于现代性"的议论,写完发现全是抽象名词堆叠,读者读后记不住任何一句话。 +2. **哲学 / 思辨小说写作**——想写一部带哲学内核的长篇(加缪式、伯恩哈德式、毕飞宇《平原》式),不知道"哲学思考怎么落到具体场景里";满稿理念满天飞,但场景空转。 +3. **描写与议论的平衡**——一段话要么从头到尾都是景物(纯下梯),要么从头到尾都是抒情判断(纯上梯);不知道何时该下、何时该上。 +4. **党政公文 / 学术风入侵小说**——议论文里出现"系统化推进"、"全方位覆盖"、"赋能场景化"等词;不知道这些是**中段陷阱信号**。 +5. **人物观点的呈现**——写一个"有思想"的角色,结果对白像论文答辩——只有抽象判断,没有具体例证;读者觉得"这人不像人,像作者在自说自话"。 + +信号:"太抽象了" / "空" / "理念悬空" / "读着读着睡着了" / "满纸抽象" / "没有画面" / "看不见摸不着" / "哲学小说怎么写" / "思辨小说" / "观念小说" / "主题先行怎么破" / "能给我个例子吗" / "给我个例子" / "具体化一下" / "怎么落" / "怎么落到一页" / "描写和议论" / "景和情" / "叙事和议论" / "夹叙夹议" / "官僚话" / "套话" / "官腔" / "新词太多" / "像政府报告" / "ladder of abstraction" / "抽象梯子" / "上梯子" / "怎么写得有深意" / "下梯子" / "由抽象到具体" / "Hayakawa" / "主题句" / "thesis statement" / "中心句太硬" / "议论太多" / "没故事" / "都是道理" / "文以载道"。 diff --git a/framework/catalog/pi/skills/prose-craft/references/base-temperature.md b/framework/catalog/pi/skills/prose-craft/references/base-temperature.md new file mode 100644 index 0000000..2c2f479 --- /dev/null +++ b/framework/catalog/pi/skills/prose-craft/references/base-temperature.md @@ -0,0 +1,174 @@ +# 基础体温:找到你(和笔下人物)的辨识度 + +> 来源:《小说课》(毕飞宇)bifeiyu-base-temp —— 第 3 章,风格·辨识,难度三星,依赖要素:性格、直觉。案例来源:鲁迅冷/巴金热/张爱玲冷 + 整本书。 + +> "正如每个人都有自己的基础体温一样,每一个作家也都有他自己的基础体温。"() + +## 原文摘录 + +毕飞宇对中国现代作家的"基础体温"分类: + +| 作家 | 基础体温 | 风格关键词 | +|-----|---------|----------| +| 鲁迅 | 最低(之一) | 冷、阴、硬——"阴刚" | +| 巴金 | 最高 | 滚烫、赤子之心、赤子之情 | +| 张爱玲 | 极低 | 冰雪聪明、看透一切 | +| 沈从文 | 温 | 田园、温情 | +| 莫言 | 热 | 狂野、奔放 | +| 苏童 | 凉 | 唯美、颓废 | +| 毕飞宇本人 | 中偏冷 | 温中带冷 | + +**关键洞察**:每个作家(和每个人物)都有自己的"基础体温"——这是辨识度的核心。 + +## 方法骨架 + +**基础体温 = 你的文字散发出的"温度"**。 + +不是题材的温度——是**语言的温度**。两个作家写"死亡": + +- 鲁迅的死亡:冷峻、残酷、"死一般的寂静" +- 张爱玲的死亡:华美、苍凉、"生命是一袭华美的袍" +- 沈从文的死亡:田园、诗意 + +**你的基础体温决定你的辨识度**——读者读你的第一段就能"认出你"。 + +## 书中的案例() + +### 案例 1:鲁迅——冷/阴刚 + +- "死一般的寂静" +- "和光同尘" +- 一针见血,冷静到残酷 +- 基础体温 = 冷 + +**这种冷不是没感情——是把感情压到水底**。 + +### 案例 2:巴金——热 + +- 滚烫、赤子之心 +- 一辈子没降温 +- 基础体温 = 烫 + +### 案例 3:张爱玲——冰雪聪明 + +- 太聪明、太明白 +- 她的冷是"看穿了一切的冷" +- 基础体温 = 冷 + 通透 + +### 案例 4:莫言——狂野 + +- 狂野奔放 +- 基础体温 = 烫 + 狂 + +### 案例 5:蒲松龄《促织》——"冷中含热" + +- 整体冷(社会残酷、命运不公) +- 但有"小虫"那一段——全篇最温暖的瞬间 +- **冷是常态,热是反常——反常即戏** + +("小虫"案例在本包 `lyric-restraint.md` 与 `pattern-and-break.md` 里从"克制中的破例"角度分析;这里从温度反差角度保留,角度不同,都留。) + +## 操作步骤 + +### 步骤 1:找"你"的体温 + +问自己: + +> "我写最惨的事时,文字是什么温度?" +> "我写最美的事时,文字是什么温度?" + +- 都是冷 → 基础体温 = 冷(鲁迅型) +- 都是热 → 基础体温 = 热(巴金型) +- 冷热并存 → 复杂型(要看哪个是"默认") + +**检验**:写三段你最常用的文字,让陌生人猜"这是谁写的"——猜得到的程度 = 辨识度。 + +### 步骤 2:找"人物"的体温 + +每个人物也要有体温: + +```yaml +林冲:忍(冷+热并存) + - 表面冷(忍) + - 内心热(被逼急了会爆发) + +王熙凤:泼辣(热) + - 表面热(掌控一切) + - 内心冷(毒设相思局) + +成名:迁讷(凉) + - 表面凉(顺从) + - 内心热(为了儿子不惜一切) +``` + +**检验**:删掉所有形容词,读者能从动词/名词的温度里"感觉到"人物的体温吗? + +### 步骤 3:用"温度"检验一致性 + +你的人物有"冷"的特征吗?看看他的所有动作: + +- ❌ 林冲说"我受够了"(太直白、不像他的温度) +- ✅ 林冲默默把石头靠门(冷的、内敛的) + +**检验**:你的人物做的所有事,是不是都在"他的温度"内? + +### 步骤 4:温度的反差 = 戏剧性 + +**温度的反差是好戏**: + +``` +人物平时冷 → 突然热 = 戏 +人物平时热 → 突然冷 = 戏 +人物表面温度 ≠ 内心温度 = 戏 +``` + +**《促织》的最暖瞬间**:整篇冷,"小虫"那一段突然暖——读者瞬间被击中。 + +**检验**:你的小说里有没有"温度反差"的瞬间? + +### 步骤 5:用温度定位风格 + +确定你(和你的作品)的温度后: + +| 温度 | 适合题材 | 适合技法 | +|-----|---------|---------| +| 冷 | 残酷、批判、人性 | 白描、冰山、留白 | +| 热 | 激情、革命、爱情 | 排比、反复、呐喊 | +| 凉 | 唯美、抒情 | 慢镜头、细节 | +| 温 | 日常、人情 | 白描、对话 | +| 复杂 | 史诗、命运 | 多视角、反差 | + +## 边界 + +- **适合**:所有文学创作、风格定位 +- **不适合**:纯工具文(说明书、新闻) +- **慎用**:考试作文(要有"中立温度") + +## 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 温度不稳 | 像几个人写的 | 找到基础体温并坚持 | +| 温度单一 | 平面 | 找"温度反差"作为戏剧点 | +| 模仿别人的温度 | 没辨识度 | 找到你自己的"默认温度" | +| 人物都一个温度 | 平面 | 给主要人物不同温度 | + +## 一句话总结 + +> **你的基础体温就是你——找到它,坚持它,偶尔反它(反差即戏)。** + +## 相关方法点 + +- 与白描(本包 `plain-description.md`)配合:白描是"冷温度"的主要技法。 +- 与抒情不抒发(本包 `lyric-restraint.md`)关联:抒情节制是"冷温度"的核心。 +- 与人物命运(character-presentation 域 bifeiyu-character-fate)关联:性格决定温度。 +- 与心慈手狠(theme-and-stance 域 bifeiyu-mercy-ruth)关联:大师级的"心慈手狠"是一种"冷温度下的热"。 +- 与声音均衡器(本包 `voice-equalizer.md`)呼应:Clark 把风格拆成约三十根杠杆,其中"㉓ 立场温度(冷/热)"与"㉔ 情感强度"大致对应基础体温的位置;体温是中文本土的比喻式诊断,杠杆是工程化拆解,两套可以互相印证。 + +## 激活场景 + +1. 你的文字"读起来像 X 不像你" → 基础体温没找到 +2. 你的文字"没辨识度" → 找基础体温 +3. 你想学某个作家的写法 → 找他的基础体温 +4. 你的人物"性格不清" → 给人物一个基础体温 +5. 你写多人物/多视角 → 每个人物要不同基础体温 diff --git a/framework/catalog/pi/skills/prose-craft/references/lyric-restraint.md b/framework/catalog/pi/skills/prose-craft/references/lyric-restraint.md new file mode 100644 index 0000000..bf898c1 --- /dev/null +++ b/framework/catalog/pi/skills/prose-craft/references/lyric-restraint.md @@ -0,0 +1,199 @@ +# 抒情不抒发:小说家只是"懂得" + +> 来源:《小说课》(毕飞宇)bifeiyu-lyric-pass —— 第 7 章,修辞·情感,难度四星,依赖要素:性格、直觉。案例来源:《促织》"小虫"的克制 + 整本书。 +> "克制中的破例"与《写作工具》的句法层模式转折是同一方法点,两书合并的一条在 `pattern-and-break.md`。 + +> "小说家只是'懂得',然后让读者'懂得',这个'懂'是关键。张爱玲说,因为'懂得',所以慈悲。"() + +## 原文摘录 + +蒲松龄《促织》里,成名的儿子变成了一只小促织。 + +**整篇小说用"虫"**——冷静、客观、距离感。 + +**唯独一处**——孩子跳到成名袖口那一段: + +> "壁上小虫忽跃落襟袖间。" + +**"小虫"——不是"虫",是"小虫"**。 + +**毕飞宇解读**: + +> "这是蒲松龄唯一失去冷静的时刻。……即使克制如蒲松龄,他也有失去冷静的时刻。" + +**两个克制**: + +1. 通篇用"虫"——理性、距离 +2. 唯独这里用"小虫"——感性、靠近 + +**没有直接抒情**——但读者**瞬间被击中**。 + +## 方法骨架 + +**小说的抒情 = 不抒发**。 + +**核心洞察**:小说和诗歌/散文不同——**小说家不抒发情感,只"传递"情感**。 + +``` +诗歌/散文的抒情:"我多么伤心啊!" +小说的抒情:(不写"我伤心")写一个具体动作,让读者感到伤心 +``` + +**小说家的工作**: + +- 懂得情感 +- 不直接说情感 +- 让读者**自己懂**情感 + +## 书中的案例() + +### 案例 1(指针):蒲松龄《促织》「小虫」(冰山) + +> 留白/冰山全文 owner:`show-and-omission` → [iceberg.md](../../show-and-omission/references/iceberg.md)。抒情克制要点:全篇用「虫」,唯独「小虫」一处失控。 + +### 案例 2(指针):莫泊桑《项链》「发红的手」(心慈手狠) + +> 作家立场/手软案例 owner:`theme-and-stance` → [mercy-ruth.md](../../theme-and-stance/references/mercy-ruth.md)。抒情克制要点:不写代价议论,只写「发红的手」。 + +### 案例 3:鲁迅《故乡》闰土叫"老爷" + +- 不写"我多么难过" +- 写闰土叫"老爷" + 母亲劝 + 闰土的"自我检讨" +- 读者自己懂:自然的崩溃、阶级的可怕 +- (同一案例在本包 `plain-description.md` 里从"不写形容词只写动作和对话"的角度再次引用,角度不同,两处都保留。) + +### 案例 4:曹雪芹 王熙凤"款步提衣上楼" + +- 不写"她多么爱美、多么空虚" +- 写她"款步提衣" +- 读者自己懂:欲望和伪装 + +### 案例 5:奈保尔 沃滋沃斯临死前 + +- 不写"我多么爱你" +- 沃滋沃斯把孩子搂在怀里说"那故事是假的" +- 读者自己懂:他的孤独和他的爱 + +## 操作步骤 + +### 步骤 1:识别"抒情冲动" + +写每段时问自己: + +> "我是不是在'告诉读者我很感动'?" + +- 是 → ❌ 删掉抒情段 +- 不是 → ✅ 继续 + +**关键信号**: + +- "我多么 X" +- "我感到 X" +- "我的心 X" +- "我泪流满面" +- "我无法用语言表达" + +→ **全部删掉** + +### 步骤 2:把"抒情"翻译成"动作" + +| ❌ 抒情 | ✅ 动作 | +|-------|-------| +| 我多么舍不得你 | 我转身走了三次都回来 | +| 她太美了 | 她的眼睛里有光 | +| 这个地方真荒凉 | 门口的草长到了窗台 | +| 他心里很乱 | 他的手指不停敲桌面 | +| 我很感动 | 我的眼睛湿了 | +| 我爱这个孩子 | 我每天给孩子抓萤火虫 | + +**检验**: + +- 删掉"抒情"句子后,小说还成立吗?→ ✅ 抒情是多余 +- 删掉"动作"句子后,小说还成立吗?→ ❌ 动作是必要 + +### 步骤 3:克制中的"破例" + +**最高级的抒情** = 通篇克制 + **唯一一次的"破例"**: + +``` +《促织》:通篇"虫" + 唯一"小虫" +《项链》:通篇冷静 + 唯一"发红的手" +《红楼梦》王熙凤:通篇优雅 + 唯一"款步提衣" +``` + +**破例 = 满盘皆输中的一子**——读者瞬间被击中。 + +**检验**:你的小说有没有"克制 + 破例"的瞬间? + +(本步骤与 Clark 的句法层模式转折是同一方法点,两书合并的完整条目见 `pattern-and-break.md`。) + +### 步骤 4:用"懂"代替"说" + +**小说家的工作**: + +> "我懂这个情感,我不需要说它——我让读者也懂。" + +**张爱玲**:"因为懂得,所以慈悲。" + +**操作方法**: + +- 写一个具体动作 +- 不解释、不抒情 +- 留一个"空"让读者填 + +**检验**: + +- 读者读完后会"啊我懂了"→ 抒情到位 +- 读者读完后"你告诉我什么"→ 抒情失败 + +### 步骤 5:检验"情感段"密度 + +小说里**情感段不能太密**——多了就滥: + +```yaml +冷段 70% +温段 20%(过渡) +热段 10%(爆点) + +热段不能连续 2 段以上 +冷段不能连续 10 段以上(读者会累) +``` + +**检验**:你的小说里"热段"是不是**短而有力**? + +## 边界 + +- **适合**:所有虚构叙事 +- **特别适合**:悲剧、现实主义 +- **慎用**:意识流(它恰恰要直接抒情) +- **不适用**:纯散文、纯抒情诗 + +## 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 抒情直白 | 像散文 | 改用动作 | +| 抒情太密 | 滥情 | 情感段 ≤ 10% | +| 没有"破例" | 平面 | 加一个"克制中的破例" | +| 抒情变说教 | 主题先行 | 删掉说教,只留动作 | +| 抒情用"形容词" | 假 | 用"动词+名词" | + +## 一句话总结 + +> **小说家不告诉读者"我感动"——小说家让读者"自己感动"。** + +## 相关方法点 + +- 与冰山理论(show-and-omission 域 bifeiyu-iceberg)同源:抒情不抒发 = 冰山理论在情感上的应用。 +- 与白描(本包 `plain-description.md`)配合:白描是抒情不抒发的主要技法。 +- 与基础体温(本包 `base-temperature.md`)关联:基础体温决定"抒情的方式"。 +- 与心慈手狠(theme-and-stance 域 bifeiyu-mercy-ruth)关联:心慈手狠 = 抒情不抒发的高级形态。 +- 与退一步/进一步(本包 `rhetoric-density.md`)呼应:重大场景两者都要求作者退后、让动作说话。 + +## 激活场景 + +1. 你的人物"该抒情了"但你写出来像散文 → 改用"具体动作" +2. 你写了"我多么 X" → 删掉,改用一个动作 +3. 你的情感段"太直白" → 用"克制"代替 +4. 你的悲剧"不够悲" → 删掉抒情,让动作说话 +5. 你想"感动读者" → 不要感动他——让他自己感动 diff --git a/framework/catalog/pi/skills/prose-craft/references/pattern-and-break.md b/framework/catalog/pi/skills/prose-craft/references/pattern-and-break.md new file mode 100644 index 0000000..6d6d830 --- /dev/null +++ b/framework/catalog/pi/skills/prose-craft/references/pattern-and-break.md @@ -0,0 +1,94 @@ +# 先建稳模式,再打破一处:模式转折与克制中的破例 + +> 本条为两书合并的方法点(同一方法点多书出现,合并一条、保留各书视角与引文): +> - 《写作工具》(Roy Peter Clark《Writing Tools》)sentence-rhythm —— Tool 8,句法层的模式转折(pattern-twist); +> - 《小说课》(毕飞宇)bifeiyu-lyric-pass —— 情感层的"克制中的破例"。 +> +> 合并理由:两条说的是同一门手艺——先建立稳固模式,再在关键处故意打破一次,打破处获得额外分量。Clark 用在句子层,毕飞宇用在情感层。 + +## 方法原则 + +- 先用平行、重复、克制(句式、节奏、词汇、意象,或通篇的称呼与冷静)建立稳固模式,让读者形成预期; +- 在结尾或关键处故意"反一手"——换词、变奏、加异常、靠近一次; +- 打破的那一处获得超出模式本身的额外强调或情感冲击; +- **只在关键处用**——高潮、转折点、情感峰值;不是每段都转折,通篇克制破得太多就等于没有破。 + +这是"出人意料"的高效版本:意外感来自你亲手建立的模式,不是不可预测的奇袭。 + +## Clark 的句法层:模式转折() + +### 原文摘录 + +> A pure parallel construction would be "Boom, boom, boom." Parallelism with a twist gives us +> "Boom, boom, bang." ... By breaking the pattern, he lends more emphasis to the final element. +> +> — Roy Peter Clark, *Writing Tools* (Tool 8) + +### 操作与案例 + +- 纯粹的平行结构是 "Boom, boom, boom";带转折的平行是 "Boom, boom, bang"——最后打破一处,末尾元素获得额外强调。 +- Martin Luther King《I Have a Dream》:"Let freedom ring from ... [pattern] ... from Stone Mountain of Georgia!"——最后一句打破模式,获得额外强调。 +- 判断标准(来自本方法的操作步骤):检查关键场景(高潮、转折点、情感峰值)是否有"模式-转折";每个关键场景至少有 1 处"建立模式 + 打破"的结构;**不是每段都要"模式转折",只在关键处用**。 + +## 毕飞宇的情感层:克制中的破例() + +### 原文摘录:《促织》的"虫"与"小虫" + +蒲松龄《促织》里,成名的儿子变成了一只小促织。 + +**整篇小说用"虫"**——冷静、客观、距离感。 + +**唯独一处**——孩子跳到成名袖口那一段: + +> "壁上小虫忽跃落襟袖间。" + +**"小虫"——不是"虫",是"小虫"**。 + +**毕飞宇解读**: + +> "这是蒲松龄唯一失去冷静的时刻。……即使克制如蒲松龄,他也有失去冷静的时刻。" + +**两个克制**: + +1. 通篇用"虫"——理性、距离 +2. 唯独这里用"小虫"——感性、靠近 + +**没有直接抒情**——但读者**瞬间被击中**。 + +### 三部作品的破例样式 + +**最高级的抒情** = 通篇克制 + **唯一一次的"破例"**: + +``` +《促织》:通篇"虫" + 唯一"小虫" +《项链》:通篇冷静 + 唯一"发红的手" +《红楼梦》王熙凤:通篇优雅 + 唯一"款步提衣" +``` + +**破例 = 满盘皆输中的一子**——读者瞬间被击中。 + +**检验**:你的小说有没有"克制 + 破例"的瞬间? + +## 中文形式【中文适配】 + +"先建模式再打破"在中文里有特殊形式(来自 的本地化注记): + +- **四字格堆叠 + 突然短句**:"他走了 / 没有回头。" +- **对仗 + 打破**:"长亭外,古道边,芳草碧连天" + "他死了。" + +## 判断标准与常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 到处打破 | 模式没建起来,打破处没有分量 | 先把模式建够,只留一处打破 | +| 只有模式没有打破 | 单调催眠,没有意外 | 在关键处加一处反手 | +| 在非关键处用 | 强调被稀释 | 只在高潮、转折、情感峰值用 | +| 破例超过一次 | 破例贬值,走向滥情 | 通篇只留唯一一次,把最重的一击留给它 | + +(Clark 明确"不是每段都要模式转折";毕飞宇的破例纪律是"唯一一次"——两条出处一致,都指向同一件事:打破的分量来自稀缺。) + +## 激活信号 + +- "boom boom bang" / "模式转折" / "pattern-twist" / "平行结构" +- "克制中的破例" / "破例" / "小虫" / "唯一一次" +- "先建立模式再打破" / "结尾怎么来一下" diff --git a/framework/catalog/pi/skills/prose-craft/references/plain-description.md b/framework/catalog/pi/skills/prose-craft/references/plain-description.md new file mode 100644 index 0000000..878d40a --- /dev/null +++ b/framework/catalog/pi/skills/prose-craft/references/plain-description.md @@ -0,0 +1,112 @@ +# 白描:用最少的字立住人物 + +> 来源:《小说课》(毕飞宇)bifeiyu-paiban —— 第 7 章,人物·修辞,难度两星,依赖要素:智商、直觉。案例来源:《促织》驼背巫的描写 + 蒲松龄的描写观。 + +> 「唇吻翕辟,不知何词。各各竦立以听。」——12 个字,一个神秘人物立住。() + +## 原文摘录 + +蒲松龄写驼背巫: + +> "巫从旁望空代祝,唇吻翕辟,不知何词。各各竦立以听。" + +**翻译**:嘴唇一张一合,不知道说什么词。所有的人都惊悚地站着听。 + +**12 个字**(不含虚词),**两个动作**(翕辟、竦立)——把一个神秘人物 + 一个静谧大场景全部搞定。 + +## 方法骨架 + +**白描 = 用最少的字画出一幅有重量的画**。 + +不是"写得简单",而是"写得精准"——每个字都**不可替换**。多一个字显得冗余,少一个字意思垮掉。 + +## 书中的案例() + +> 铺垫「自然楼梯」案例 owner:`foreshadow-payoff` → [natural-staircase.md](../../foreshadow-payoff/references/natural-staircase.md)「蒲松龄《促织》驼背巫」节。白描要点:只写动作与对话,不用形容词堆人物。 + +### 案例 2(指针):蒲松龄《促织》成名(逻辑自洽) + +> 立场/性格碰撞全文 owner:`theme-and-stance` → [stance-by-logic.md](../../theme-and-stance/references/stance-by-logic.md)。本处只保留白描对比:「为人迂讷」四字定性格,对照现代形容词堆砌写法。 + +### 案例 3:鲁迅《故乡》闰土 + +> "他站住了,脸上现出欢喜和凄凉的神情;动着嘴唇,却没有作声。他的态度终于恭敬起来了,分明地叫道:'老爷!……'" + +没有形容词——**只写动作和对话**,人物的全部复杂性就出来了。 + +(同一案例在本包 `lyric-restraint.md` 里从"不直接抒情、让读者自己懂"的角度再次引用,角度不同,两处都保留。) + +### 案例 4(指针):海明威《杀手》(对白白描) + +> POV 与多重视角案例 owner:`narration-pov` → [pov-camera.md](../../narration-pov/references/pov-camera.md)。本处只取白描角度:对话省略主语与代词,用内容本身透露说话人。 + +## 操作步骤 + +### 步骤 1:拒绝形容词 + +写第一稿时不要用"他很 X"(X = 任何形容词)。**改用动作**: + +| ❌ 形容词式 | ✅ 白描式 | +|---|---| +| 他很紧张 | 他的手指不停敲桌面 | +| 她很伤心 | 她的筷子停在半空 | +| 这地方很荒凉 | 门口的草长到了窗台 | +| 他很傲慢 | 他没抬眼看那人 | + +### 步骤 2:删除虚词 + +写完后做"虚词清理": + +- "的、了、着、于是、然后" → 能删就删 +- 形容词前的程度副词(很、非常、特别)→ 全删 +- "我看到/我听到" → 直接进入画面 + +### 步骤 3:检验"动作的代表性" + +每个白描动作要能代表**人物整体**: + +- 写驼背巫"唇吻翕辟"——代表她通神的能力 +- 写林冲"靠了门"——代表他忍辱负重的性格 +- 写闰土叫"老爷"——代表他从自然人到奴性的转化 + +**检验问题**:这个动作放在另一个场景、另一个人物身上,还成立吗?如果成立 → 换动作。 + +### 步骤 4:检验"动态"密度 + +一段白描文字里,**至少 1/3 的字是动词或名词性动作**。 + +- 静态白描(全是名词)= 死的描写 +- 动态白描(动词驱动)= 活的描写 + +## 边界 + +- **适合**:人物出场、关键瞬间、氛围营造 +- **不适合**:复杂心理活动(需要内心独白)、意识流 +- **不适合**:长篇大段的场景描写(需要更厚重的笔法) + +## 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 把白描当成"句子短" | 失去密度 | 每个短句都要承重 | +| 写一堆动作但没选择 | 散乱 | 动作必须有代表性 | +| 拒绝一切形容词 | 失去必要修饰 | 该用"鬼魅""青灰色"就用 | + +## 一句话总结 + +> **不写"他很 X",写"他做了一个动作,这个动作等于 X"。** + +## 相关方法点 + +- 与冰山理论(show-and-omission 域 bifeiyu-iceberg)互补:冰山关注"水下",白描关注"水面"。 +- 与人物命运(character-presentation 域 bifeiyu-character-fate)配套:白描是给"性格即命运"提供"性格描写"的技术。 +- 与反常(character-presentation 域 bifeiyu-anti-norm)配合:白描写常态,反常写变态——变态才有戏。 +- 与抒情不抒发(本包 `lyric-restraint.md`)配合:白描是抒情不抒发的主要技法。 +- 与基础体温(本包 `base-temperature.md`)配合:白描是"冷温度"的主要技法。 + +## 激活场景 + +1. 人物第一次出场 → 用 1-2 个具体动作代替 5 个形容词 +2. 群像描写 → 每个人物只用 1 个标识性动作区分 +3. 神秘人物/反派 → 用"动态"代替"介绍" +4. 时间紧/篇幅短(短篇、闪回)→ 白描是最高效的写法 diff --git a/framework/catalog/pi/skills/prose-craft/references/revision-checklist.md b/framework/catalog/pi/skills/prose-craft/references/revision-checklist.md new file mode 100644 index 0000000..4f41c98 --- /dev/null +++ b/framework/catalog/pi/skills/prose-craft/references/revision-checklist.md @@ -0,0 +1,100 @@ +# 语言修辞改稿清单(prose-craft) + +用法:初稿完成后按七遍顺序逐项过。每遍只列判断标准,方法细节与案例见对应 references/ 文件。不是每遍每次都用:句子遍、情感遍几乎必用,杠杆遍只在长篇风格出问题时用。 + +## 第一遍:句子(references/sentence-rhythm.md) + +- [ ] 每句的主谓位置已用 X 光标出(X 光 = 结构化透视标记,逐句标出主语和动词的落点),再判断先行还是远置 +- [ ] 每段 70% 以上句子主谓先行;主谓远置只出现在悬念、发现、庄重处 +- [ ] 主谓远置没有越过警戒线(英文 18 词分隔 = 致命;中文以"读者要不要回头重读"为准) +- [ ] 相邻五句至少出现三种不同长度;没有短-短-短或长-长-长的单轨 +- [ ] 每段至少一个短句刹车;中文长句用句号刹车,不用逗号连拖 +- [ ] 翻译腔三信号为零:"是"字句不超标、被动不滥用、没有长定语后置 +- [ ] 关键场景(高潮、转折、情感峰值)至少一处"建立模式 + 打破"(references/pattern-and-break.md) + +## 第二遍:梯子(references/abstraction-ladder.md) + +- [ ] 每段至少触底一次:删掉抽象名词后还剩至少一个看得见的物 +- [ ] 每段至少触顶一次:删掉具体描写后还剩至少一句可引用的判断 +- [ ] 中段信号词扫描零命中:"系统化 / 全方位 / 解决方案 / 赋能 / 抓手"、四字格套话("感人至深""催人泪下""气势恢宏")、半文言("其情可悯""呜呼""悲夫")、公文腔("闭环管理""压实责任") +- [ ] 意境式意象(月亮、古井、白发)都落到了一个具体动作或一句清晰判断上 +- [ ] "太抽象"的段落问过"能给我一个例子吗",直到给出具体物;"太散"的段落问过"那是什么意思",直到给出可引用的判断 + +## 第三遍:温度(references/rhetoric-density.md) + +- [ ] 当前场景严肃度打了 1-10 分(10 = 亲人死亡、战争屠杀;1 = 日常打趣);评分犹豫时按默认保守(更克制) +- [ ] 修辞密度与温度成反比:温度 8-10 → 密度 2-3;温度 5-7 → 密度 5-6;温度 1-4 → 密度 8-10 +- [ ] 重大场景自检:让一个广岛幸存者来读这段,他会觉得用力过猛吗?会就更克制 +- [ ] 日常场景自检:放进 Koch 式胡闹场景够炫技吗?不够就加修辞 +- [ ] 网文 / 爽文提示:反比不是铁律(莫言"重说重"同样成立,关键是与主题匹配),但重场景保留克制工具 + +## 第四遍:情感(references/lyric-restraint.md) + +- [ ] 直白抒情信号词零命中:"我多么 X""我感到 X""我的心 X""我泪流满面""我无法用语言表达" +- [ ] 每删一处抒情都换成了一个动作;删掉抒情句小说仍成立(抒情多余),删掉动作句小说不成立(动作必要) +- [ ] 全篇有且只有一次"克制中的破例"(references/pattern-and-break.md) +- [ ] 情感段密度:冷段约 70%、温段约 20%、热段约 10%;热段不连续超过两段,冷段不连续超过十段 + +## 第五遍:白描(references/plain-description.md) + +- [ ] 人物出场段没有"他很 X",一律改成了动作 +- [ ] 虚词清理:"的、了、着、于是、然后"能删就删;"很、非常、特别"全删;"我看到/我听到"删掉直接进画面 +- [ ] 每个白描动作能代表人物整体:换一个人物、换一个场景还成立的动作,换掉 +- [ ] 白描段至少三分之一的字是动词或名词性动作(全是名词的静态白描 = 死的描写) +- [ ] 没有拒绝一切形容词:该用"鬼魅""青灰色"就用 + +## 第六遍:体温(references/base-temperature.md) + +- [ ] 全篇默认温度已确定(看写最惨与最美的事时是什么温度),前后一致 +- [ ] 主要人物各有体温;每个人物的动作都在他的温度内(林冲不说"我受够了",他默默把石头靠门) +- [ ] 有意识地布置了温度反差:平时冷突然热/平时热突然冷/表面温度 ≠ 内心温度,至少一处 +- [ ] 温度与技法匹配:冷配白描、留白;热配排比、呐喊;凉配慢镜头、细节;温配白描、对话;复杂配多视角、反差 + +## 第七遍:杠杆(references/voice-equalizer.md) + +- [ ] 按下方台账标注至少 25 根杠杆的当前位置;长篇检查前 10 章与后 10 章的杠杆一致性(声音漂移) +- [ ] 选定基线(模仿对象或自己最满意的一章),X 光阅读 3-5 章读出基线位置表 +- [ ] 找出差值最大的 5-8 根杠杆,每次只动 1-3 根,改写 500-1000 字验证;调完反而更不像 → 回退换一根 +- [ ] 模仿纪律:只学基线的 1-2 根标志杠杆,其余保持自己的;模仿是参考不是替换 + +## 三十杠杆基线台账模板 + +复制下表,逐根填写当前稿与基线的位置(高/中/低),标出差值与是否调整。前 30 根是 Clark 原表,后 5 根是中文补充杠杆(见 references/voice-equalizer.md 中文落地节)。 + +| 杠杆 | 层 | 当前稿 | 基线 | 差值 | 是否调整 | +|---|---|---|---|---|---| +| ① 句长分布(短/中/长) | 句法 | | | | | +| ② 句型变化(主谓前置/后置) | 句法 | | | | | +| ③ 主谓位置 | 句法 | | | | | +| ④ 主动/被动比 | 句法 | | | | | +| ⑤ 修辞密度 | 句法 | | | | | +| ⑥ 段落长短 | 句法 | | | | | +| ⑦ 标点使用密度 | 句法 | | | | | +| ⑧ 词汇正式度(口语/书面) | 词汇 | | | | | +| ⑨ 抽象-具体比 | 词汇 | | | | | +| ⑩ 方言/俚语比例 | 词汇 | | | | | +| ⑪ 典故来源(古典/现代/无) | 词汇 | | | | | +| ⑫ 行业行话密度 | 词汇 | | | | | +| ⑬ 对话密度 | 声音 | | | | | +| ⑭ 引语 vs 对话比例 | 声音 | | | | | +| ⑮ 内心独白比例 | 声音 | | | | | +| ⑯ 第一/第三人称 | 声音 | | | | | +| ⑰ 人物视角距离 | 声音 | | | | | +| ⑱ 视觉细节 | 感官 | | | | | +| ⑲ 听觉细节 | 感官 | | | | | +| ⑳ 嗅觉/触觉/味觉 | 感官 | | | | | +| ㉑ 修辞(明喻/暗喻)密度 | 感官 | | | | | +| ㉒ 距离(远/近) | 修辞 | | | | | +| ㉓ 立场温度(冷/热) | 修辞 | | | | | +| ㉔ 情感强度 | 修辞 | | | | | +| ㉕ 节奏点(短句爆点) | 修辞 | | | | | +| ㉖ 框架方式(全知/限知) | 修辞 | | | | | +| ㉗ 章节切分 | 结构 | | | | | +| ㉘ 空白使用 | 结构 | | | | | +| ㉙ 章节标题风格 | 结构 | | | | | +| ㉚ 段首句惯例 | 结构 | | | | | +| 补1 对仗/骈文密度 | 中文补充 | | | | | +| 补2 四字格/成语密度 | 中文补充 | | | | | +| 补3 七字句/五言节奏点 | 中文补充 | | | | | +| 补4 语气词密度(呢/啊/吧/嗯) | 中文补充 | | | | | +| 补5 标点中文化(顿号、省略号、引号) | 中文补充 | | | | | diff --git a/framework/catalog/pi/skills/prose-craft/references/rhetoric-density.md b/framework/catalog/pi/skills/prose-craft/references/rhetoric-density.md new file mode 100644 index 0000000..dbfd81c --- /dev/null +++ b/framework/catalog/pi/skills/prose-craft/references/rhetoric-density.md @@ -0,0 +1,106 @@ +# 修辞密度校准:退一步与进一步(back off / show off) + +> 来源:《写作工具》(Roy Peter Clark《Writing Tools》)back-off-show-off —— Tool 21 "Know when to back off and when to show off"。 +> 中文三家对照(鲁迅/张爱玲/莫言)与网文规则并存为中文适配内容,含规则冲突标注。 + +## 原文摘录(全量) + +以下引文出自。 + +> Here's a tool of thumb that works for me: The more serious or dramatic the subject, the more +> the writer backs off, creating the effect that the story tells itself. The more playful or inconsequential +> the topic, the more the writer can show off. Back off or show off. +> +> — Roy Peter Clark, *Writing Tools* (Tool 21) + +## 方法骨架 + +Clark 提出**强反直觉**的校准法则:**主题重量与修辞密度成反比**。 + +- **反直觉的核心**: + - 重大场景(严肃主题、悲剧、死亡)→ **克制**(back off)→ 简单句、短句、人物自己动作 + - 轻微场景(日常、轻佻、不重要)→ **炫技**(show off)→ 修辞、典故、声音展示 +- 判断标准:在场景的"严肃度"和写作者的"在场度"之间做校准。 +- Clark 引用两个对照案例: + - **广岛幸存者演讲**(Tool 21,严肃度极高)= "有礼貌地道歉 / 占用了我们的时间"——**最克制的开场** + - **Koch 市长胡闹**(Tool 21,严肃度极低)= 全套剧场式修辞——**最炫技的笔法** +- 机制:情感是有限资源。**重度场景 + 重度修辞 = 情感透支 → 读者反而冷漠**。严肃场景的克制反而是"高密度情感传递"。 +- 斯皮尔伯格的对照:Schindler's List 用克制(黑白 + 长镜头 + 极少台词)、《拯救大兵瑞恩》用暴露(慢镜头 + 抖动 + 大量音效)——同样严肃场景,前者有效,后者审美疲劳。 + +这是**校准决策框架**——用主题的温度计,调节写作者的"声音音量"。 + +## 书中的案例 + +### 案例 1:John Hersey《广岛》"有礼貌的开场"() + +- **问题**:写广岛原子弹爆炸幸存者,如何让读者不被"重大"压垮? +- **方法的使用**:Hersey 让 6 位幸存者各自讲述。广岛幸存者(old woman)在演讲台开始时**先为占用时间道歉**——一个"有礼貌的道歉"开篇。 +- **结论**:**重大场景最克制的开场 = 让读者"轻装进入"**。 +- **结果**:成为"克制美学"的金标准;展示了"轻说重"的力量。 + +### 案例 2:Clark 引用 Spielberg《Saving Private Ryan》对照() + +- **问题**:同样严肃场景(纳粹屠杀),不同修辞密度的对照。 +- **方法的使用**:Schindler's List = 黑白 + 长镜头 + 极少台词(克制);Saving Private Ryan = 慢镜头 + 抖动 + 大量音效(暴露)。 +- **结论**:**前者有效,后者审美疲劳**——重大场景的"轻处理"反而让读者情感到位。 +- **结果**:电影美学的对照;说明"克制"是处理重大场景的工具,不是"缺乏能力"。 + +## 操作步骤 + +1. **评估场景的"主题温度"** + - 列出当前场景:涉及什么主题?人物命运的重量?读者会期待什么情感强度? + - 完成标准:1-10 的温度评分(10 = 最严肃,如亲人死亡、战争屠杀 / 1 = 最轻,如日常打趣)。 + - 判停条件:若评分犹豫,默认保守(更克制)。 +2. **反比决定修辞密度** + - 温度 8-10:修辞密度 2-3(克制,简单句,人物自己动作,作者"不在场")。 + - 温度 5-7:修辞密度 5-6(中等,可有修辞但需谨慎)。 + - 温度 1-4:修辞密度 8-10(炫技,作者声音可大量展示)。 + - 完成标准:温度与密度成反比。 +3. **"广岛幸存者"检验** + - 写完重大场景后,问:"如果让一个广岛幸存者来读这个场景,他会觉得'用力过猛'吗?" + - 完成标准:若会,改写为更克制版本。 +4. **"Koch 市长"对照** + - 写完日常场景后,问:"如果把这段放在一个 Koch 式胡闹场景里,是否够炫技?" + - 完成标准:若否,加大修辞密度。 + +## 中文落地与规则并存【中文适配】 + +- **Clark 偏新闻克制美学**(Hersey 的《广岛》是新闻特稿),不一定适用于中文网文"虐文美学"——后者常以"重笔写重事"为美。**网文写作者应保留"克制"工具,但不必全盘照搬**。 +- **中国新文学的对照**:鲁迅的克制(《孔乙己》《示众》)+ 张爱玲的"轻说重"(《倾城之恋》"一座城的陷落成全了她的爱情")+ 莫言的"重说重"(《丰乳肥臀》)。三种笔法都成立,关键是**与主题匹配**。 + - **规则冲突标注**:莫言式"重笔写重事"与 Clark 的"主题重量与修辞密度成反比"并存冲突。Clark 的反比出自新闻克制美学,是默认值不是铁律;两条规则都保留,以"与主题匹配"为最终裁决。 +- **短视频 / 直播时代**:读者注意力更短,"修辞密度"与"严肃度"的反比关系被压缩——可能需要"快速切换"。 +- **"网络爽文"**:主题重量往往不"重",修辞密度可以"用力",Clark 的"反比"不适用——爽文有自己的"轻场景用力 / 重场景也用力"逻辑。 + +与《小说课》的呼应:毕飞宇的"抒情不抒发"(本包 `lyric-restraint.md`)在重大场景与本方法结论一致——作者退后,让动作说话。两者分工:本方法管"场景严肃度允许多少修辞",那个管"情感用什么出口传递"。 + +## 失败模式(作者在书中警告) + +1. **"严肃场景炫技"(ce09)**:失败模式是在广岛幸存者这种最严肃时刻用华丽修辞、独白、戏剧化。信号:悲剧场景里有"作者旁白独白"或"刻意感人"段落。机制:作者"不放心"读者,想用修辞"加力",但情感透支反而冷漠。预警:广岛幸存者检验失败。 +2. **"日常场景紧绷"**:失败模式是把日常场景写得像悲剧——每句都用力,每个细节都"沉重"。信号:日常对话也有"诗化"语言。机制:作者误以为"用力 = 文气",但日常场景需要炫技空间而不是紧绷。预警:整本书都是紧绷的,没有"轻下来"的时刻。 +3. **"误判严肃度"**:失败模式是误判场景温度(把轻场景当重场景)。信号:写打闹场景用庄重笔法,或写悲剧用轻佻笔法。机制:作者对"主题重量"敏感度不足。预警:Koch 市长对照失败。 + +## 边界(不适用场景) + +- **后现代反讽**——故意用"反比"作为反讽。 +- **喜剧 / 网络爆款**——喜剧本身需要"用力"或"用力装作不用力",Clark 的"严肃克制"模型不适用。 +- **实验文学**——故意打散"主题-修辞"对应关系。 +- **网络段子的快节奏**——短视频的"金句感"需要修辞密度直接拉满,不能"反比"。 + +## 容易混淆的邻近方法 + +- 与"语言节制"的区别:语言节制是"减少华丽词",back off 是"减少作者声音"。前者是词汇层,后者是叙述者层。 +- 与原型选择(character-design 域 archetype-toolkit)的区别:原型选择是"主题层"操作(说什么),back off / show off 是"修辞层"操作(怎么说)。两者可同时使用。那个管"在选定原型上如何说",这个管"给多大的声音音量"。 +- 与声音均衡器(本包 `voice-equalizer.md`)的区别:那是"整体声音的杠杆清单"(30+ 杠杆,默认设置),这个是"特定场景的修辞密度校准"(反比主题)。前者是基线,后者是局部操作;本方法是它的**一个子旋钮**。 +- 与句法节奏(本包 `sentence-rhythm.md`)的区别:那是"句法节奏"(主谓、句长、模式),这个是"修辞密度"(比喻、典故、声音的展示)。前者是微观句法,后者是宏观修辞。 + +## 激活场景与信号 + +场景: + +1. 写到"高潮场"(死亡、悲剧、告白)用了一堆华丽修辞,但读起来"用力过猛" / "俗"。 +2. 写日常向场景,反而没有"文气" / "笔力"。 +3. 写战争 / 灾难 / 重病等重大场景,担心读者疲劳。 +4. 写完一个场景后觉得"主题宏大但修辞没跟上"或"修辞宏大但主题很轻"。 +5. 网络虐文读者反应冷淡——想找原因。 + +信号:"用力过猛" / "过度修辞" / "back off" / "show off" / "如何写重大场景" / "严肃场景怎么写" / "克制" / "restraint" / "主题温度" / "日常场景怎么写" / "文气" / "修辞密度" / "读者反应冷淡" / "写得俗"。 diff --git a/framework/catalog/pi/skills/prose-craft/references/sentence-rhythm.md b/framework/catalog/pi/skills/prose-craft/references/sentence-rhythm.md new file mode 100644 index 0000000..431b561 --- /dev/null +++ b/framework/catalog/pi/skills/prose-craft/references/sentence-rhythm.md @@ -0,0 +1,138 @@ +# 句法节奏三轴:主谓先行、句长控速、模式转折 + +> 来源:《写作工具》(Roy Peter Clark《Writing Tools: 55 Essential Strategies for Every Writer》)sentence-rhythm —— Tool 1(主谓先行)、Tool 18(句长控速)、Tool 8(模式转折)。源单元 frontmatter 的 source_chapter 另标注 Tool 7,但源正文无 Tool 7 的方法点,本条不含其内容。 +> 模式转折(轴 2)与《小说课》"克制中的破例"是同一方法点,两书合并的一条在 `pattern-and-break.md`,本文只留骨架与指针。 +> 本方法基于英语句法,中文落地处均标注【中文适配】。 + +## 原文摘录(全量) + +以下三处引文均出自。 + +> Rebels seized control of Cap Haitien, Haiti's second largest city, on Sunday, meeting little +> resistance as hundreds of residents cheered, burned the police station, plundered food from port +> warehouses and looted the airport, which was quickly closed. +> +> — Roy Peter Clark, *Writing Tools* (Tool 1) + +> A pure parallel construction would be "Boom, boom, boom." Parallelism with a twist gives us +> "Boom, boom, bang." ... By breaking the pattern, he lends more emphasis to the final element. +> +> — Roy Peter Clark, *Writing Tools* (Tool 8) + +> Long sentences — I sometimes call them journey sentences — create a flow that carries the reader +> down a stream of understanding, an effect that Don Fry calls "steady advance." A short sentence +> slams on the brakes. +> +> — Roy Peter Clark, *Writing Tools* (Tool 18) + +## 方法骨架:三轴系统 + +句法节奏不是玄乎的"文笔",而是三个可调度的旋钮,Clark 在这 3 个 tool 中分别处理(Tool 1 · Tool 8 · Tool 18)。 + +### 轴 1:主谓先行(Locomotive Sentence,Tool 1) + +英语的"火车头"模型:主语+动词放在句首作为**机车**,其他成分(从句、介词短语、分词)**向右拖挂**。Steinbeck 几乎每句都用此结构;Quindlen 故意把主谓拉开 31 词制造悬念。 + +- 决策规则:**默认把主谓放前**(locomotive 拉车厢)→ 清晰、动力、可读。 +- **偶尔把主谓放后**(用于悬念、发现、旅程)→ 特殊效果。 +- 关键判断:**18 个词分隔主谓 = 致命**;31 个词分隔 + 主题庄重 = 出色。 + +### 轴 2:模式转折(Pattern-Twist,Tool 8) + +平行结构(句式、节奏、词汇、意象)建立稳固模式后,在结尾或关键处故意"反一手"——换词、变奏、加异常。"Boom, boom, boom" 变成 "Boom, boom, bang"。先建稳模式,再凿一处反——是"出人意料"的高效版本,不是不可预测的奇袭。 + +此方法点在 里有情感层版本(克制中的破例),两书合并成一条,案例、判断标准与中文形式见 `pattern-and-break.md`。 + +### 轴 3:句长控速(Sentence Length,Tool 18) + +- 长句 = journey sentence = 流体力学(读者被载着走)。 +- 短句 = slam on the brakes(急刹车)。 +- **5 种句长的战略目的**: + 1. 简化复杂(simplify the complex) + 2. 制造悬念(create suspense) + 3. 聚焦情感(focus on emotional truth) + 4. 段落开头减速 / 段末加速 + 5. 一句超长 = 庄重 + +这是**句子级架构的复合框架**——把"句法"从模糊的"文笔"重新框架为可调度的三轴旋钮。 + +## 书中的案例 + +### 案例 1:Steinbeck《Cannery Row》"Doc 的潮汐作息"() + +- **问题**:写自然主义场景如何让读者"被场景裹挟"? +- **方法的使用**:Steinbeck 用连续的"主谓 + 向右分枝"句子描写海洋生物学家 Doc 的早晨——一段没有明显标点的流水句。 +- **结论**:**右分支句**在自然描写里的"流体力学"——读者像坐船一样被句子载着走。 +- **结果**:成为"句法节奏"在英文文学课中的标准范例之一;展示了"形式追随材料"。 + +### 案例 2:Polgreen《纽约时报》海地报道() + +- **问题**:战地报道开头 37 词,如何既信息密集又可读? +- **方法的使用**:"Rebels seized control ... on Sunday, meeting little resistance as hundreds of residents cheered, burned, plundered, and looted, which was quickly closed."——每个动词都是具体动作(seized, cheered, burned, plundered, looted)。"Rebels seized control"前三个词是"火车头"——抓住了全部意义。 +- **结论**:主谓先行 = 战地报道的认知优势——读者第一秒就知道"谁做了什么"。 +- **结果**:NYT 的标准战地报道起手式之一;说明了"主谓前置"的认知优势。 + +## 操作步骤 + +1. **诊断主谓位置** + - 用 X 光标出每句的主谓位置(X 光即 Clark 的 X 光阅读:戴上 X 光眼镜透视文本底下的隐形机器,这里是逐句标出主语和动词的落点),看是否"主谓先行"或"主谓远置"。 + - 完成标准:每段 70% 以上句子是"主谓先行",只有特殊效果处主谓远置(主题庄重)。 + - 判停条件:若某段主谓远置过多,改写为机车结构。 +2. **列出 5 种句长比例** + - 在要修改的段落中,标出每句的字数(中)/ 词数(英)。 + - 理想:长-短-短-长 / 短-长-短-短等"有模式"的分布,**不是**长-长-长 / 短-短-短。 + - 完成标准:5 个相邻句子里,至少 3 种不同长度。 + - 判停条件:每段必须有 1 个"短句刹车"。 +3. **模式转折检验** + - 检查关键场景(高潮、转折点、情感峰值)是否有"模式-转折"。 + - 完成标准:每个关键场景至少有 1 处"建立模式 + 打破"的结构。 + - 判停条件:不是每段都要"模式转折",只在关键处用。 + +## 中文落地【中文适配】 + +Clark 的句法理论是英语的。中文小说作者需要本地化,不能直接套用: + +1. **"主谓先行"的中文版是"先动作后修饰"** + - 英语右分支:"She opened the door slowly."(主谓先 + 副词后) + - 中文对应:"她把门慢慢打开。"(动作+对象+方式)——而非"她缓慢地打开了那扇沉重的木门"。 + - 中文流水句(类似 Quindlen 的远置):"她走去开门,看见他站在雨里,手里拿着一束已经湿透的玫瑰,花瓣被风吹得七零八落。"——一气呵成,但 Clark 的 18 词 / 31 词界限不直接适用,中文的"语义句"比"语法句"长。 +2. **"模式转折"在中文里有特殊形式** + - 四字格堆叠 + 突然短句("他走了 / 没有回头。") + - 对仗 + 打破("长亭外,古道边,芳草碧连天" + "他死了。") + - 详见 `pattern-and-break.md`。 +3. **"句长控速"在中文是"逗号节奏"**——中文逗号密度比英文高,长句需要"句号"而不是"逗号"来刹车。 +4. **"翻译腔"检测**——中文写作者常见的 3 个翻译腔信号:"是"字句、被动语态、长定语后置。 + +## 失败模式(作者在书中警告) + +1. **主谓远置造成"读者溺水"(ce01)**:失败模式是 30+ 词分隔主谓,但主题不庄重。信号:读完一段后读者需要回头重读。机制:人脑短时记忆容量有限(7±2 项),过长前置修饰"溢出"工作记忆。预警:翻译腔、未消化的长定语后置。 +2. **句长单轨(ce07)**:失败模式是每句话一样长(即使都很短)。信号:每段都是"短-短-短"或"长-长-长"。机制:人脑对模式敏感,模式建立就期待重复——一致句长 = 无意外 = 无效果。预警:用"短句"代替"句长变化"。 +3. **"翻译腔"**:失败模式是英文句法直接套中文——"这是一件重要的事情,涉及......"(This is an important thing that involves...)。信号:句子里"是"太多、被动语态多、长定语后置。机制:中文是"意合",英文是"形合"。预警:每个段落都从"是"开始,或每段都有"被"字。 + +## 边界(不适用场景) + +- **实验文学 / 后现代解构**——故意打破语法的项目。 +- **诗歌**——句法规则与诗不同(虽然有交集)。 +- **短抒情 / 极简文风**——短句刻意一致,反而是设计。 +- **翻译文本**——翻译要保留原语种节奏,不应强加 Clark 的英语规则。 + +## 容易混淆的邻近方法 + +- 与"短句好 / 长句坏"的简单规则的区别:Clark 不是主张"只用短句",而是主张"句长差异是修辞杠杆"。同样不是主张"主谓必须在前",而是主张"主谓位置是调度旋钮"。 +- 与"风格 = 用词"的区别:句法节奏是"句子结构层",不是"词汇层"。 +- 与声音均衡器(本包 `voice-equalizer.md`):那是"整体声音的杠杆清单"(30+ 杠杆),这个是"句法层三轴"(主谓位置、句长、模式转折)。前者是宏观,后者是微观;本方法是它的节奏子模块。 +- 与镜头距离(scene-craft 域 cinematic-distances):那是"摄影机距离"在叙事单元间的调度,这个是"句法节奏"在句子间的调度。前者是"镜头",后者是"句间"。 +- 与对话即行动(dialogue-craft 域 dialogue-as-action):那是"对话的功能化"(做事),这个是"对话的句法"(节奏)。前者管"对话做什么",后者管"对话怎么说"。 +- 与抽象梯子(本包 `abstraction-ladder.md`)的搭配:抽象句与具体句交替;上梯产出的格言句,配本方法的短句刹车最有力。 + +## 激活场景与信号 + +场景: + +1. 写完一段后觉得"读起来催眠"——句长单调,没有呼吸。 +2. 翻译腔太重,句子"主语+系动词+表语"太多,没有动作。 +3. 写长段描写,不知道何时该"刹车"放短句。 +4. 写对话后觉得"每个人的台词都一样长",没有节奏差异。 +5. 读到好句子想学,但不知道"为什么这个句子好"——Clark 的三轴可以诊断。 + +信号(用户的话里出现这些就应激活):"句法节奏" / "sentence rhythm" / "主谓先行" / "右分支句" / "locomotive sentence" / "句子太长" / "句长" / "模式转折" / "pattern-twist" / "boom boom bang" / "读者怎么读得下去" / "句子催眠" / "翻译腔" / "翻译体" / "句子读起来累" / "短句太多像在喊" / "主语和动词隔太远"。 diff --git a/framework/catalog/pi/skills/prose-craft/references/voice-equalizer.md b/framework/catalog/pi/skills/prose-craft/references/voice-equalizer.md new file mode 100644 index 0000000..e16b1d1 --- /dev/null +++ b/framework/catalog/pi/skills/prose-craft/references/voice-equalizer.md @@ -0,0 +1,122 @@ +# 声音均衡器:把"风格"从神秘变工程 + +> 来源:《写作工具》(Roy Peter Clark《Writing Tools》)voice-equalizer —— Tool 23 "Tune your voice · Read stories aloud",借用写作教师 Don Fry 的"声音"定义。 +> 中文杠杆补充(对仗、四字格、节奏点、语气词、标点中文化、声调)为中文适配内容,单独成节。 + +## 原文摘录(全量) + +以下引文出自。 + +> Voice is the sum of all the strategies used by the author to create the illusion that the writer +> is speaking directly to the reader from the page. … Think of a piece of sound equipment called +> a graphic equalizer. This is the device that creates the range of sounds in an amplifier by +> providing about thirty dials or levers. +> +> — Roy Peter Clark, *Writing Tools* (Tool 23), quoting Don Fry + +## 方法骨架 + +Clark 在 Tool 23 中借用了写作教师 Don Fry 的"声音"定义,并配上一组工程比喻: + +- **声音不是人格**——它是作者**营造的"在纸上直接对读者说话"的幻觉**。三个关键词:create(创造)、illusion(幻觉)、speaking(在说话)。 +- **声音是合成效果**——由约 **30 个杠杆(dials/levers)** 同时调节而成:语言层级、口语 vs 书面语比例、句长分布、句型变化、词汇正式度、节奏、修辞密度、抽象-具体比、人物视角、对话密度、感官细节、情感强度、典故来源、距离感、立场温度、框架方式、隐喻密度、是否用方言/俚语、第一人称或第三人称、内心独白比例、引语密度、标点使用、段落长短、章节切分、甚至空格与空白…… +- **图形均衡器(Graphic Equalizer)比喻**:每个杠杆都是音响上的一个"频段旋钮",可调高调低。模仿海明威 = 看见他把"句长旋钮"压短、"形容词旋钮"调低、"感官细节旋钮"调高;模仿张爱玲 = 看见她把"对仗旋钮"调高、"感官旋钮"调中、"心理距离旋钮"近。 +- **核心操作**:列出 30 杠杆 → 选定基线作家(模仿对象或自己的稳定稿)→ 在每根杠杆上读出当前位置 → 想去的方向 → 调高/调低。 +- **关键判断**:"听起来像"不是玄学,是 30 个滑块的某种特定组合。 + +把"风格"从"做你自己 / 找到你的声音"这种**神秘口号**重新框架为**可拆解、可诊断、可调节**的工程问题——这是 Clark 整个 Tool 23 的贡献。 + +## 书中的案例() + +### 案例 1:E. B. White 11 岁在《St. Nicholas》杂志发表的故事 + +- **问题**:"作者声音"到底是后天养成,还是天生注定? +- **方法的使用**:Clark 引用同事 David McCord 的回忆:McCord 偶然读到一篇儿童故事,文中"他知道我十一岁生日那天的所有感受"——McCord 心里说"这听起来像 E. B. White",然后看署名:**Elwyn Brooks White, age 11**。 +- **结论**:White 11 岁就已经拥有"声音"——这证明声音**不是"后天学会"**而是**"被发现 + 被调谐"**。配合 graphic equalizer 模型:每个写作者生来就有这 30 个旋钮的**初始位置**(口音、家庭、阅读偏好早就塑好了),工作不是"创造声音",而是**识别初始位置 + 调试想去的方向**。 +- **结果**:Clark 用此例反对"声音是天赋"的本质主义,把"找到你的声音"从浪漫口号改成**可逆向工程的任务**——先测自己的旋钮在哪,再问想去哪。 + +### 案例 2:海明威 vs 菲茨杰拉德——同一时期不同"均衡器" + +- **问题**:模仿海明威,为什么只学到了"短句 + 不用形容词",还是不像? +- **方法的使用**:Clark 用 30 杠杆框架做对比诊断——海明威把"句长"压到 4-8 词、"感官细节(具体)"调高、"心理距离"远、"修辞密度"压低、"对话密度"中等。菲茨杰拉德则把"句长"调到 15-25 词、"修辞密度"调高、"心理距离"近、"感官细节"调中(更华丽抽象)。**表面看一个短一个长,本质是 30 个滑块的不同组合。** +- **结论**:模仿不是"抄一两个标志",而是**把目标作家的 30 个旋钮逐一读出位置**,再把自己的均衡器调到那个组合。 +- **结果**:提供了"模仿学习"的可操作路径——不再是"读 50 本找感觉",而是"读 3-5 个章节,用 X 光透视出 30 旋钮的设定"。 + +## 操作步骤 + +1. **列出 30 个杠杆(List the 30 dials)**——让用户对照下面 30 杠杆清单,逐一标注"当前我的设定(高/中/低)": + + - **句法层**:① 句长分布(短/中/长)② 句型变化(主谓前置/后置)③ 主谓位置 ④ 主动/被动比 ⑤ 修辞密度 ⑥ 段落长短 ⑦ 标点使用密度 + - **词汇层**:⑧ 词汇正式度(口语/书面)⑨ 抽象-具体比 ⑩ 方言/俚语比例 ⑪ 典故来源(古典/现代/无)⑫ 行业行话密度 + - **声音层**:⑬ 对话密度 ⑭ 引语 vs 对话比例 ⑮ 内心独白比例 ⑯ 第一/第三人称 ⑰ 人物视角距离 + - **感官层**:⑱ 视觉细节 ⑲ 听觉细节 ⑳ 嗅觉/触觉/味觉 ㉑ 修辞(明喻/暗喻)密度 + - **修辞层**:㉒ 距离(远/近)㉓ 立场温度(冷/热)㉔ 情感强度 ㉕ 节奏点(短句爆点)㉖ 框架方式(全知/限知) + - **结构层**:㉗ 章节切分 ㉘ 空白使用 ㉙ 章节标题风格 ㉚ 段首句惯例 + + - 完成标准:30 个杠杆中至少 25 个被标注。 + - 判停条件:标记为"无意识/不知道"也算一次标注(后续调试对象)。 + +2. **选定基线(Pick a baseline)** + - 问用户:**"你想模仿谁?或者你自己哪一章最满意?"**——选定一个基线文本(模仿对象的一篇,或自己最满意的一章)。 + - 用 **X 光阅读**:读 3-5 个章节,逐一标注基线在 30 杠杆上的位置。 + - 完成标准:拿到一份"基线 30 旋钮位置表"。 + - 判停条件:基线必须可读出 25+ 旋钮位置,否则换基线。 + +3. **调高调低(Tune up/down)** + - 拿当前稿的"30 杠杆位置表"和"基线 30 杠杆位置表"对比,标出差值最大的 5-8 个杠杆。 + - 选 1-3 个杠杆,做局部改写测试(改 500-1000 字),只动这一根杠杆,看是否更像基线。 + - 完成标准:完成至少 1 根杠杆的"调高/调低"测试,并通读自检"像不像基线"。 + - 判停条件:若调完 1 根杠杆后"反而更不像",**回退**,换另一根杠杆(说明那根杠杆不是主因)。 + +## 中文落地【中文适配】 + +Don Fry 的定义原属英语新闻业:Don Fry 是 Poynter 新闻研究所的写作教师,他的"30 杠杆"是为**英语非虚构**总结的。**迁移到中文小说需要补全中文特有的杠杆**: + +- **对仗 / 骈文密度**(中文独有,鲁迅/张爱玲都大量使用) +- **四字格 / 成语密度**(中文的"压缩信息"杠杆) +- **节奏点(七字句 / 五言节奏)**(中文的内在韵律感) +- **语气词密度**("呢 / 啊 / 吧 / 嗯"——决定"京味 / 沪语 / 港式") +- **标点中文化**(顿号、省略号、引号样式)——和英文杠杆系统不同 + +**时代局限(2006 年英文版)**——未涵盖**网文 / 弹幕体 / 微博体**的声音系统,这些是 2010 年后兴起的"新 30 杠杆"(括号表情、截图体、emoji 节奏点),需另行补充。 + +**盲点:无声调意识**——Don Fry 的英语杠杆不包括"声调 / 音韵",但中文有声调,中文的"对仗"+"节奏点"+"声调"构成的中文声律系统,需要在迁移时**额外补 3-5 根杠杆**。 + +## 失败模式(作者在书中警告) + +1. **把"工具"当"规则"硬套(ce17)**——以为 30 杠杆"必须**全部**调到中位",结果写出来四不像。**信号**:写完一段自检 5+ 个杠杆位置。**机制**:工具是"在多数情况下有效"的杠杆,不是"必须遵守"的规则;知道何时**不调**比知道何时**调**更难。 +2. **杠杆混乱 = 没有风格**——30 旋钮各调各的,每段声音都不一样。**信号**:同章内对话密度忽高忽低、句长分布无规律、距离感忽远忽近。**机制**:风格 = 杠杆组合的**一致性**,不是"每个杠杆都用上"。**解药**:选定基线 + 围绕基线微调,不要每根都创新。 +3. **模仿变抄袭**(未在书中明列,但属于此方法必警告)——把基线作家的"标志杠杆"(海明威短句)调到极端,自己的杠杆全部抹掉。**信号**:写出来一句,通读发现完全是海明威的句子、自己没贡献。**解药**:选基线时选 1-2 个杠杆学,其余保持自己的;**模仿是参考,不是替换**。 +4. **"教科书式"对话(ce24)**——每句对话完整、无语气词,杠杆 ⑬(对话密度)和 ⑭(口语比例)失调。详见 dialogue-craft 域 dialogue-as-action。 + +## 边界(不适用场景) + +- **单篇短文(< 2000 字)**——30 杠杆组合尚未沉淀,均衡器比喻失效,改用句法节奏(本包 `sentence-rhythm.md`)即可。 +- **学术论文 / 商业文案**——声音不是核心目标(目标是把事说清楚 / 卖出去),调音会牺牲清晰度。 +- **诗歌**——诗歌的"声音"在音步 / 韵律 / 跨行上有自己的 30 杠杆系统,与散文的杠杆不同。 +- **跨语言翻译文学**——模仿某作家的"声音",原语种的杠杆系统(如英文的句法节奏、中文的四字格对仗)无法直接迁移,会失真。 + +## 容易混淆的邻近方法 + +- **与"风格 = 用词"(误解)**——很多人以为"风格"就是"用词"——用大词 vs 小词、书面 vs 口语、典雅 vs 俚俗。但 voice-equalizer 明确:**风格 = 30 杠杆的组合**,用词只是 30 杠杆中的 3-4 根(⑧ 词汇正式度 ⑩ 方言比例 ⑪ 典故来源 ⑫ 行话密度)。只看用词是**以偏概全**。 +- **与"作者声音 = 角色声音"(混淆)**——很多中文写作教学把"声音"等同于"角色对话的口音",但 voice-equalizer 管的是**作者自己的叙述声音**(作者在纸上对读者说话的口吻),人物对话只是 30 杠杆中"对话密度 + 人物视角"两个旋钮。**作者声音 ≠ 人物声音**。 +- **与"找到自己的声音"(神秘主义)**——把"声音"当成"做你自己"的口号,反对可拆解;voice-equalizer 明确:声音**不是"找到"**而是**"调试"**,从已有的初始位置出发,调到想去的地方。 +- **与"风格 = 流派"(genre)**——流派(武侠 / 悬疑 / 科幻)是**题材 + 情节范式**,声音是**语言风格**;同一个流派可以有 30 种声音。voice-equalizer 不管流派,管语言。 +- **与退一步/进一步(本包 `rhetoric-density.md`)的区别**:那个是**单一杠杆的反比关系**——"修辞密度反比主题重要性"(轻主题用重修辞,重主题用轻修辞)。这个是**整体声音的 30 杠杆清单**——视野更大,管所有杠杆的组合,而非单杠杆的反比。back-off-show-off 是 voice-equalizer 的**一个子旋钮**。 +- **与句法节奏(本包 `sentence-rhythm.md`)的区别**:那个管**句法节奏**(短-中-长交替、句首动词、主动语态),只覆盖 30 杠杆中的"句长 / 句型 / 主谓位置"等 3-5 个旋钮。这个是**整个声音系统**——包括节奏、视角、距离、词汇、对话密度、感官、修辞等所有杠杆。sentence-rhythm 是 voice-equalizer 的**节奏子模块**。 +- **与对话即行动(dialogue-craft 域 dialogue-as-action)的区别**:那个管"对话的功能化"(推进 / 暴露 / 改变权力),是 30 杠杆中"对话密度 + 人物声音"两个旋钮的**功能论**。这个管"作者声音"的合成,人物声音是其中一环。 +- **与抽象梯子(本包 `abstraction-ladder.md`)的区别**:那个管"抽象-具体"一个**纵轴**,是 30 杠杆之一(且只占一维)。这个管 30 个杠杆的**整体并联**。 +- **与基础体温(本包 `base-temperature.md`)的呼应**:毕飞宇用一个"默认温度"抓住风格辨识度,温度大致落在 ㉓ 立场温度与 ㉔ 情感强度两根杠杆上;体温模型对中文写作者直观,杠杆模型便于精细诊断,两套互证。 +- 跨域一句话指针:与细节马赛克(character-presentation 域 mosaic-of-detail)——人物声音需要细节支撑;与镜头距离(scene-craft 域 cinematic-distances)——看声音系统在哪些镜头距离上表现;与叙事模式混合(narration-pov 域 mix-narrative-modes)——看不同叙事模式下声音如何变;与煽动事件(story-structure 域 inciting-incident)——开篇声音为全书定调。 + +## 激活场景与信号 + +场景: + +1. **风格自我诊断**——写了几万字,读起来"不像我"或"像三个人写的",但说不出哪里不对。 +2. **模仿学习**——读海明威/张爱玲/鲁迅/汪曾祺很喜欢,想在自己写作里复现那种味道,但只学了皮毛(短句 / 不用形容词 / 句号多)。 +3. **长篇声音漂移**——三十万字长篇,写到中段发现"前 10 章"和"后 10 章"语气不一样,自己没察觉,读者已经察觉。 +4. **风格定位**——新作者问"我到底是什么风格?",无工具,只能凭感觉。 +5. **跨体裁混乱**——同一人写小说和写散文,声音系统不统一,被读者评论"你写小说时像另一个人"。 + +信号:"作者声音" / "voice" / "个人风格" / "如何形成风格" / "怎么像某个作家" / "模仿海明威" / "学张爱玲" / "学鲁迅" / "声音均衡器" / "graphic equalizer" / "30 个杠杆" / "风格统一" / "声音漂移" / "写着写着不像我了" / "风格分析" / "我的风格是什么" / "找到自己的声音" / "声音不统一" / "听起来像三个人写的" / "Don Fry" / "Clark 写作工具" / "Tool 23"。 diff --git a/framework/catalog/pi/skills/scene-craft/SKILL.md b/framework/catalog/pi/skills/scene-craft/SKILL.md new file mode 100644 index 0000000..564186d --- /dev/null +++ b/framework/catalog/pi/skills/scene-craft/SKILL.md @@ -0,0 +1,95 @@ +--- +name: scene-craft +description: | + 小说场景执行方法:给每个场景定使命、定详略、定进出点、定镜头距离,把相邻场景排成节奏, + 再把拼装痕迹蒙蔽掉。用户建场景、改场景、诊断场景时激活:"这个场景有什么用、场景散、 + 小说拖、场景太慢、不知道该详写还是略写、字数安排不合理、过渡生硬、场景扁平、没画面感、 + 全程中景、场景切换不自然、读者出戏、高潮没力"。 + 关键 trigger:"场景使命 / 场景任务 / scene mission / 晚进入 / 早退出 / enter late leave early / + 场景进入退出 / 场景节奏 / 场景紧凑 / 详写略写 / 字数安排 / 过渡 / 镜头距离 / 摄影机距离 / + 拉远推近 / 远景中景特写 / 鸟瞰 / 建立镜头 / cinematic distances / 没画面感 / 场景扁平 / + 全程中景 / 对质戏 / 对峙戏 / 群像戏 / 回忆与现实切换 / 突兀 / 不自然 / 拼装痕迹 / 蒙蔽 / + 读者出戏"。 + 不适用于:整体篇章结构与里程碑(用 story-structure)、对话写法(用 dialogue-craft)、 + 展示与留白的一般原则(用 show-and-omission)、视角选择与叙述模式(用 narration-pov)、 + 没有场景概念的非虚构与诗歌散文、剧本台词部分、纯抒情独白与全程单一距离的意识流章节、 + 三千字以下切不开档的极短篇。 + 与 foreshadow-payoff 交接:有「埋了没收 / 契诃夫之枪 / 铺垫债」语境 → foreshadow-payoff; + 仅「这个场景高潮没力 / 进出点弱」→ 本 Skill。 + 与 narrative-momentum 交接:跨场景章末钩子、弃读、势链归后者;单场景使命与排节奏归本 Skill。 +--- + +# 场景执行 + +场景执行解决六件事:这个场景干什么、给它多少篇幅、从哪里进从哪里出、用多远的镜头拍、相邻场景怎么排、拼装痕迹怎么藏。前三件决定场景成不成立,第四五件决定它好不好读,最后一件决定读者会不会出戏。 + +## 方法索引 + +### 定使命:这个场景干什么 + +- 一个场景只交付一个戏剧使命:一条关键事实、一个不可逆决定,或一次改变主角状态的推进;写前写后各用一句话验证,说不清就该删或并 → references/scene-mission.md +- 使命分三种(信息型 / 决策型 / 动作型),共同点是改变故事的下一步走向,不要造第四种;使命必须达到"改变故事走向"的量级 → references/scene-mission.md +- 一场塞两个以上使命就拆;整篇统计:全部有使命算通过,两个以上没使命就删或并 → references/scene-mission.md + +### 定详略:给多少篇幅 + +- 这一刻故事的核心是冲突、转变、启示就详写,核心是推进、过渡、背景就略写;详写给读者必须知道感受的,略写给读者不必知道但你自己要懂的 → references/scene-detail.md +- 不重要的过渡三个字打发,略写场景用动作词扛,字数拿"数他几字"来校准而不是照抄 → references/scene-detail.md + +### 定进出:从哪里进,从哪里出 + +- 晚进入早退出:跳过寒暄铺垫直接落在戏剧爆发那一刻,张力释放完立刻切下一场 → references/scene-entry-exit.md +- 进入问"读者现在还不知道什么",退出问"读者需要知道的都知道了吗",答案就是剪切点 → references/scene-entry-exit.md + +### 定镜头:用多远的距离拍 + +- 五档焦距各管一件事:鸟瞰交代格局、建立镜头带出场所氛围、中景处理动作对话、特写推到情绪、极端特写钉住关键细节;每写完一段问自己"我现在是哪一档" → references/scene-camera.md +- 给死亡、告白、揭露这类关键瞬间指派距离;一个场景内切换三档以上;全程中景是场景扁平的头号原因 → references/scene-camera.md + +### 排节奏:相邻场景怎么排,哪里换气 + +- 三种节奏模式(紧-紧-紧 / 详-略-详 / 略-略-详),不知道选哪个就默认详-略-详;过渡要短,是节奏的屏息 → references/scene-rhythm.md +- 全书要有快有慢:慢场景留着建氛围,长篇中段放一个鸟瞰或建立镜头给读者换气 → references/scene-rhythm.md + +### 藏拼装:别让读者看见接缝 + +- 没有"自然"的小说,都是拼装出来的;唯一值得诟病的是拼装被当场看穿 → references/scene-mystification.md +- 用桥梁叙述和细节延续掩盖接缝,禁止作者亲自跳出来替读者解读人物;收尾做一次盲测 → references/scene-mystification.md + +### 边界与误区 + +- 什么时候不要用这套方法、十一个常见误区、各书盲点与中文适配 → references/boundaries-and-pitfalls.md + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|----------| +| references/scene-mission.md | 场景使命原文引文;一场一使命与三种使命类型;写前写后一句话验证法;詹姆斯·帕特森百章一场一使命案例;一场塞三件事与零使命咖啡馆反例;场景改稿五步与统计标准 | +| references/scene-detail.md | 详略判断核心标准(冲突/转变/启示详写);四个技术(数他几字、三个字过渡、惯性场景去留、动作词概括);五个常见错误;布兰德原文引文;福特"知道一切"案例;场景诊断五问与六步执行流程 | +| references/scene-entry-exit.md | 晚进入早退出原文引文;进入跳什么、退出跳什么;读者知道/不知道两问判定剪切点;去前妻家平铺版与晚入版对照示范;进入太早三页变半页、退出太晚两页变半页反例;单场景五步执行 | +| references/scene-camera.md | 五档镜头距离原文引文与各档功能;Turn your notebook into a camera;克拉克一段四距离金标准;《哈姆雷特》独白换档案例;距离分布诊断阈值(八成可标、中景六成警告);关键瞬间指派距离;场景内切三档;长文中段换气段 | +| references/scene-rhythm.md | 三种节奏模式及选择法;好坏过渡的标准与例句;过渡是节奏的屏息;全书有快有慢(三书视角合并:慢场景的价值、统一节奏是错误、长篇中段鸟瞰换气) | +| references/scene-mystification.md | 蒙蔽三段原文引文;所有作品都是拼装;蒙蔽成功/失败征兆;作者亲临的危险与"站着喝酒";蒙蔽与欺骗的区分;间歇性认知;《荒凉山庄》成功案例;《伪币制造者》反例;菲尔丁/萨克雷小酒馆旁白极端失败;五步执行与盲测 | +| references/boundaries-and-pitfalls.md | 五个源单元的不适用场景汇总;常见误区(多使命、零使命、过渡详写、高潮写快、全程中景、为换而换、极端特写堆砌、技法展览、作者亲临等);各书盲点与时代局限;中文适配(中文段落单位、网文与对话体、留白传统、说书人说书人亲临);易混方法区分;规则冲突标注 | + +## 脚本 + +| 脚本 | 用途 | 来源 | +|------|------|------| +| references/scene-revision-checklist.md | 场景改稿五关检查清单:使命关、详略关、进出关、距离关、蒙蔽关,含全部量化阈值与判停条件 | 五个源单元的执行步骤合并 | +| references/scene-ledger-template.md | 场景台账模板:场景清单逐场登记使命、详略、字数、节奏模式、进出点、镜头距离 | /scene-mission-driven;/fiction-scene-craft;/scene-enter-late-exit-early;/cinematic-distances | + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/pi/skills/scene-craft/references/_coverage.md b/framework/catalog/pi/skills/scene-craft/references/_coverage.md new file mode 100644 index 0000000..8235dbc --- /dev/null +++ b/framework/catalog/pi/skills/scene-craft/references/_coverage.md @@ -0,0 +1,19 @@ +# scene-craft 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| aspects-of-the-novel/mystification | references/scene-mystification.md | +| aspects-of-the-novel/mystification | references/boundaries-and-pitfalls.md | +| becoming-a-writer/fiction-scene-craft | references/scene-detail.md | +| becoming-a-writer/fiction-scene-craft | references/scene-rhythm.md | +| becoming-a-writer/fiction-scene-craft | references/boundaries-and-pitfalls.md | +| story-engineering/scene-enter-late-exit-early | references/scene-entry-exit.md | +| story-engineering/scene-enter-late-exit-early | references/scene-rhythm.md | +| story-engineering/scene-enter-late-exit-early | references/boundaries-and-pitfalls.md | +| story-engineering/scene-mission-driven | references/scene-mission.md | +| story-engineering/scene-mission-driven | references/boundaries-and-pitfalls.md | +| writing-tools-clark/cinematic-distances | references/scene-camera.md | +| writing-tools-clark/cinematic-distances | references/scene-rhythm.md | +| writing-tools-clark/cinematic-distances | references/boundaries-and-pitfalls.md | diff --git a/framework/catalog/pi/skills/scene-craft/references/boundaries-and-pitfalls.md b/framework/catalog/pi/skills/scene-craft/references/boundaries-and-pitfalls.md new file mode 100644 index 0000000..e01ad7b --- /dev/null +++ b/framework/catalog/pi/skills/scene-craft/references/boundaries-and-pitfalls.md @@ -0,0 +1,160 @@ +# 边界与误区:什么时候不用,哪里容易摔 + +> 本文件汇总五个源单元的不适用场景、失败模式、盲点与时代局限、易混方法,并标注规则冲突。方法本体见各主题文件:[scene-mission.md](scene-mission.md)、[scene-detail.md](scene-detail.md)、[scene-entry-exit.md](scene-entry-exit.md)、[scene-camera.md](scene-camera.md)、[scene-rhythm.md](scene-rhythm.md)、[scene-mystification.md](scene-mystification.md)。 + +## 不适用场景汇总 + +**scene-mission-driven(/scene-mission-driven)** + +- 场景的进入退出技巧(用 scene-enter-late-exit-early,即本包 [scene-entry-exit.md](scene-entry-exit.md)) +- 整体结构(用 structure-* 系列,现归 story-structure) +- 中短篇/单场景——不适用,整个故事 1 个 mission + +**scene-enter-late-exit-early(/scene-enter-late-exit-early)** + +- 场景的功能诊断(用 scene-mission-driven,即本包 [scene-mission.md](scene-mission.md)) +- 文学/意识流(这些场景故意慢,节奏不是快就好) +- 中短篇单场景(没"进入/退出"问题) + +**fiction-scene-craft(/fiction-scene-craft)** + +- 用户不知道怎么写故事——那是整体写作流程问题(原书路由 story-draft-flow,现归 story-planning) +- 写非虚构/技术文档——没有"场景"概念 +- 写诗/散文——节奏逻辑不同 +- 写剧本——剧本是按场景写,每一个都是"详写",不需要"详略" +- 写长篇(> 30000 字)——短篇的"详略"在长篇里要重新设计(每章有自己的"详略") + +**cinematic-distances(/cinematic-distances)** + +- 纯抒情独白 / 内心独白为主体的章节——这种章节本身就是"全程极端特写",不需要再切距离,切了反而稀释情绪 +- 极短篇(3000 字以下)——篇幅不够切 5 档,强切会显得凌乱;用句子节奏(sentence-rhythm,现归 prose-craft)即可 +- 学术论文 / 说明文 / 新闻消息——cinematic-distances 是叙事场景的杠杆,非虚构的应用面窄(只在叙事特写、报告文学中适用) +- 剧本(用舞台指示)而非小说——剧本已经有"舞台提示"的距离感,文字部分聚焦对话;cinematic-distances 适用于剧本的"场景说明"而非对话本身 + +**mystification(/mystification)** + +- 透明性优先的场景——如科学报告、新闻报道、合同;蒙蔽在这里是反价值 +- 刻意展示"思考过程"的场景——如辩论、咨询、教育;让学生/用户看到你的思考是合法目标 +- 元小说/元艺术——故意让作者出现的作品(如《项狄传》某些段落),不适用 +- 极简风格——一条推文、一个标签,没有"拼装",蒙蔽不适用 + +## 常见误区(按来源单元) + +### 来自 scene-mission-driven(《Story Engineering》) + +1. **1 场景塞多个 mission**:决定、见反派、拿信息塞进同一场,戏剧张力稀释,读者消化不了。修:拆成多场,各背一个 mission。 +2. **0 mission 场景**:角色在咖啡馆描述环境、想了想、离开,什么都没发生。修:删,或并入相邻场景。 +3. **把 Patterson 风格当唯一正确**:一场一使命一章一场是极致做法,不是教条。 +4. **Mission 太小**:如"角色出门"——mission 必须"改变故事走向"。 +5. **Mission 太多变体**:集中于"信息/决策/动作"3 种,不要造新类。 + +### 来自 scene-enter-late-exit-early(《Story Engineering》) + +1. **进入太早**:路上、停车、电梯、打招呼全写,浪费读者时间。修:跳到读者还不知道的那一点。 +2. **退出太晚**:戏剧已结束还写思考、讨论、打电话。修:决定已做就切下一场。 +3. **所有场景都晚入早出**:失去氛围/共情建立的时间;有时 1 句寒暄是共情建立。 +4. **删过渡后场景"割裂"**:需要用"白空间/换行"维持连贯。 + +### 来自 fiction-scene-craft(《成为作家》) + +1. **过渡场景写太多**:失重,读者疲倦。修:减到 3 个字,或动作词概括。 +2. **高潮场景写太快**:离婚谈判一段对话就完了,读者没感受到张力。修:高潮详写,短句+对话+动作密集。 +3. **所有场景一个节奏**:详写详写详写 = 读者累;略写略写略写 = 读者没感觉。修:模式 2 或模式 3。 +4. **不知道详写哪些**:什么都想完整描述。修:每次只详写当前冲突的核心。 +5. **模仿字数不知判断**:数了海明威 150 字,不知道为什么是 150 不是 50 或 500。修:字数是校准,不是摹本。 +6. **"X 说 Y 说"标签**:节奏断(对话标签问题归 dialogue-craft,原书见 fiction-dialogue)。 +7. **模仿风格 / 模仿题材**:模仿别人的"详略风格"永远不像;跟着用别人的场景结构也不行(原书失败模式 ce02、f10 条)。 + +### 来自 cinematic-distances(《写作工具》) + +1. **"全程中景"**(与 ce06 / ce07 同族):写作者一辈子只用"中景"——场景扁平、读者视觉疲劳、远无交代近无情绪。**信号**:一章里 80% 段落都是"人物 + 动作 + 对话",无任何"鸟瞰 / 建立 / 特写"。**机制**:中景是"安全区",作者躲在"叙述者默认距离"里不用冒险;但读者需要空间感(远)、情绪感(近)、物件感(极近)——这些中景都给不了。 +2. **"为换而换"**:反向失败——每段都换距离,读者头晕、失去空间锚点。**信号**:段落开头变化太快,读者每次都要"重新定位我在哪";"像剪辑师抽风"。 +3. **"极端特写堆砌"**:把极端特写当"形容词 / 意象",放 20 个细节而没有鸟瞰/建立来"清空"视觉。**信号**:一段里堆 5+ 个"小物件",失去"远-近"的对比张力,读者视觉过载。 + +### 来自 mystification(《小说面面观》) + +1. **作者亲临(作者亲自解说人物)**——菲尔丁/萨克雷的"小酒馆式东拉西扯"(ce05);把读者领进幕后("A 看着不错吧——我一直都特别喜欢她")。在过去的小说中,再没有比这一点更致命的了。 +2. **视角转换太刻意**——纪德式"技法展览吞掉人物"(ce12):转换之间的解说累赘,读者太在意作者创作技法,失去对人物的兴趣,热情骤降。 +3. **"站着喝酒"姿态**——让人没工夫批评你的想法,实际上贬低了读者。这不是蒙蔽,是引诱。 + +## 盲点与时代局限(按来源单元) + +### scene-mission-driven(《Story Engineering》) + +- Mission 假设"线性故事"——闪回/非线性可能 mission 重新定义 +- Mission 假设"主角 POV"——群像/POV 切换每个场景都需 1 mission +- Mission 默认"看得见"——内心独白场景 mission 是"信息"(角色领悟) + +### scene-enter-late-exit-early(《Story Engineering》) + +- 假设读者都急——实际部分读者喜欢慢/氛围 +- 假设"快" = "好"——部分场景需要慢(回忆/情感) +- 假设只用 1 种时间感——整本书应该有时快有时慢 + +### fiction-scene-craft(《成为作家》) + +- 1934 年没有"章节"概念——短篇通常没有章节,详略靠段落 +- 不区分"文学" / "类型"——类型小说(悬疑/科幻)对详略有不同要求(类型需要"节奏卡点") +- 没考虑"网文节奏"——网络连载要求"每章必有钩子",是另一套节奏(中文适配:这一条恰好与"一场一使命"的连载排法对接,见 [scene-mission.md](scene-mission.md) 中文落地条) +- "数他几字"假设你能"感觉"——这是经验,不是技术,初学者很难 +- 不区分"叙述视角"对场景的影响——第一人称场景限制更多 + +### cinematic-distances(《写作工具》) + +- **中文段落单位不同(中文适配)**:Clark 2006 年(英文版)写的是英语文学场景;在中文小说里,"段落"长度与英文不同——5 句话的中文段落可能对应 1 段英文。所以"5 距离切换"在中文里要看**整章 / 整场景**为单位,**不是段段必切**;否则会变成"段落碎片化"。 +- **新兴形式未覆盖(中文适配)**:Clark 时代没有网文 / 微信对话体 / 弹幕小说——他不讨论这些新兴形式的距离感。但这些形式本质是"全程极端特写 + 心理活动",与传统小说的"中景叙事"形成对比,值得中文写作者对照。 +- **中文留白传统(中文适配)**:中文写作者常用"留白"代替"建立镜头"(不写场景,直接对话,让读者脑补)。两者可互补:在留白处插入一个极端特写(一个物件),比纯留白更有"锚点"。 + +### mystification(《小说面面观》) + +- 现代主义巅峰期的视角——1927 年;当时还没有"打破第四面墙"作为合法艺术手法(如品钦、巴斯) +- **西方文学中心的视角(中文适配)**:中国评书/相声中"说书人亲临"是合法传统,西方小说中不一定(详见 [scene-mystification.md](scene-mystification.md) 中文落地条) +- 对"作者亲临"的全盘否定过激——某些伟大作品(《项狄传》《一个青年艺术家的画像》)故意让作者出现,福斯特未充分讨论这种情况 + +## 规则冲突标注(都保留) + +1. **"跳过寒暄" vs "1 句寒暄是共情建立"**——同出/scene-enter-late-exit-early:主规则要求晚进入时跳过寒暄铺陈,失败模式条又警告完全删寒暄会丢掉共情建立。取舍看场景使命:推进事件就跳,推进关系就留一句。 +2. **"作者亲临是致命的" vs "说书人亲临是合法传统 / 元小说故意让作者出现"**——/mystification 的主规则与其自身盲点条(1927 年后打破第四面墙成为合法手法、中国评书传统)之间的冲突。取舍看文体约定:文体承诺了叙述者在场,亲临就不是罪。 +3. **"场景内切 3+ 距离、一段四距离是金标准" vs "中文不是段段必切"**——/cinematic-distances 的英文示范与其中文落地盲点条。取舍按语言单位:英文按段数距离,中文按整场整章数距离。 +4. **"写长篇不适用(详略要重新设计)" vs "长篇中段放鸟瞰换气段"**——/fiction-scene-craft 说的是短篇详略体系不直接套长篇;/cinematic-distances 说的是长篇距离调度。两者不是真冲突:前者管详略体系按章重建,后者管距离换气,长篇里同时成立。 + +## 易混方法与相邻区分(按来源单元) + +### scene-mission-driven + +- "Single Beat per Scene"(Snyder)——接近,但 Snyder 强调"节拍" +- "Scene-Sequel"(Dwight Swain)——是另一种结构(场景-反应),不是 mission +- "MRU"(Motivation-Reaction Unit)——是"角色心理单元",不是"场景使命" + +### scene-enter-late-exit-early + +- "Show, Don't Tell"——接近,但 Show 主要是"演示" vs "陈述"(现归 show-and-omission) +- "Scene-Sequel"(Swain)——是"场景+反应"2 段结构,不是节奏 +- "Cinematic Writing"(影视)——接近,但影视可视觉化,文字更需紧凑 + +### fiction-scene-craft + +- "三幕剧"结构——是**结构**,不是详略(现归 story-structure) +- "故事弧"(Story Arc)——是**张力曲线**,不是详略 +- "节奏卡"(Pacing Beats)——是**电影/网文术语**,类似但不同 +- 与 fiction-dialogue(现归 dialogue-craft):对话是工具,场景是框架 +- 与 fiction-opening(现归 story-structure):第一句是局部,场景是贯穿 +- 与 imitate-technique-not-style(已按合并计划裁剪):那是"学别人的字数安排",本方法是"自己判断字数";前者是模仿,后者是原创 +- 与 story-draft-flow(现归 story-planning):那是整个流程,本方法是其中场景阶段的内部技术 + +### cinematic-distances + +- 与 show, don't tell(《写作工具》Tool 27,现归 show-and-omission):show 管"用什么"(用证据代替断言),cinematic-distances 管"在哪看"(在 5 档里切换视距);一个特写段如果只 show 证据而不在正确的距离,效果有限 +- 与 mosaic-of-detail(Tool 54,现归 character-presentation):前者用"9 类细节拼人物",本方法用"5 个距离拼场景";一个专注人物,一个专注空间;两者可叠加——人物登场段可以先"建立(看见房间)+ 中景(看见人)+ 极端特写(看见他手上的戒指)" +- 与 active verbs(Tool 3,同书工具,未入本库):active verbs 是"动词力度"(句子内部),cinematic-distances 是"距离切换"(段落/场景级别);一个微观,一个中观 +- 与 pattern-twist(Tool 8,同书工具,未入本库):pattern-twist 是"先建模式再打破"(句式层),cinematic-distances 是"在 5 档里切换"(空间层);两者都可制造"裂缝"让读者注意力回弹——一个在词法层,一个在空间层 +- 与 back-off / show-off(Tool 21,现归 prose-craft):back-off/show-off 是"严肃时克制、轻松时炫技"(作者声音的音量),cinematic-distances 是"切换视距"(摄影机的距离);一个是作者的存在度,一个是读者的视距 +- 与 mix-narrative-modes(Tool 36,现归 narration-pov):那个管"**何时**跳出动作做解释/反思/独白"——是叙事模式的开关(主线 / 折线);本方法管"在 5 档距离里**现在停在哪一档**"——是空间视距的开关(远 / 中 / 近);一个是"动作里 vs 动作外",一个是"远 vs 近" +- 与 sentence-rhythm(Tool 18,现归 prose-craft):那个管句长搭配,是**时间**节奏(快/慢);本方法管视距远近,是**空间**节奏(远/近);一个是油门,一个是方向盘,可同时调但作用不同 +- 与 dialogue-as-action(Tool 26,现归 dialogue-craft):那个管对话的功能化;本方法决定"对话放在哪个距离"——对话通常在中景,情感高潮在特写;两者正交,中景对话推进情节是好的,特写对话放大情绪也是好的 + +### mystification + +- vs 沉浸式设计(Immersive Design):沉浸式追求"用户感觉不到界面",与蒙蔽相似但目标不同(蒙蔽是叙事/技术,沉浸式是产品/界面) +- vs 透明性(Transparency):透明性是反蒙蔽,故意让过程可见 +- vs 4th wall breaking(打破第四面墙):故意让作者/演员出现,是反蒙蔽 diff --git a/framework/catalog/pi/skills/scene-craft/references/scene-camera.md b/framework/catalog/pi/skills/scene-craft/references/scene-camera.md new file mode 100644 index 0000000..d0b14fb --- /dev/null +++ b/framework/catalog/pi/skills/scene-craft/references/scene-camera.md @@ -0,0 +1,95 @@ +# 定镜头:五档焦距随时切换 + +> 来源单元:《写作工具》(Roy Peter Clark, *Writing Tools*)writing-tools-clark/cinematic-distances,Tool 34 · Write from different cinematic angles。 +> 本文件管"这个场景用多远的距离拍"。详略见 [scene-detail.md](scene-detail.md),长篇中段的镜头换气也收录在 [scene-rhythm.md](scene-rhythm.md),边界与误区见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> Aerial view. Establishing shot. Middle distance. Close-up. Extreme close-up. ... Simple descriptions +> of standard camera angles should help you imagine how to use your "word cameras" for a variety of +> effects. In that single paragraph, I measure at least four different distances from the author's +> camera to the subject matter. +> +> — Roy Peter Clark, *Writing Tools* (Tool 34) + +(/cinematic-distances) + +## 方法核心:五种标准距离 + +Clark 把"笔"当摄影机,把"叙事段落"当"镜头"。他给出 **5 种标准距离**,每种对应一种叙事功能:(/cinematic-distances) + +- **鸟瞰(Aerial view)**——"as if standing atop a skyscraper"——交代**位置、整体格局、世界的尺度**。读者需要"知道我们在哪里、事情多大规模"。 +- **建立镜头(Establishing shot)**——退后一步,带出**场所、氛围、时间感**。读者需要"看见这个房间 / 这条街 / 这一刻"。 +- **中景(Middle distance)**——"the common distance for most stories"——处理**人物动作、对话、互动**。是大多数叙事者的默认档位。 +- **特写(Close-up)**——"close enough to detect anger, fear, dread, sorrow, irony"——推到**情绪/心理层**。读者需要"看见人物此刻的状态"。 +- **极端特写(Extreme close-up)**——"focuses on an important detail that would be invisible from a distance"——聚焦**一个若不从极近看就看不见的细节**(流氓小指上的戒指、杯沿的唇印、鞋底的泥土)。读者需要"抓住这个物件/这个符号"。 + +Clark 的核心命令:**"Turn your notebook into a camera."**——把笔记本变成摄影机,5 档焦距随时切换。(/cinematic-distances) + +**判定方法**:每写完一段,问"**我现在用的是哪一档**"。Clark 自己的标准示范是:**一段之内出现 4 种距离**——这是高水平叙事的常规,不是炫技。(/cinematic-distances) + +**为什么大多数人只敢写中景?** 因为中景是"安全的叙述者距离",作者躲在这里不用冒险;但场景扁平、读者视觉疲劳、远无交代近无情绪。(/cinematic-distances) + +**与叙事模式开关的关系**:Tool 36 的"折线 / 不断线"是这一工具的延伸——什么时候"拉远做解释/反思"(折线),什么时候"推回场景中"(不断线),本质也是"距离切换",只是从"远-近"扩展到"内-外"。(叙述模式本身归 narration-pov 域,见/cinematic-distances) + +## 案例 + +### 案例 1:Clark 自己示范的"4+ 距离段落" + +- **问题**:写作者一辈子停在"中景安全区",写出来的场景像监控录像——读者看得见发生了什么,但**没画面感**。 +- **方法论的使用**:Clark 在 Tool 34 中给出 5 种距离,然后在**自己写的一个段落**里数出 4 种不同的距离——他把这个段落作为"金标准"示范,证明"高密度距离切换"在顶级写作中**很常见**,不是炫技。 +- **结论**:一个场景的"画面感"不靠形容词,靠**焦距调度**——读者在不同尺度上**重新看见**同一场景,获得空间感、情绪感、象征感。 +- **结果**:成为了"5 距离切换"的金标准示范;说明场景的"调度感"是**可数、可练**的工艺,不是天赋。 + +(/cinematic-distances) + +### 案例 2:莎士比亚《哈姆雷特》"生存还是毁灭"独白 + +- **问题**:主角在动作进行中需要"内心独白"——但独白会**打断动作链**;若直接插入独白,叙事节奏断裂。 +- **方法论的使用**:Shakespeare 用 cinematic-distances 解决——把镜头**从"中景"(动作)切到"极端特写"(人物心理)再切回**。独白是"特写停格",不是"另起一段"。读者在极近距离上**与哈姆雷特共呼吸**。 +- **结论**:极端特写是混合叙事模式(折线 / 不断线)的**视觉表现**——什么时候拉远(交代)、什么时候推近(情绪),由"读者此刻需要什么"决定。 +- **结果**:成为了 cinematic-distances 与 mix-narrative-modes 的**共同金标准**;说明两种工具(空间距离 / 叙事模式)在高手笔下是**同一种调度的两个面**。 + +(/cinematic-distances) + +## 可执行步骤 + +1. **诊断当前距离分布** + - 把一章/一个场景的每个段落标上"鸟瞰/建立/中景/特写/极端特写"5 档之一。 + - 完成标准:80%+ 段落被明确标上距离;无"中景含糊"(分不清是中景还是特写的)段落。 + - 判停条件:出现 ≥ 60% 中景 = **警告**,说明作者"只敢写中景",需要拉远和推近的练习。 +2. **指派关键瞬间的距离** + - 列出场中 3-5 个"情绪 / 信息 / 动作"的关键瞬间(死亡、告白、揭露、冲突顶点、回忆闪回),问"这个瞬间应该在哪一档"——**大多数作者把死亡/告白写在"中景" = 没换档**。 + - 完成标准:每个关键瞬间被指派一个明确距离(死亡=特写,战场=中景+鸟瞰,告白=特写+极端特写)。 + - 判停条件:关键瞬间仍在中景 = 重新设计段落,否则场景不会有情绪峰值。 +3. **在一个场景内切换 3+ 距离** + - 改写一个关键场景,保证一个段落或两个相邻段落内出现 **≥ 3 种距离**(常见:建立→中景→特写)。 + - 完成标准:改写后场景中可识别 3+ 距离切换;读者读后能"看见"空间(知道在哪里、人物多大距离、聚焦在哪)。 + - 判停条件:切换"为换而换" / 每段都换 5 词特写 = 矫枉过正,回头减;每个距离段至少 2-3 句再切。 +4. **可选:加一个"鸟瞰 / 建立"作节奏换气** + - 在长篇中段(读者开始疲劳处)插入 1 个**鸟瞰 / 建立镜头**段落,不带情节,只交代空间与时间——让读者"换气"。 + - 完成标准:鸟瞰/建立段不承载情节功能,只服务"读者呼吸";位置在中段 40-60% 处。 + - 判停条件:把鸟瞰当"省力"——一段不写的"空"段不叫鸟瞰,鸟瞰仍要**有具体内容**(晨光、街景、季节变化)。 + - 这一条同时是全书节奏手段,见 [scene-rhythm.md](scene-rhythm.md)。 + +(/cinematic-distances) + +## 激活场景与语言信号 + +适用范围(源单元 frontmatter「适用于」清单原样承接):小说场景戏、动作戏、对质戏、人物登场段、群像、回忆与现实切换、长篇中段的节奏"换气"段。(/cinematic-distances) + +用户会在这些情境下需要这条方法: + +1. 写一个场景戏,但读者说"读着读着走神了"——大概率**全程中景**,没在关键时刻推近或拉远。 +2. 写一段本应震撼的死亡 / 告白 / 揭露,读者只感到"信息"——情绪没推到特写,细节没收到极端特写。 +3. 写人物登场段,作者想"显示"但只会用"形容词 / 心理活动"——应该用"建立镜头 + 极端特写"代替抽象。 +4. 长篇中段读者弃读,作者想"换气"——一个"鸟瞰 / 建立镜头"段落能制造**节奏的窗口**,让读者重新定位。 +5. 写动作戏 / 战斗 / 追逐,作者发现"画面乱"——可能是 5 档切得太快,失去空间锚点,需要**先建立中景再换档**。 + +语言信号:"场景扁平 / 没画面感 / 像监控录像"、"全程中景 / 不会换距离 / 焦距不会切"、"镜头距离 / 摄影机距离 / cinematic angles / cinematic distances"、"拉远推近 / 远景中景特写 / 鸟瞰 / 建立镜头"、"读者看不到空间 / 读者走神"、"写场景像流水账 / 调度感不够"、"Turn your notebook into a camera / 把笔记本变成摄影机"、"show, don't tell 但 show 不出来"。(/cinematic-distances) + +## 中文落地(中文适配) + +- **段落单位不同**:Clark 2006 年(英文版)写的是英语文学场景;在中文小说里,"段落"长度与英文不同——5 句话的中文段落可能对应 1 段英文。所以"5 距离切换"在中文里要看**整章 / 整场景**为单位,**不是段段必切**;否则会变成"段落碎片化"。(中文适配;/cinematic-distances) +- **新兴形式对照**:Clark 时代没有网文 / 微信对话体 / 弹幕小说——这些形式本质是"全程极端特写 + 心理活动",与传统小说的"中景叙事"形成对比,中文写作者可对照理解各档位的取舍。(中文适配;/cinematic-distances) +- **留白传统互补**:中文写作者常用"留白"代替"建立镜头"(不写场景,直接对话,让读者脑补)。两者可互补:在留白处插入一个极端特写(一个物件),比纯留白更有"锚点"。(中文适配;/cinematic-distances) diff --git a/framework/catalog/pi/skills/scene-craft/references/scene-detail.md b/framework/catalog/pi/skills/scene-craft/references/scene-detail.md new file mode 100644 index 0000000..53aeb95 --- /dev/null +++ b/framework/catalog/pi/skills/scene-craft/references/scene-detail.md @@ -0,0 +1,168 @@ +# 定详略:该详写还是略写,给多少字 + +> 来源单元:《成为作家》(多萝西娅·布兰德)becoming-a-writer/fiction-scene-craft,第十章 + 第八章 + 第十一章。 +> 本文件管单个场景的篇幅判断。相邻场景怎么排见 [scene-rhythm.md](scene-rhythm.md),场景该干什么见 [scene-mission.md](scene-mission.md),边界与误区见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> "我们举例说吧, 在一个五千字的短入小说中你所模仿的作者用了一百五十个字描写他的主人公生活中的不怎么重要的一天一夜。 +> 那么你呢? 或许会用三个字, 或者用一句话这样写, ' 第二天康拉德如此这般'。 +> 总的来说, 这字数有点太少了。或者尽管康拉德的夜晚和早晨就故事本身而言并不重要, +> 尽管你已经在刻画主人公方面用完了所有的空间, 一旦你开始了, 你也许需要六百字。 +> 只是因为你没法停下来不写他。 +> 你学习的那位作者如何运用那些你数过的字来进行间接描写呢? +> 他是否选择使用了一些表达动作的词, 显示他的主人公虽然当时并没有做什么事去推进故事情节发展, +> 却仍然内心丰富呢? 他为故事的结局埋下了什么线索, 让他能够回归到真正的行动上去? +> 当你能够用这种方式尽可能多地有所发现时, 你就掌握了模仿的技巧。 +> 段话, 逐句模仿你的术科。" +> +> — 多萝西娅·布兰德,《成为作家》第十章 + +(/fiction-scene-craft) + +这段原文同时给出了本文件的四个技术:数他几字(一百五十字)、不重要的过渡("第二天康拉德如此这般")、惯性场景("你也许需要六百字, 只是因为你没法停下来不写他")、动作词间接描写("表达动作的词")。 + +## 核心判断:这个场景,该详写还是略写? + +这是场景写作的中心问题。(/fiction-scene-craft) + +- **详写**:给"读者**必须**知道/感受"的内容 +- **略写**:给"读者**不需要**知道/感受"的内容(但你**自己**要懂) +- **判断标准**:这一刻,故事的核心是**什么**? + - 核心 = 冲突 / 转变 / 启示 — 详写 + - 核心 = 推进 / 过渡 / 背景 — 略写 + - 核心 = 节奏 / 呼吸 / 对比 — 看情况 + +(/fiction-scene-craft) + +注意:这把"读者必须知道/不需要知道"的尺子,和晚进入早退出的进出判断是同一把尺子——进入问"读者还不知道什么",退出问"读者已经知道什么",见 [scene-entry-exit.md](scene-entry-exit.md)。 + +## 四个具体技术(怎么决定详写/略写) + +### 技术 1:"数他几字"(模仿字数) + +- 选一个要模仿的作者,**数**他在一个场景上用了多少字 +- 比如:5000 字短篇,主人公"不重要的"一天一夜,他用了 150 字 +- 你的判断:这个字数是"够"还是"不够"? +- **关键**:不是"模仿他的字数",是"用他的字数来校准自己的判断" +- 布兰德的洞察:**好的作家能"感觉到"一个场景需要多少字**——你在练习中校准 + +(/fiction-scene-craft) + +### 技术 2:"不重要的场景用 3 个字" + +- 不重要的过渡,**3 个字**就够:"第二天。" +- 不要:"第二天早晨, 阳光透过窗帘, 照在床头的书本上, 她翻了个身, 看到手机上有三条未读消息……" +- 为什么:**读者的注意力是有限的**,不重要的场景详写 = 失重 +- 例外:如果"不重要场景"本身有**隐喻功能**(如"三天三夜的雨"),详写 + +(/fiction-scene-craft) + +### 技术 3:"必须停下来写"(惯性) + +- 有时,**一旦开始写一个场景,就停不下来** +- 即使这个场景"不重要",但你**已经**在脑子里想了很久 +- 布兰德的洞察:"你也许需要六百字, 只是因为你没法停下来不写他" +- 怎么判断:写完一个场景,看——这 600 字**删掉**会影响故事吗? + - 影响 → 留下(即使看起来不重要) + - 不影响 → 删到 3 个字 + +(/fiction-scene-craft) + +### 技术 4:"动作词代替叙述" + +- 略写的场景,不是"略去",是"用动作/感官词概括" +- 坏:"那天晚上她想了很久。" +- 好:"她把信烧了。" +- 动作词 = 1-3 个字,暗示了"想了很久 + 决定 + 行动" +- **怎么练**:每个略写场景,找 1-2 个**动作/感官**词概括 + +(/fiction-scene-craft) + +## 五个常见错误(场景写作的陷阱) + +1. **"过渡场景写太多"**——"不重要"的过渡场景详写,浪费字数,失重,读者疲倦。**修**:减到 3 个字,或"动作词概括"。 +2. **"高潮场景写太快"**——关键场景**略写**,失去力量。例子:离婚谈判,一段对话就完了——读者没感受到张力。**修**:高潮场景应该详写,短句 + 对话 + 动作密集。 +3. **"所有场景一个节奏"**——详写详写详写 = 读者累;略写略写略写 = 读者没感觉。**修**:用"模式 2"(详-略-详)或"模式 3"(略-略-详),见 [scene-rhythm.md](scene-rhythm.md)。 +4. **"不知道详写哪些"**——写什么都想"完整描述",没有取舍。**修**:每次只详写**当前冲突的核心**,其他略过。 +5. **"模仿别人的字数但不知道判断"**——数了海明威 150 字,但不知道**为什么**是 150,不是 50 或 500。**修**:把"数"当作**校准**,不是"模仿";问自己"这个场景,150 字够吗?" + +(/fiction-scene-craft) + +## 案例 + +### 案例 1:布兰德的"数他几字"——校准判断 + +- **问题**:不知道一个场景该用多少字 +- **方法论的使用**:选一个作者,数他每个场景的字数 +- **结论**:用**他的字数**作为校准,不是模仿 +- **结果**:学会"感觉"一个场景该用多少字 + +(/fiction-scene-craft) + +### 案例 2:布兰德的"不重要 = 3 个字"——简略过渡 + +- **问题**:过渡场景写太多,失重 +- **方法论的使用**:"不重要的过渡 = 3 个字" +- **结论**:过渡是节奏的"屏息",不是另一个场景 +- **结果**:故事节奏紧凑,详略得当 + +(/fiction-scene-craft) + +### 案例 3:福特的方法——知道一切 + +- **问题**:不知道详写哪些细节 +- **方法论的使用**:前期准备"知道"一切(即使不写到) +- **结论**:你**知道**得越多,你的**判断**越准——该详写哪些,你知道 +- **结果**:写出来的人物动作**可信**,因为作者知道每个细节 + +(/fiction-scene-craft) + +## 可执行步骤(单篇详略安排) + +1. **诊断:用户的场景问题在哪** + - 完成标准:用户能指出"我的场景是 X 问题" + - 提问:"你的场景问题是——(a) 不知道详写哪些?(b) 详写太多?(c) 过渡拖沓?(d) 高潮没力?(e) 整体一个节奏?" + - 判停条件:若用户说"我都不知道场景是什么" → 先解决整体写作流程问题(原书路由到 story-draft-flow 阶段 1,现归 story-planning) +2. **第一步:列出场景清单** + - 完成标准:用户能列出故事的所有场景(5-15 个) + - 关键:每个场景一个名字(例:"第一次见面" / "三个月后" / "重逢") +3. **第二步:给每个场景标"详/略"** + - 完成标准:每个场景标 详 或 略 + - 关键:详写场景 = 5%-15% 故事字数,略写 = 1-3 个字或一段 +4. **第三步:选节奏模式** + - 完成标准:用户能说出"我用模式 X" + - 默认:模式 2(详-略-详) + - 关键:不要全详或全略(三种模式见 [scene-rhythm.md](scene-rhythm.md)) +5. **第四步:用"动作词"略写过渡** + - 完成标准:略写场景都有 1-3 个动作/感官词 + - 例:"她把信烧了。" / "那夜雨下到天明。" +6. **第五步:用"数他几字"校准** + - 完成标准:选一个作者,数他类似场景的字数,校准自己 + - 关键:这是**校准**,不是"模仿" +7. **第六步:写完不立即重读** + - 完成标准:写完后立刻放一边,至少隔一夜再看 + - 这条纪律原挂 set-aside-the-manuscript(作者状态管理,已按合并计划裁剪,不入 skill 库),纪律本身保留 + +(/fiction-scene-craft) + +配表使用:场景逐场登记见 [../references/scene-ledger-template.md](scene-ledger-template.md)。 + +## 激活场景与语言信号 + +用户会在这些情境下需要这条方法: + +1. "我场景之间切换不好"——过渡问题 +2. "我场景写得太平"——节奏问题 +3. "我不知道该详写还是略写"——决策问题 +4. "我场景字数安排不合理"——数字问题 +5. "我故事节奏拖沓"——整体节奏问题 +6. "我场景写太多/太少"——密度问题 +7. "我描写太多/对话太多"——比例问题 +8. "我过渡生硬"——衔接问题 + +语言信号:"场景切换"、"节奏拖沓"、"详写略写"、"字数安排"、"描写太多"、"过渡生硬"、"我故事太平"、"我场景写太多"。(/fiction-scene-craft) + +## 中文落地(中文适配) + +本单元源文即中文译本,举例已落在中文语境("第二天。"、"三个月后。"、"她搬到北京那年。"、"她把信烧了。"、"那夜雨下到天明。"、"三天三夜的雨"),可直接照用。中文小说里"三个字过渡"常由单句独段或空行承担,效果等同。(中文适配;依据 becoming-a-writer/fiction-scene-craft) diff --git a/framework/catalog/pi/skills/scene-craft/references/scene-entry-exit.md b/framework/catalog/pi/skills/scene-craft/references/scene-entry-exit.md new file mode 100644 index 0000000..5560d37 --- /dev/null +++ b/framework/catalog/pi/skills/scene-craft/references/scene-entry-exit.md @@ -0,0 +1,126 @@ +# 定进出:晚进入,早退出 + +> 来源单元:《Story Engineering》(Larry Brooks)story-engineering/scene-enter-late-exit-early,Part 6 · The Function of Scenes。 +> 本文件管单场景从哪里开始、在哪里结束。场景该干什么见 [scene-mission.md](scene-mission.md),详略判断见 [scene-detail.md](scene-detail.md),边界与误区见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> "Enter the scene late, leave it early. Don't make your reader sit through the pleasantries before getting to the drama. Don't make them sit through the conversation once the dramatic moment is over and resolved. This is simple, almost too simple, yet adherence to it is one of the most powerful tools in a writer's tool chest." +> +> — Larry Brooks, *Story Engineering* (2011), Part 6 + +(/scene-enter-late-exit-early) + +## 方法核心 + +进入场景时跳过所有铺垫到戏剧爆发的瞬间;退出场景时在戏剧张力释放完的瞬间立刻离开。看似太简单,却是"你放不下这本书"的最强工具之一。(/scene-enter-late-exit-early) + +**晚进入(Enter Late)**: + +- 跳过:寒暄、问候、铺陈、问候"最近如何" +- 跳到:戏剧爆发的瞬间 / 关键信息揭示 / 关键决策点 +- 例:不用写"主角走进咖啡馆, 看到朋友, 两人点单";跳到"主角说: '我查过了, 你丈夫是凶手'" + +**早退出(Leave Early)**: + +- 跳过:戏剧张力释放后的"收尾"(客套、告别、反思) +- 跳到:戏剧张力释放完的瞬间(角色做出决定 / 真相浮出) +- 例:不用写"主角说: '我决定这么做', 朋友说: '好的', 两人离开";跳到主角做出决定, 立刻切下一场景 + +(/scene-enter-late-exit-early) + +**为什么有效**: + +- 读者时间宝贵,不能浪费 +- 戏剧张力 = 读者"想知道下一步",早退场 = 把这个想知道带到下一场景 +- 进入晚 = 不浪费"读者已经知道的事" + +(/scene-enter-late-exit-early) + +**判断标准**: + +- 进入:"读者还不知道什么?" = 跳到那 +- 退出:"读者已经知道什么?" = 立刻退出 + +(/scene-enter-late-exit-early) + +这把"读者知道/不知道"的尺子和详略判断是同一把,见 [scene-detail.md](scene-detail.md)。 + +**风险**: + +- 太晚进入 = 读者"不知道发生什么" = 困惑 +- 太早退出 = 戏剧没爆发 = 场景没 mission +- 需要配合 scene-mission-driven 使用:先确认场景有东西可爆(使命),再谈从哪里剪(见 [scene-mission.md](scene-mission.md)) + +(/scene-enter-late-exit-early) + +## 案例 + +### 案例 1:书中直接对比——去前妻家 + +- **作者原书示范**:同一段(主角去前妻家),用两种方式写 +- **方式 A(平铺)**:"主角出门, 开车 10 分钟, 到了前妻家, 敲门, 前妻开门, 进屋, 坐下, 寒暄……" +- **方式 B(晚入早出)**:跳到"前妻的车在车道, 主角心沉, 决定不停下" +- **结论**:方式 B 更紧凑,戏剧更强 + +(/scene-enter-late-exit-early) + +### 案例 2:反例——进入太早 + +- **问题**:写作者 3 页写主角"开车去公司, 停车, 电梯, 跟同事打招呼, 坐下" +- **诊断**:进入过早,浪费读者时间 +- **方法**:跳到"主角到公司, 接到关键电话" +- **结果**:3 页变 0.5 页,节奏紧凑 + +(/scene-enter-late-exit-early) + +### 案例 3:反例——退出太晚 + +- **问题**:戏剧决策已做,但写作者继续写 2 页"角色思考决定, 跟助手讨论, 跟家人打电话" +- **诊断**:退出过晚,戏剧已结束 +- **方法**:跳到"决定已做, 切下一场景" +- **结果**:2 页变 0.5 页,节奏紧凑 + +(/scene-enter-late-exit-early) + +## 可执行步骤(单场景剪切) + +1. **选 1 个场景** + - 完成标准:用户指定 1 个场景 +2. **标记场景当前的开头/结尾** + - 完成标准:1 句话标"场景从这里开始"和"场景在这里结束" +3. **判断进入** + - 问"读者现在还不知道什么?" + - 答案点 = 应该是真正的进入点 + - 在那之前 = 应该删 / 并 +4. **判断退出** + - 问"读者现在需要知道的都知道了?" + - 是 = 应该是退出点 + - 在那之后 = 应该删 / 并 +5. **改稿** + - 完成标准:列出"删多少字/段" + - 注意:删不是粗暴,是用"白空间/换行"暗示场景切换 + +(/scene-enter-late-exit-early) + +## 激活场景与语言信号 + +用户会在这些情境下需要这条方法: + +1. **场景节奏优化**:"场景太慢,怎么改?" +2. **改稿**:"我场景开头/结尾太多废话" +3. **新场景建**:"场景怎么进入/退出?" +4. **教学**:"教学生写紧凑场景" + +语言信号:"晚进入 / 早退出 / enter late leave early"、"场景紧凑 / 场景节奏 / 场景不拖"、"场景开头 / 场景结尾"、"怎么进入场景 / 怎么退出场景"。(/scene-enter-late-exit-early) + +## 与相邻方法的分工 + +- **scene-mission-driven**(同包 [scene-mission.md](scene-mission.md)):管"场景功能"(做什么);本方法管"场景节奏"(快慢、剪切点)。 +- **structure-\***(现归 story-structure):管"整体结构",不管单场景剪切。 + +(/scene-enter-late-exit-early) + +## 中文落地(中文适配) + +原文说的"白空间/换行"暗示场景切换,在中文小说里对应空一行、分节符、或直接一句独立成段的时空跳转(如"三个月后。",见 [scene-rhythm.md](scene-rhythm.md) 的过渡条)。中文传统里的留白与分节天然承接晚入早出:删掉的路上工夫不写,读者自会补上。(中文适配;依据 story-engineering/scene-enter-late-exit-early 与 becoming-a-writer/fiction-scene-craft) diff --git a/framework/catalog/pi/skills/scene-craft/references/scene-ledger-template.md b/framework/catalog/pi/skills/scene-craft/references/scene-ledger-template.md new file mode 100644 index 0000000..c8216cc --- /dev/null +++ b/framework/catalog/pi/skills/scene-craft/references/scene-ledger-template.md @@ -0,0 +1,23 @@ +# 场景台账模板 + +> 用途:改稿前把全部场景列成一张表,逐场登记使命、详略、进出点与镜头距离,再拿这张表去对 [scene-revision-checklist.md](scene-revision-checklist.md) 的五关。 +> 来源:/scene-mission-driven 执行步骤 1-2(列出所有场景、逐场景一句话回答使命);/fiction-scene-craft 执行步骤 2-3(列场景清单 5-15 个、每个场景一个名字、标详/略、详写占 5%-15% 字数);/scene-enter-late-exit-early 执行步骤 3-4(判断进入问"读者还不知道什么"、判断退出问"读者需要知道的都知道了吗",答案即进入点/退出点);/cinematic-distances 执行步骤 1-2(逐段标距离、关键瞬间指派距离)。 + +## 台账 + +| # | 场景名 | 使命(一句话:让故事前进了什么) | 使命类型 | 详/略 | 约字数 | 节奏模式位置 | 进入点(读者从哪一刻开始知道) | 退出点(读者知道够了就切) | 主要镜头距离 | 关键瞬间及距离 | 处置(留/删/拆/并) | +|---|--------|------------------------------|----------|-------|--------|--------------|------------------------------|--------------------------|--------------|----------------|---------------------| +| 1 | 例:第一次见面 | 例:让两人结下梁子 | 动作型 | 详 | 1200 | 详-略-详 的"详" | 例:对方开口挑衅 | 例:主角决定报复 | 建立→中景→特写 | 告白=特写+极端特写 | 留 | +| 2 | 例:三个月后 | 例:时间过渡 | ——(略写过渡) | 略 | 3-30 | 详-略-详 的"略" | —— | —— | —— | —— | 留(压到一句话) | +| 3 | | | | | | | | | | | | + +## 填表规则 + +1. **场景名**:每场一个名字("第一次见面" / "三个月后" / "重逢"),列不出名字的场景先怀疑它没有存在的理由。(/fiction-scene-craft) +2. **使命**:一句话回答"这个场景让故事前进了什么",说不清 = 无使命,处置列写"删/并";一场写出两件事 = 处置列写"拆"。(/scene-mission-driven) +3. **使命类型**:信息型 / 决策型 / 动作型 三选一,不要造第四种;内心独白场景归信息型(角色领悟)。(/scene-mission-driven) +4. **详/略与字数**:核心是冲突/转变/启示就详写,推进/过渡/背景就略写;全篇详写场景合计约占 5%-15% 字数,略写 1-3 个字或一段。(/fiction-scene-craft) +5. **节奏模式位置**:先看全篇落在紧-紧-紧 / 详-略-详 / 略-略-详 哪一种,再标每场在模式里的位置;相邻三场全详或全略 = 节奏警报。(/fiction-scene-craft) +6. **进入点/退出点**:进入 = 读者还不知道什么就跳到哪;退出 = 读者需要知道的都知道了就切。只填时刻,不填过程。(/scene-enter-late-exit-early) +7. **主要镜头距离与关键瞬间**:逐段标五档后写主档;死亡/告白/揭露这类关键瞬间单独登记指派距离,关键瞬间停在中景 = 重新设计。(/cinematic-distances) +8. **统计口径**(填完整张表后核对):无使命场景 ≥ 2 = 删或并;中景占比 ≥ 60% = 练拉远推近;高潮场被标"略" = 先改详略。(三个源单元的判停条件) diff --git a/framework/catalog/pi/skills/scene-craft/references/scene-mission.md b/framework/catalog/pi/skills/scene-craft/references/scene-mission.md new file mode 100644 index 0000000..99176ef --- /dev/null +++ b/framework/catalog/pi/skills/scene-craft/references/scene-mission.md @@ -0,0 +1,125 @@ +# 定使命:一个场景只交付一件事 + +> 来源单元:《Story Engineering》(Larry Brooks)story-engineering/scene-mission-driven,Part 6 · The Function of Scenes。 +> 本文件管"这个场景干什么"。场景给多少篇幅见 [scene-detail.md](scene-detail.md),从哪里进从哪里出见 [scene-entry-exit.md](scene-entry-exit.md),边界与误区见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> "Every scene has a mission to accomplish. The mission of each scene is to deliver a single, salient, important piece of story to the reader. Less is more here. More than one bomb going off, or even a little mouse trap clicking shut, is often too much for one scene." +> +> — Larry Brooks, *Story Engineering* (2011), Part 6 + +(/scene-mission-driven) + +## 方法核心 + +每个场景必须有一个**戏剧使命(mission)**——交付一条关键信息,或做出一个关键决策,或推动一个关键情节节点。一个场景 1 个 mission;多个 mission = 戏剧张力稀释。(/scene-mission-driven) + +**Mission 的 3 种类型**: + +1. **信息型**:告诉读者一个关键事实(背景 / 真相 / 即将发生的事) +2. **决策型**:角色在场景内做出一个不可逆决定 +3. **动作型**:场景推进情节 / 改变主角状态 + +**3 类的共同点**:改变故事的下一步走向。(/scene-mission-driven) + +**为什么 1 个 mission**: + +- 多个 mission = 读者注意力分散 +- 每个 mission 都削弱其他 mission 的冲击力 +- 1 个 mission = 读者每次被打动 1 次,印象深 + +(/scene-mission-driven) + +**操作法**: + +- 写场景前,用 1 句话回答"这个场景让故事前进了什么" +- 写场景后,再用 1 句话验证 +- 说不清 = 这个场景删 / 并 + +(/scene-mission-driven) + +**使命的量级标准**:mission 必须达到"改变故事走向"的量级,"角色出门"这种不算 mission。(/scene-mission-driven) + +**反例**:"这个场景让角色思考了,之后她做决定"——思考 + 决定 = 2 mission,拆。(/scene-mission-driven) + +**内心独白场景怎么算**:mission 默认是"看得见"的,但内心独白场景也有 mission,归入信息型——角色领悟了某件事。(/scene-mission-driven) + +## 案例 + +### 案例 1:James Patterson——极致的任务驱动 + +- **方法**:每场景 1 mission,每章 1 场景,100+ 章/书 +- **Mission 例子**: + - Chapter 1:介绍主角 + - Chapter 2:介绍反派 + - Chapter 3:第一场追逐 + - Chapter 4:反派接近主角 + - …… 一直到高潮,1 mission/章 +- **结果**:验证了"每场景 1 mission"的可读性优势 + +(/scene-mission-driven) + +注意:帕特森式"一场一使命、一章一场"是极致做法,不是唯一正确的写法,见下文误区。(/scene-mission-driven) + +### 案例 2:反例——写作者 1 场景塞 3 件事 + +- **问题**:1 个场景里:(1) 角色做决定 (2) 角色见到反派 (3) 角色得到关键信息 +- **诊断**:3 mission = 戏剧张力稀释,读者消化不了 +- **方法**:拆成 3 场景,每个 1 mission +- **结果**:故事节奏加快,戏剧强度提升 + +(/scene-mission-driven) + +### 案例 3:反例——1 场景无 mission + +- **问题**:1 场景里角色在咖啡馆,描述环境,角色想,角色离开,什么都没发生 +- **诊断**:0 mission = 删 +- **方法**:删场景,或并入相邻场景 +- **结果**:小说变紧凑 + +(/scene-mission-driven) + +## 可执行步骤(整篇/整段场景改稿) + +1. **列出所有场景** + - 完成标准:用户列出当前所有场景(或一段内的所有场景) +2. **逐场景回答 mission** + - 完成标准:每个场景 1 句话:"这个场景让故事前进了什么?" + - 说不清 = 这个场景无 mission +3. **统计** + - 全有 mission = 通过 + - ≤ 1 个无 mission = 还行 + - ≥ 2 个无 mission = 改稿,删 / 并 +4. **检查 mission 数量** + - 完成标准:每个场景只 1 mission + - 有 2+ mission = 拆场景 +5. **改稿** + - 完成标准:列出"删哪些 / 拆哪些 / 并哪些" + +(/scene-mission-driven) + +配表使用:场景逐场登记可用 [../references/scene-ledger-template.md](scene-ledger-template.md),改稿逐关过用 [../references/scene-revision-checklist.md](scene-revision-checklist.md)。 + +## 激活场景与语言信号 + +用户会在这些情境下需要这条方法: + +1. **新场景建**:"我要写 1 个场景,它应该做什么?" +2. **场景诊断**:"这个场景有用吗?" +3. **节奏优化**:"我的小说拖,怎么改?" +4. **改稿**:"我写完一稿,怎么诊断场景?" + +语言信号:"场景任务 / 场景使命 / scene mission"、"这个场景有什么用 / 场景为什么"、"场景太多 / 场景散 / 小说拖"、"场景诊断 / 1 个场景 1 件事"。(/scene-mission-driven) + +## 本单元的误区提醒 + +1. **把"1 场景 1 mission"当教条**:Patterson 风格是极致做法,不是唯一正确,不要拿它苛责一切写法。(/scene-mission-driven) +2. **Mission 太小**:如"角色出门"——mission 必须"改变故事走向"才算数。(/scene-mission-driven) +3. **乱造 mission 变体**:集中于"信息 / 决策 / 动作"3 种,不要造新类。(/scene-mission-driven) + +更多边界(不适用场景、盲点、易混方法)见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 中文落地(中文适配) + +网文连载"每章必有钩子"的节奏要求(见《成为作家》单元盲点条)与"一场一使命"天然合拍:一章一场、一场一使命、章末落在使命刚完成或刚被打破的位置,就是帕特森式排法的中文连载版。(中文适配;依据 story-engineering/scene-mission-driven 与 becoming-a-writer/fiction-scene-craft) diff --git a/framework/catalog/pi/skills/scene-craft/references/scene-mystification.md b/framework/catalog/pi/skills/scene-craft/references/scene-mystification.md new file mode 100644 index 0000000..a629eab --- /dev/null +++ b/framework/catalog/pi/skills/scene-craft/references/scene-mystification.md @@ -0,0 +1,121 @@ +# 藏拼装:蒙蔽读者,唯一的罪是被看穿 + +> 来源单元:《小说面面观》(E. M. 福斯特)aspects-of-the-novel/mystification,第四讲 人物(续) / 第五讲 情节。 +> 本文件管场景与视角的拼装痕迹如何不被读者察觉。边界与误区见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> "总领小说技巧的最复杂问题 (珀西·卢伯克先生如是说), 我认为是视角问题, 也就是叙事者与所叙故事之间的关系问题。在我看, 总领小说技巧的最复杂问题不在于总结几个套路公式, 而在于作者有多少能力'蒙蔽'读者, 使之信服自己所讲述的一切。" + +> "《荒凉山庄》的第一章是全知视角 …… 到了第二章, 他的视角收窄了 …… 第三章, 他更是离谱, 索性直接用上戏剧手法 …… 从逻辑上说, 《荒凉山庄》完全是碎片化的, 可狄更斯蒙蔽了我们的感知, 让我们完全不在意视角的转换。" + +> "唯一值得诟病的, 就是被我们当场察觉出转换的生硬。" +> +> — E. M. 福斯特, 《小说面面观》第四讲 人物(续) / 第五讲 情节 + +(/mystification) + +## 方法核心 + +福斯特在评论技巧中提出的**核心方法**:视角转换/扁平/圆形人物/碎片化逻辑/模式等等技术手段,真正重要的不是"我用了哪几种",而是"我有没有**蒙蔽**读者的感知,让一切显得自然"。(/mystification) + +**核心操作**: + +1. **承认"所有作品都是拼装"**——没有"自然"的作品,都有视角转换、类型切换、模式裁剪。**唯一值得诟病的不是"拼装",是"被当场察觉出拼装"**。 +2. **判断"蒙蔽"成功的征兆**: + - 读者/听众/用户感到"自然",不问"这里为什么突然换视角了" + - 即使被告知"这里有转换",也觉得"啊,确实自然,我没注意到" + - 读者/听众/用户主动跟随,不掉线 +3. **判断"蒙蔽"失败的征兆**: + - 读者/听众/用户感到"突兀" / "硬" / "不对劲" + - 主动指出"这里好像换了风格 / 这里人物怎么突然变样了" + - 注意力从内容转移到形式 +4. **危险的"作者亲临"**——福斯特明示:把读者领进幕后("A 看着不错吧——我一直都特别喜欢她","让我们来猜猜 B 为什么要这么做")破坏想象空间和尊严。"就像是只许人站着喝酒, 这样他们就没工夫批评你的想法了。" +5. **"蒙蔽"和"欺骗"的区别**——蒙蔽是"让拼装不刺眼",欺骗是"让内容失真"。前者是技术,后者是道德。 + +(/mystification) + +**关键认识**:福斯特把"蒙蔽读者"作为小说这一艺术形式的**最大优势之一**。这与现实生活的"间歇性认知"一致——我们有时候比其他人傻,我们偶尔可以理解别人的心思但并不总能如此。这种间歇性确保了我们有能力迎接更多彩多样的各色体验。**小说家对人物也是时松时紧,有冷有热**,这是合法且必要的。(/mystification) + +**具体蒙蔽手段**(给修改建议时用): + +- 在视角转换前加入一段"桥梁"叙述 +- 用细节的延续掩盖视角的切换 +- 不要空话(如"让叙述更自然")——给可操作修改 + +(/mystification,执行步骤第 3 步) + +## 案例 + +### 案例 1:狄更斯《荒凉山庄》——视角转换的蒙蔽(成功) + +- **问题**:《荒凉山庄》从全知视角(第一章)→ 收窄视角(第二章累斯特·戴洛克男爵)→ 戏剧手法(第三章埃丝特·萨默森),这种"碎片化"为什么没让读者察觉? +- **方法论的使用**:福斯特诊断——"狄更斯蒙蔽了我们的感知, 让我们完全不在意视角的转换"。从逻辑上说,这本书完全是碎片化的,但狄更斯的"蒙蔽"能力让它看起来自然 +- **结论**:蒙蔽是狄更斯的核心能力 +- **结果**:借此福斯特说明"蒙蔽"是评论小说技巧的**真正核心**,不是"我用了哪几种视角" + +(/mystification) + +### 案例 2:纪德《伪币制造者》——蒙蔽的反例 + +- **问题**:纪德也做视角转换,为什么不成功? +- **方法论的使用**:福斯特诊断——纪德的视角转换"在转换之间的解说显得累赘了",读者"太在意作者创作技法",失去对人物的兴趣 +- **结论**:纪德"放弃了对人物的创造, 只召唤我们来帮忙分析他自己的心思, 结果自然只能是叫人热情骤降" +- **结果**:借此福斯特说明,蒙蔽失败的征兆是"读者开始琢磨作者的心思" + +(/mystification) + +### 案例 3:菲尔丁/萨克雷的小酒馆式旁白——蒙蔽的极端失败 + +- **问题**:菲尔丁/萨克雷在小说中直接"东拉西扯"评论人物,这种"作者亲临"为什么是"致命的"? +- **方法论的使用**:福斯特诊断——这种"作者亲临""破坏想象空间和尊严"。"就好像是只许人站着喝酒, 这样他们就没工夫批评你的想法了。"——这不是蒙蔽,是"引诱" +- **结论**:在过去的小说中,再没有比这一点更致命的了 +- **结果**:借此福斯特划出"蒙蔽"和"诱惑/打破第四面墙"的明确边界 + +(/mystification) + +## 可执行步骤 + +1. **承认"所有作品都是拼装"** + - 完成标准:明确说出"没有'自然'的作品,都有视角转换、类型切换、模式裁剪,关键是蒙蔽质量" +2. **检测"蒙蔽失败"的具体征兆** + - 完成标准:至少标出 1 处"读者/听众/用户可能察觉的拼装痕迹" + - 提示:关注"转换的瞬间"——视角、语气、节奏、密度突然改变的地方 +3. **设计"蒙蔽"的具体手段** + - 完成标准:至少 1 条具体修改(如"在视角转换前加入一段'桥梁'叙述"或"用细节的延续掩盖视角的切换") + - 不要空话(如"让叙述更自然")——给可操作修改 +4. **避免"作者亲临"陷阱** + - 完成标准:检查"我是否亲自出现在叙述中,替读者解读人物",如有,删去 + - 福斯特明示:"A 看着不错吧——我一直都特别喜欢她"这种旁白是致命的 +5. **做"读者/听众盲测"** + - 完成标准:至少 1 个人(或 1 个独立评审)在不知道"作者意图"的情况下阅读,报告"哪里觉得突兀" + - 判停条件:如果盲测报告 0 处突兀,蒙蔽成功 + +(/mystification) + +## 激活场景与语言信号 + +用户会在这些情境下需要这条方法(原单元覆盖写作之外的演示、教学、产品场景,此处全数保留,小说场景之外用法同理): + +1. **写小说/剧本/课程/演讲**——写完前自检:"我的视角转换自然吗?" +2. **设计演示/汇报/会议**——评估"听众是否觉得突兀" +3. **教学**——评估"学生是否察觉到了我的拼装" +4. **产品 UX/界面设计**——评估"用户是否察觉到我的表面功夫" +5. **设计一个多模块/多角色/多视角的产品**——评估"切换是否自然" +6. **做品牌/营销/广告**——评估"观众是否觉得生硬" +7. **编辑/审校/反馈他人作品**——诊断"这里是不是有未蒙蔽的拼装" + +语言信号:"不自然 / 突兀 / 生硬"、"拼装 / 痕迹 / 不流畅"、"听众/读者没察觉"、"X 看起来很硬"、"X 的转折太硬了"、"读者开始关注形式而不是内容"、"X 让我跳戏"、"X 让人出戏"、"X 太匠气 / 太刻意"、"X 太炫技 / 太技巧"。(/mystification) + +## 与相邻方法的分工 + +- 与 flat-vs-round-character(现归 character-design)的区别:蒙蔽是**整体感知层**,扁/圆是**单人物形式层**;前者管"自然不自然",后者管"深不深"。圆形人物的"出人意料"必须被蒙蔽,才能既意外又可信。 +- 与 plot-character-tug(现归 novel-diagnosis)的区别:蒙蔽是**作者姿态**,情节-人物拉锯是**结构张力**;前者管"我让你信服",后者管"两种要素的张力"。 +- 与"打破第四面墙"的区别:后者故意让作者/角色跳出来,是**反蒙蔽**;蒙蔽是让作品自然,打破是让作品"不自然"。 +- 与 expansion-vs-completion(现归 story-ending)的配合:扩展/完成两种结尾姿态都需要蒙蔽支撑——收尾处的速度变化、视角收束同样不能被读者看出接缝。 + +(/mystification) + +## 中文落地(中文适配) + +中国评书/相声中"说书人亲临"是合法传统——说书人当众点评人物、与听众搭话,并不构成失败。这与福斯特"作者亲临是致命的"的判断不同:福斯特的论断基于西方现代小说传统,移到说书体、章回体口吻时要看文体约定——文体本就承诺了说书人在场,读者的期待不同,蒙蔽的对象也不同(蒙蔽的是情节接缝,不是说书人的存在)。(中文适配;依据 aspects-of-the-novel/mystification 盲点条) diff --git a/framework/catalog/pi/skills/scene-craft/references/scene-revision-checklist.md b/framework/catalog/pi/skills/scene-craft/references/scene-revision-checklist.md new file mode 100644 index 0000000..92cbcd1 --- /dev/null +++ b/framework/catalog/pi/skills/scene-craft/references/scene-revision-checklist.md @@ -0,0 +1,91 @@ +# 场景改稿检查清单(五关) + +> 用途:一稿写完后,逐场景、逐关过一遍。五关按"先定命,再定篇幅,再剪进出,再调镜头,最后藏缝"的顺序走;单场景快速诊断可只过相关的关。 +> 来源:五个源单元的可执行步骤合并——/scene-mission-driven 与 scene-enter-late-exit-early;/fiction-scene-craft;/cinematic-distances;/mystification。 +> 逐场登记用 [scene-ledger-template.md](scene-ledger-template.md)。 + +## 第一关:使命关(这个场景干什么) + +来源:scene-mission-driven + +- [ ] 列出当前所有场景(或一段内的所有场景) +- [ ] 逐场景用一句话回答:"这个场景让故事前进了什么?" + - 说不清 = 这个场景无使命 +- [ ] 统计: + - 全有使命 = 通过 + - ≤ 1 个无使命 = 还行 + - ≥ 2 个无使命 = 改稿,删 / 并 +- [ ] 检查每场使命数量:每个场景只 1 个使命 + - 有 2+ 使命 = 拆场景(典型反例:"角色思考了,之后她做决定" = 思考 + 决定两个使命) +- [ ] 检查使命量级:使命必须"改变故事走向","角色出门"不算 +- [ ] 输出改稿清单:"删哪些 / 拆哪些 / 并哪些" + +## 第二关:详略关(给多少篇幅) + +来源:fiction-scene-craft + +- [ ] 诊断问题类型:(a) 不知道详写哪些?(b) 详写太多?(c) 过渡拖沓?(d) 高潮没力?(e) 整体一个节奏? +- [ ] 给每个场景标详 / 略: + - 核心 = 冲突 / 转变 / 启示 → 详写 + - 核心 = 推进 / 过渡 / 背景 → 略写 + - 详写场景合计约占故事字数 5%-15%,略写 = 1-3 个字或一段 +- [ ] 高潮场景没有被略写(略写高潮 = 失去力量:短句 + 对话 + 动作密集才是高潮写法) +- [ ] 不重要的过渡是否减到 3 个字左右(例外:自带隐喻功能的场景详写,如"三天三夜的雨") +- [ ] 每个略写场景有 1-3 个动作/感官词扛住("她把信烧了。",不是"那天晚上她想了很久。") +- [ ] 惯性场景去留判断:一开写就停不下来的场景,写完试删——删掉影响故事就留,不影响就减到 3 个字 +- [ ] 字数校准:数一个参考作者同等场景的字数,问"这个字数够吗"(是校准,不是模仿) +- [ ] 全篇节奏落在三种模式之一:紧-紧-紧 / 详-略-详(默认)/ 略-略-详;不全详不全略 +- [ ] 过渡短(3-30 字),没有几百字的过渡段 +- [ ] 写完不立即重读,放一边至少隔一夜 + +## 第三关:进出关(从哪里进,从哪里出) + +来源:scene-enter-late-exit-early + +- [ ] 标出场景当前的开头和结尾(各一句话) +- [ ] 进入判断:问"读者现在还不知道什么?" + - 答案点 = 真正的进入点;在那之前的内容 = 删 / 并 +- [ ] 退出判断:问"读者需要知道的都知道了吗?" + - 是 = 退出点;在那之后的内容 = 删 / 并 +- [ ] 输出"删多少字/段" +- [ ] 边界检查: + - 进入太晚 = 读者不知道发生什么(困惑)→ 回退到能给读者定位的点 + - 退出太早 = 戏剧没爆发 = 场景没使命 → 回第一关确认使命 +- [ ] 删掉的过渡用"白空间/换行"暗示场景切换,不剪出断裂 + +## 第四关:距离关(用多远的镜头拍) + +来源:cinematic-distances + +- [ ] 把一章/一个场景的每个段落标上五档之一:鸟瞰 / 建立 / 中景 / 特写 / 极端特写 + - 完成标准:80%+ 段落标得明确;没有"分不清中景还是特写"的含糊段 + - 判停:中景占比 ≥ 60% = 警告,作者只敢写中景,练拉远和推近 +- [ ] 列出场景中 3-5 个关键瞬间(死亡、告白、揭露、冲突顶点、回忆闪回),逐个指派距离: + - 死亡 = 特写;战场 = 中景 + 鸟瞰;告白 = 特写 + 极端特写 + - 判停:关键瞬间仍在中景 = 重新设计段落,否则场景没有情绪峰值 +- [ ] 一个场景内切换 3+ 距离(常见:建立→中景→特写) + - 判停:为换而换 / 每段都换 = 矫枉过正,回头减;每个距离段至少 2-3 句再切 +- [ ] 长篇中段(约 40-60% 处)可加 1 个鸟瞰/建立镜头段作换气: + - 不承载情节,只服务读者呼吸 + - 必须有具体内容(晨光、街景、季节变化),"空段"不叫鸟瞰 +- [ ] 中文单位检查:距离切换按整场/整章看,不段段必切,避免段落碎片化 + +## 第五关:蒙蔽关(藏拼装痕迹) + +来源:mystification + +- [ ] 找接缝:视角、语气、节奏、密度突然改变的地方,至少标出 1 处可能被读者察觉的拼装痕迹 +- [ ] 每处接缝给至少 1 条具体修改:视角转换前加一段"桥梁"叙述,或用细节的延续掩盖切换;不说"让叙述更自然"这类空话 +- [ ] 检查作者亲临:有没有亲自出现在叙述中替读者解读人物的句子("她看着不错吧——我一直都特别喜欢她"),有就删 +- [ ] 分清蒙蔽与欺骗:只让拼装不刺眼(技术),不让内容失真(道德) +- [ ] 盲测:至少 1 个不知道作者意图的人(或独立评审)通读,报告哪里突兀 + - 判停:盲测报告 0 处突兀 = 蒙蔽成功 + +## 整体适用性预检(开工前先过) + +- 中短篇/单场景:整个故事一个使命,进出与距离切换可不强求 +- 文学/意识流:场景故意慢,节奏不是快就好;全程单一距离的章节切了反而稀释情绪 +- 极短篇(3000 字以下):篇幅不够切五档,强切凌乱 +- 长篇(> 30000 字):详略按章重新设计,每章有自己的详略 +- 剧本:台词部分不适用,场景说明可用距离法 +- 非虚构、诗歌散文、纯抒情独白:不适用本清单 diff --git a/framework/catalog/pi/skills/scene-craft/references/scene-rhythm.md b/framework/catalog/pi/skills/scene-craft/references/scene-rhythm.md new file mode 100644 index 0000000..fea98f0 --- /dev/null +++ b/framework/catalog/pi/skills/scene-craft/references/scene-rhythm.md @@ -0,0 +1,99 @@ +# 排节奏:详略相间,有快有慢 + +> 本文件是三本书的合并落点:《成为作家》(多萝西娅·布兰德)becoming-a-writer/fiction-scene-craft 的三种节奏模式与过渡规则;《Story Engineering》(Larry Brooks)story-engineering/scene-enter-late-exit-early 的"慢场景有价值、全书不能只有一种速度";《写作工具》(Roy Peter Clark)writing-tools-clark/cinematic-distances 的长篇中段换气段。 +> 单个场景的详略判断见 [scene-detail.md](scene-detail.md),单场景的剪切点见 [scene-entry-exit.md](scene-entry-exit.md),镜头距离见 [scene-camera.md](scene-camera.md)。 + +排节奏回答的问题是:相邻场景怎么排列,整本书在哪里屏息、在哪里换气。详略是单个场景的篇幅判断,节奏是这些篇幅的排布。 + +## 三种节奏模式(场景的不同节奏) + +(/fiction-scene-craft) + +**模式 1:"紧 → 紧 → 紧"(高潮场景)** + +- 全部详写,节奏快 +- 大量短句,大量对话,动作密集 +- 适用:冲突 / 高潮 / 转折 +- 例子:离婚谈判的高潮,一次告白,一次摊牌 + +**模式 2:"详 → 略 → 详"(呼吸)** + +- 一个详写场景 + 一个略写过渡 + 一个详写场景 +- 像呼吸:吸 → 屏 → 呼 +- 适用:故事主体 +- 例子:详写"第一次见面" + 略写"几个月后" + 详写"重逢" + +**模式 3:"略 → 略 → 详"(蓄势)** + +- 开头都是略写,蓄势到一个详写场景 +- 像慢镜头推到特写 +- 适用:故事铺垫,关键场景前 +- 例子:略写"5 个人物的日常" + 详写"关键事件" + +**怎么选**: + +- 不知道选哪个?**默认模式 2**(详-略-详),最平衡 +- 写高潮?**模式 1** +- 写铺垫?**模式 3** + +(/fiction-scene-craft) + +## 场景之间过渡(节奏的关键) + +**好的过渡**: + +- 短(3-30 字) +- 暗示时间/空间的变化 +- 不需要完整描述 +- 例:"三个月后。" / "她搬到北京那年。" + +**坏的过渡**: + +- 长(几百字) +- 像另一个场景一样详写 +- 例:"三个月后, 她搬到了北京, 找了一份新工作, 认识了新的朋友……" + +**过渡的作用**: + +- 节奏的"屏息" +- 让详写场景之间有**呼吸** +- 让读者**主动**填补空白(这正是想象的入口) + +(/fiction-scene-craft) + +## 全书要有快有慢(三书视角合并) + +同一个方法点——"整本书不能只有一种速度,慢的部分有它的位置"——三本书从不同角度说过,合并如下,各自视角与出处保留。 + +### 《Story Engineering》视角:别把所有场景都剪成快戏 + +- 所有场景都晚入早出——失去氛围/共情建立的时间。 +- 完全删寒暄——有时 1 句寒暄是共情建立。 +- 假设读者都急——实际部分读者喜欢慢/氛围。 +- 假设"快" = "好"——部分场景需要慢(回忆/情感)。 +- 假设只用 1 种时间感——整本书应该有时快有时慢。 + +(/scene-enter-late-exit-early,失败模式与盲点条) + +注意这里与"跳过所有寒暄"的原文命令存在张力:原文主规则要求进入场景时跳过寒暄铺陈,作者自己又警告"有时 1 句寒暄是共情建立"。两条都保留,取舍看场景使命是推进关系还是推进事件。(冲突标注:同出/scene-enter-late-exit-early) + +### 《成为作家》视角:统一节奏就是错误 + +- 所有场景一个节奏:详写详写详写 = 读者累;略写略写略写 = 读者没感觉。 +- 修法:用模式 2(详-略-详)或模式 3(略-略-详)换着排。 + +(/fiction-scene-craft,常见错误第 3 条) + +### 《写作工具》视角:长篇中段放一个换气窗口 + +- 在长篇中段(读者开始疲劳处)插入 1 个**鸟瞰 / 建立镜头**段落,不带情节,只交代空间与时间——让读者"换气"。 +- 完成标准:鸟瞰/建立段不承载情节功能,只服务"读者呼吸";位置在中段 40-60% 处。 +- 判停条件:把鸟瞰当"省力"——一段不写的"空"段不叫鸟瞰,鸟瞰仍要**有具体内容**(晨光、街景、季节变化)。 + +(/cinematic-distances,执行步骤第 4 步) + +## 节奏与详略、进出的关系 + +- 节奏模式是详略的排布:先按 [scene-detail.md](scene-detail.md) 给每场定详略,再看全篇落在三种模式的哪一种。 +- 剪切点影响单场内部的快慢,但"全书快慢"不由剪切点单独决定:晚入早出是单场景层面的紧,慢场景与换气段是全书层面的松,两者配合使用。 +- 高潮场景被略写时,先改详略再调距离:详略错了,焦距救不回来(见 [scene-detail.md](scene-detail.md) 常见错误第 2 条)。 diff --git a/framework/catalog/pi/skills/show-and-omission/SKILL.md b/framework/catalog/pi/skills/show-and-omission/SKILL.md new file mode 100644 index 0000000..f924ee9 --- /dev/null +++ b/framework/catalog/pi/skills/show-and-omission/SKILL.md @@ -0,0 +1,84 @@ +--- +name: show-and-omission +description: | + 激活场景:小说文本里情绪、氛围、性格被抽象标签堆出来("她很悲伤""气氛阴森""他是个好人"),读者没有画面; + 写到极端情绪场景(崩溃、杀人后、噩耗、求爱)不知道心理怎么下笔;奇幻、梦境、超现实情节写得假、读者出戏; + 对话和动作看着平淡,扛不出第二层意思;想藏住两个人之间的秘密或暗流,不想明说; + 视角人物说出了自己不可能知道的信息;或者总怕读者看不懂,解释越写越多,读者仍说读不懂。 + 关键 trigger:"show don't tell" / "展示不说教" / "没有画面感" / "太抽象" / "形容词太多" / + "心理描写怎么写" / "不写他感到,写他做什么" / "留白" / "飞白" / "冰山" / "写得假" / "出戏" / + "imagination" / "magical realism" / + "读者不信" / "藏着不写明" / "说得太满" / "视角穿帮" / "人物知道了不该知道的" / "信息差" / + "读者读不懂" / "明明很显然" / "跳步" / "术语太多" / "why is this jargon"。 + 不适用于:意识流作品里刻意的直接心理呈现(乔伊斯、伍尔夫式的美学追求); + 第一人称主观独白和全知叙述者的合法评述;纪实写作和须符合科学逻辑的硬科幻; + 需要逻辑严密的悬疑推理与动作戏(反逻辑法不能用); + 说明书、新闻导语、学术论文、儿童启蒙等只需明确传递信息的段落;写给同行的专业文献(术语是该有的)。 + 与 prose-craft 交接:句长单调、修辞密度、风格杠杆诊断归 prose-craft。 + 与 theme-and-stance 交接:抽象标签、极端情绪缺画面、视角穿帮归本 Skill;主题演示、作家立场、手软/心慈手狠归 theme-and-stance(含 show don't tell 主题层)。 +--- + +# 展示与留白 + +一句话定位:不把结论递给读者,给读者能自己得出结论的材料——写出来的部分是抓手,没写出来的部分是分量。 + +## 方法索引 + +### 写情绪、氛围、性格:把标签换成场景 + +- 抽象标签(愤怒 / 阴森 / 勇敢 / 有效 / 重要)全部换成动作、数字、场景、对话,以"读者脑中能出现什么画面"为验收 → references/show-vs-tell.md +- 极端情绪场景关掉"他感到 / 她心想"的心理分析通道,改写手在做什么、眼睛看到什么、耳朵听到什么、身体什么姿态 → references/extreme-emotion-body.md +- 用一个具体的动作、对话或物件扛住心理、氛围、关系、主题等多层信息,让读者自己读出第二层 → references/iceberg.md + +### 写超现实:让想象可信 + +- 想象与虚幻的差别在有无现实依据:为每个超现实元素找一个读者经验里有的现实锚点,周围用写实笔法、人物反应写得日常,不解释成因 → references/imagination-anchor.md + +### 写留白:用不写来写 + +- 反逻辑三形态:缺席(该出现的人不出现)、反常(该有的反应没有 / 不该有的反应出现)、飞白(该写的不写,让读者从空白读) → references/anti-logic.md +- 写周围人的反应,不写主角的心思,让读者从周围推导主角 → references/anti-logic.md +- 空白处必须留可反推的暗示,并控反逻辑密度:短篇一两处、中篇三到五处、长篇每章约一处 → references/anti-logic.md + +### 写视角:锁住知识边界 + +- 每个视角人物只说、只想他视角内的信息;信息差是叙事张力的引擎,戏剧反讽(读者知道角色不知道)是它的正面用法 → references/pov-knowledge-boundary.md + +### 修订与验证:防读者读不懂 + +- 知识诅咒诊断:写下"显然 / 不用说 / 众所周知"基本是诅咒发作;靠"想得更努力换位"破不了,要靠读者复述、隔夜重读、反向拆解组块 → references/reader-gap-diagnosis.md +- 逐段自问"读者在这里应该看到什么",答不上来就还在告知;只传信息(时间、地点、数字)的地方直接告知即可 → references/show-vs-tell.md +- 全部检查项按写作进程汇总(写作中 / 修订 / 完稿验收) → references/show-omission-checklist.md + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|----------| +| references/show-vs-tell.md | 展示而非告知的原则与认知基础(镜像神经元);四步法(识别标签→问具体→替换具象→画面自检);tell/show 对照例;zombie noun 过度抽象模式;Pinker 三个 show 范本(Dawkins、Greene、兔错觉重写);兔错觉 / 暗能量 / Goldstein 三个案例;六步执行流程;五条不适用边界;四个失败模式;三个盲点(含 AI 腔、中文四字套话);三个易混方法;小说落地五项(情绪 / 氛围 / 节奏 / 对话 / 性格)与小说专属边界;中文适配 | +| references/extreme-emotion-body.md | 无心理描写法:极端情绪关闭心理分析通道、打开身体感官通道;福克纳《沃许》杀人后的视觉动作、陀思妥耶夫斯基《罪与罚》杀人后二十页动作、司汤达《红与黑》桌下握手三个案例全文;五步执行流程(含判停条件与三分之一标准);四条边界(平静场景 / 意识流 / 纪实 / 儿童视角);失败模式(绕开、动作当点缀);盲点(福克纳长篇反例、普遍法则化表述);与冰山理论的"省略 vs 转移"区分 | +| references/imagination-anchor.md | 想象-事实转化法:想象与虚幻的区分(口技木偶 vs 真人);现实锚点;文学的真实含想象、梦境、欲望;毕加索"虚伪中的真实";马尔克斯床单飞天、卡夫卡《变形记》、马尔克斯《虚度年华的海洋》三个案例全文;五步执行流程;三条边界(严格现实主义 / 历史纪实 / 硬科幻);失败模式(把虚幻当想象、过度解释);盲点(网文世界观、无量化标准);与世界观构建、写实主义的区分 | +| references/iceberg.md | 冰山写作法:不是少写,是写有含量的少;《杀手》"哪一份是你的"水面 / 水下拆解;奈保尔《布莱克·沃滋沃斯》"取"vs"讨"一字之差;蒲松龄《促织》"小虫";四步执行流程(水下清单、承载原则、冰山比 1/8-1/3、删字测试);五条触发场景;适用边界与新手慎用;三个常见错误表项 | +| references/anti-logic.md | 反逻辑写作:用不写来写;三种形态(缺席 / 反常 / 飞白);《红楼梦》秦可卿之死原文拆解;王熙凤三次"走"、秦可卿死后消失、林冲向东走、责编轶事四个案例;五步执行流程(该写没写清单、三问归因、反常反应设计、飞白方法与检验、密度控制);适用边界(推理 / 动作戏禁用);四个常见错误表项;与冰山、视角、关系、必然逻辑的跨域链接 | +| references/pov-knowledge-boundary.md | 知识诅咒在小说叙事层的直接应用:POV 角色只知道自己知道的;多视角 / 第一人称 / 第三人称限制 / 多角色对话逐条检查;侦探 .38 口径反例;信息差是叙事张力引擎;戏剧反讽(《罗密欧与朱丽叶》);小说专属边界(全知叙述者 / 童话寓言 / 元小说) | +| references/reader-gap-diagnosis.md | 知识诅咒本体:认知机制定义与英文原段;五个变体(自我中心 / 后见之明 / 错误共识 / 虚幻透明 / 心盲);功能固着与组块化;"显然"自我诊断信号;三破解(close the loop / 隔夜重读 / 反向拆解组块);兔错觉摘要、鸟食器说明书、术语邮件三个案例;七步执行流程;五条边界;三个失败模式;两个盲点(含 AI 腔);三个易混方法(Dunning-Kruger / 读者中心 / 认知负荷) | + +## 脚本 + +| 脚本 | 用途 | +|------|------| +| references/show-omission-checklist.md | 展示与留白检查清单:按写作进程排列(写作中六张子清单:抽象标签 / 极端情绪 / 想象锚点 / 冰山 / 反逻辑 / 视角边界;修订阶段:画面自检、隔夜重读、读者复述;完稿验收:密度与暗示核对;快速排错表) | + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/pi/skills/show-and-omission/references/_coverage.md b/framework/catalog/pi/skills/show-and-omission/references/_coverage.md new file mode 100644 index 0000000..c0b12e3 --- /dev/null +++ b/framework/catalog/pi/skills/show-and-omission/references/_coverage.md @@ -0,0 +1,17 @@ +# show-and-omission 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| bifeiyu-novel-skill/bifeiyu-anti-logic | references/anti-logic.md | +| bifeiyu-novel-skill/bifeiyu-anti-logic | references/iceberg.md | +| bifeiyu-novel-skill/bifeiyu-iceberg | references/iceberg.md | +| bifeiyu-novel-skill/bifeiyu-iceberg | references/anti-logic.md | +| sense-of-style/curse-of-knowledge | references/reader-gap-diagnosis.md | +| sense-of-style/curse-of-knowledge | references/pov-knowledge-boundary.md | +| sense-of-style/show-dont-tell | references/show-vs-tell.md | +| sense-of-style/show-dont-tell | references/extreme-emotion-body.md | +| wo-neng-fou-xiang-xin-zi-ji/imagination-to-fact | references/imagination-anchor.md | +| wo-neng-fou-xiang-xin-zi-ji/no-psychological-description | references/extreme-emotion-body.md | +| wo-neng-fou-xiang-xin-zi-ji/no-psychological-description | references/iceberg.md | diff --git a/framework/catalog/pi/skills/show-and-omission/references/anti-logic.md b/framework/catalog/pi/skills/show-and-omission/references/anti-logic.md new file mode 100644 index 0000000..2f15497 --- /dev/null +++ b/framework/catalog/pi/skills/show-and-omission/references/anti-logic.md @@ -0,0 +1,191 @@ +# 反逻辑与飞白:用不写来写 + +> 来源单元:《小说课》(毕飞宇)bifeiyu-novel-skill/bifeiyu-anti-logic,读《红楼梦》王熙凤/秦可卿 + 曹雪芹的"真事隐去"(第 6 章)。 +> 本文件管"留白"的极端形式:该写的偏偏不写,空白本身就是信息。冰山的一般形式见 [iceberg.md](iceberg.md)。 + +## 原文引文 + +> 「有时候,你从具体的描写对象上反而看不到作者想表达的真实内容,你要从'飞白'——也就是没有写到的地方去看。所谓'真事隐去、假语存焉'就是这个道理。」 + +(/bifeiyu-anti-logic) + +## 书中原文:《红楼梦》第十三回,秦可卿死了 + +**按常理最该悲痛的人**:贾蓉(丈夫)、王熙凤(闺蜜)。 + +**曹雪芹的写法**: + +- 贾蓉、王熙凤在小说里**突然失踪**——没有写他们的反应。 +- 真正反应激烈的是:贾宝玉(喷血)、贾珍(哭成泪人)。 +- 秦可卿的婆婆**尤氏**——祭奠时胃疼、葬礼时胃又疼。 + +**毕飞宇解读**:王熙凤和贾蓉"暧昧"——他们的"消失"是反逻辑的,但**正是这种反逻辑泄露了真相**。 + +(/bifeiyu-anti-logic) + +## 方法核心 + +**反逻辑 = 用"不写"来写。** 当所有人按逻辑应该如此,你偏偏如此——**这本身就是信息**。(/bifeiyu-anti-logic) + +**反逻辑的三种形态**: + +1. **缺席**:该出现的人不出现。 +2. **反常**:该有的反应没有 / 不该有的反应出现。 +3. **飞白**:该写的不写,让读者从"空白"读。 + +## 书中案例 + +### 案例 1:曹雪芹 王熙凤的"走"——三次走,三种心态 + +``` +第一次:一步步行来赞赏(离开秦可卿的病房) + → 字面:心情不错 + → 飞白:心里没别人,包括秦可卿 + +第二次:方移步前来(离开贾瑞的色诱) + → 字面:轻松潇洒 + → 飞白:她根本没把贾瑞放在眼里 + +第三次:款步提衣上了楼 + → 字面:妖娆美不胜收 + → 飞白:王熙凤心里只有"爷们"——欲望 +``` + +**关键**:三次"走"的字面都"正常"——**但放在一起看,反逻辑**。 + +(/bifeiyu-anti-logic) + +### 案例 2:曹雪芹 秦可卿死后的"消失" + +- 贾蓉、熙凤不该消失。 +- 他们的消失泄露了秘密。 +- 尤氏的"胃疼"是反逻辑的"借口"。 + +(/bifeiyu-anti-logic) + +### 案例 3:施耐庵 林冲的"向东走" + +- 林冲被逼到山神庙,杀了人。 +- 接下来他"向东走"。 +- **向东**是反逻辑——林冲没方向,只是流亡。 +- **这个"没方向"本身说明他没想造反**。 + +(/bifeiyu-anti-logic) + +### 案例 4:反逻辑的"话"在叙述者身上的应用 + +> 「一句话原封不动地送给贾责编:遇上你这样的责编,我容易吗我。」 + +——这是反逻辑的"话"在叙述者身上的应用(毕飞宇叙述自己与编辑的关系)。 + +注:源单元此条标题文字有串讹(混入"莫泊桑《项链》"与"王熙凤的'见面'"字样),内容与《项链》、王熙凤无关,按内容保留如上。(/bifeiyu-anti-logic) + +## 触发场景 + +1. 你想写"两个人有秘密"但不能明说 → 用反逻辑。 +2. 你的人物"应该"有反应但你没有写 → 检查是不是用了反逻辑。 +3. 你发现"不该出现的反应"出现了 → 这是金矿。 +4. 你想让读者读出"字面之外" → 用飞白。 +5. 你的小说太"顺"了 → 考虑加一个反逻辑点。 + +(/bifeiyu-anti-logic) + +## 可执行步骤 + +### 步骤 1:识别"应该写但没写" + +列出场景里**按逻辑应该有反应/动作**的所有元素: + +```yaml +场景:秦可卿之死 +应该反应的人: + - 贾蓉(丈夫)—— ❌ 失踪 + - 王熙凤(闺蜜)—— ❌ 失踪 + - 尤氏(婆婆)—— ✅ 胃疼(反常) +实际反应的人: + - 贾宝玉 —— 喷血 + - 贾珍 —— 哭成泪人 +``` + +**失踪就是反逻辑**。 + +### 步骤 2:问"为什么没写" + +为每一个"应该写但没写"找原因: + +- 是作家没想到?→ 补上。 +- 是作家刻意?→ 这是反逻辑——深挖原因。 +- 是作家"藏"了?→ 这是飞白——设计空白让读者填空。 + +### 步骤 3:设计"反常反应" + +让一个**不该有反应的人有反应**,或者**该有反应的人反应异常**: + +``` +不该反应的人反应 → 揭示隐藏关系 +该反应的人无反应 → 揭示心理距离 +该反应的人反常反应 → 揭示深藏的性格 +``` + +### 步骤 4:用"飞白"留白 + +**最难的技巧**:让读者读"没说出口的话"。 + +方法: + +1. 写出"周围的人的反应"。 +2. 不写"主角的反应"。 +3. 让读者从"周围"推导"主角"。 + +**检验**: + +> "我从没写到主角的心思,但读者读出来了吗?" + +### 步骤 5:检验"反逻辑密度" + +一部小说里**反逻辑点不能太多**——多了读者读不懂。 + +- 短篇:**1-2 个**反逻辑点足够。 +- 中篇:**3-5 个**。 +- 长篇:每章节 1 个,累积密度可控。 + +(以上五步均出自/bifeiyu-anti-logic) + +## 适用边界 + +- **适合**:长篇、复杂人物关系、有秘密的情节。 +- **慎用**:短篇(密度太高会失焦)。 +- **不适合**:动作戏、悬疑推理(它们要逻辑严密)。 + +(/bifeiyu-anti-logic) + +## 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 反逻辑当逻辑用 | 人物不真实 | 反逻辑要有"暗示"——读者事后能反推 | +| 反逻辑太多 | 读者困惑 | 短篇不超过 2 处 | +| 飞白留白变成"偷懒" | 读者读不懂 | 飞白也要"暗示" | +| 滥用巧合 | 假 | 反逻辑是结构选择,巧合是偷懒 | + +(/bifeiyu-anti-logic) + +## 一句话总结 + +> **真正的高手从不写主角的心思,只写周围人的反应——让读者自己读出主角在想什么。** + +(/bifeiyu-anti-logic) + +## 与相邻方法的区分与跨域链接 + +- 与 bifeiyu-shakespeare 互补:逻辑是"必然",反逻辑是"反必然"——两者配对才立体。(注:bifeiyu-shakespeare 归 theme-and-stance 综合 skill。) +- 与 bifeiyu-iceberg 同源:反逻辑是冰山的极端形式——"水下"是**没发生的事**(见 [iceberg.md](iceberg.md))。 +- 与 bifeiyu-perspective 配合:反逻辑往往通过"看的人"实现。(注:bifeiyu-perspective 归 narration-pov 综合 skill。) +- 与 bifeiyu-relationship 同源:关系即人物——反逻辑经常用于揭示隐藏关系。(注:bifeiyu-relationship 归 character-presentation 综合 skill。) + +(/bifeiyu-anti-logic) + +## 同一方法的多书视角 + +- Pinker 从读者认知一端给出同样的要求:读者处理具体动作时镜像神经元激活、处理抽象标签时没有感官激活——飞白正是把"主角的心思"这个抽象留给读者用自己的感官经验去补全(见 [show-vs-tell.md](show-vs-tell.md))。 +- 余华的无心理描写法是飞白的近亲:不写主角的心理,写他的身体和周围(见 [extreme-emotion-body.md](extreme-emotion-body.md))。区别在于:无心理描写法写主角的身体动作,飞白连主角的身体也不写,只写周围人。 diff --git a/framework/catalog/pi/skills/show-and-omission/references/extreme-emotion-body.md b/framework/catalog/pi/skills/show-and-omission/references/extreme-emotion-body.md new file mode 100644 index 0000000..b7e5f47 --- /dev/null +++ b/framework/catalog/pi/skills/show-and-omission/references/extreme-emotion-body.md @@ -0,0 +1,138 @@ +# 极端情绪不写心理,写身体:无心理描写法 + +> 来源单元:《我能否相信自己》(余华)wo-neng-fou-xiang-xin-zi-ji/no-psychological-description,《内心之死》(1998) / 《我能否相信自己》演讲。 +> 本文件管极端情绪场景(狂喜、崩溃、杀人后、噩耗、求爱)的内心呈现。这是 show-don't-tell 在情绪层的具体应用(总原则见 [show-vs-tell.md](show-vs-tell.md));它与冰山理论的区别("转移"vs"省略")见本文件末节。 + +## 原文引文 + +> "心理描写是知识分子虚构出来的,来吓唬我们这些写小说的,害得我走了很长一段弯路。" +> +> "当人物最需要内心表达的时候,我学会了如何让人物的心脏停止跳动,同时让他们的眼睛睁开,让他们的耳朵矗起,让他们的身体活跃起来,我知道了这时候人物的状态比什么都重要,因为只有它才真正具有了表达丰富内心的能力。" +> +> — 余华,《内心之死》 + +(/no-psychological-description) + +## 方法核心 + +当人物面临极端情境时,内心是"兵荒马乱"的——百感交集,用再多语言也无法直接表达。此时任何心理分析("他感到极度痛苦""她心中充满矛盾")都会局限人物真实的内心,因为内心在最丰富的时候恰恰是无法言说的。(/no-psychological-description) + +正确的做法是**关闭心理分析的通道,打开身体和感官的通道**:让人物的心脏停止跳动(不写内心),让眼睛睁开(写他看到了什么),让耳朵矗起(写他听到了什么),让身体活跃起来(写他的动作和姿态)。人物的身体状态比任何心理分析都更能表达丰富的内心。(/no-psychological-description) + +这不是"不写内心",而是**通过外在的身体和动作让内心自己浮现**。读者通过人物的动作、视觉、身体状态,自行感受到人物的内心——这种感受比直接告知更强烈、更持久。(/no-psychological-description) + +## 书中案例 + +### 案例 1:福克纳《沃许》——杀人后的视觉描写 + +- **问题**:穷白人沃许砍死了侮辱他外孙女的富白人塞德潘,杀人后的内心如何描写? +- **方法论的使用**:福克纳没有写沃许的心理活动,而是写他出奇的平静——帮助外孙女喝水,安慰她的眼泪,动作"笨拙",姿态"硬挺挺"而且阴沉。他坐在窗口等了一上午,时不时踮脚走到草垫那边。一个白人男孩碰上死尸,抽了口冷气喊了一声,抬头看见窗口的沃许,被催眠似的转身逃开。 +- **结论**:全部是视觉和动作,没有一句心理描写,但杀人者内心的麻木和压力扑面而来。 +- **结果**:余华读到这一段后"明白了"心理描写的真正方式,跨越了写作最大的障碍。 + +(/no-psychological-description) + +### 案例 2:陀思妥耶夫斯基《罪与罚》——杀人后二十页动作 + +- **问题**:拉斯柯尔尼科夫用斧头砍死放高利贷老太婆后,内心的惊恐如何描写? +- **方法论的使用**:陀思妥耶夫斯基写了近二十页,没有一句心理描写。拉斯柯尔尼科夫刚躺下立刻跳起来,感觉袖管上可能有血迹,一看没有,再躺下,接着又跳起来;钥匙插不进锁孔,手上的鲜血擦在红锦缎上;发烧、打寒颤、发现没扣门钩、睡觉没脱衣服还戴着帽子——一连串热锅上的蚂蚁似的动作。 +- **结论**:通过身体的不停动作和对细节的强迫性检查,杀人后的恐惧被表达得淋漓尽致。 +- **结果**:成为文学史上最经典的杀人后心理描写之一,但全程没有"心理描写"。 + +(/no-psychological-description) + +### 案例 3:司汤达《红与黑》——于连抓德·瑞那夫人的手 + +- **问题**:于连在德薇夫人在场的情况下,桌下抓住德·瑞那夫人的手,这个极度紧张的时刻如何写内心? +- **方法论的使用**:司汤达写于连"强迫自己说话,为了不让德薇夫人觉察,于连强迫自己声音洪亮有力";德·瑞那夫人的声音"泄露出来情感的激动,忸怩不安";于连"把这只手握得更紧了";他"高谈阔论,忘记了装假做作"。 +- **结论**:通过声音的变化、手的力度、说话的状态,两个人的内心紧张被精确呈现。 +- **结果**:"他的心浸润在幸福里。并不是他爱着德·瑞那夫人,而是一个可怕的苦难结束了。"——唯一一句心理陈述,但前面的动作已经让读者感受到了。 + +(/no-psychological-description) + +## 触发场景与语言信号 + +用户会在什么情境下需要这个方法(/no-psychological-description): + +1. 写到人物极端情绪(杀人后、得知亲人去世、被背叛、求爱时刻)时,停下笔不知道怎么继续。 +2. 写出的心理描写读起来苍白、像心理学教科书,自己都不满意。 +3. 被编辑/读者反馈"人物情绪不够真实""心理描写太表面"。 +4. 想学习 "show, don't tell" 但不知道具体怎么操作。 +5. 写关键场景时总是"绕过去",用叙述概括代替具体描写。 + +语言信号: + +- "心理描写怎么写" +- "他感到/她心想 这样写是不是太直白" +- "这个情绪场景写不下去了" +- "人物内心活动怎么写才有力量" +- "写杀人/死亡/崩溃场景" +- "show don't tell 具体怎么做" + +## 可执行步骤 + +当这个方法被激活后,按以下步骤执行(/no-psychological-description): + +1. **识别极端情绪场景** + - 完成标准:确认人物正处于狂喜/极度悲伤/恐惧/愤怒/杀人后/求爱等内心"兵荒马乱"的时刻。 + - 判停条件:如果人物内心平静(日常思考、回忆),跳到步骤 5,可直接写心理。 +2. **关闭心理分析通道** + - 删除或避免所有"他感到…""她心想…""心中充满…"式的直接心理陈述。 + - 完成标准:段落中没有任何直接描述内心状态的句子。 +3. **打开身体和感官通道** + - 写人物的**动作**:手在做什么(颤抖/紧握/反复检查/无意识的动作)。 + - 写人物的**视觉**:他的眼睛看到了什么(注意他注视的细节,往往是无关紧要的东西)。 + - 写人物的**听觉**:他听到了什么(环境声音、自己的呼吸/心跳)。 + - 写人物的**身体状态**:姿势、呼吸、体温、肌肉紧张。 + - 完成标准:至少包含 3 种身体/感官维度的描写。 +4. **让动作暴露内心** + - 人物的动作应该是"不由自主"的——反复检查、走来走去、突然停下、机械性重复。 + - 这些动作本身就是内心状态的外化,不需要解释。 + - 完成标准:读者通过动作就能感受到人物情绪,不需要额外说明。 +5. **(非极端场景)适度心理描写** + - 人物内心平静时,可以直接写心理活动,但要简洁。 + - 完成标准:心理描写不超过段落的 1/3,其余用动作和对话。 + +## 不要在以下情况使用 + +- **人物内心平静的日常场景**:此时内心可以直接描写,强行用动作反而做作。 +- **意识流文学的特定追求**:乔伊斯《尤利西斯》、伍尔夫《达洛维夫人》等作品正是以直接心理描写见长,本方法的法则不适用于这种美学追求。 +- **非虚构写作/纪实文学**:纪实作品中人物心理需要基于事实,不能用虚构的动作替代。 +- **儿童视角的内心**:儿童的心理活动本身就是简单直接的,不需要"绕弯子"。 + +(/no-psychological-description) + +## 失败模式(作者在书中警告) + +- **90% 的作家遇到心理描写就绕开**:"很多作家的作品让我们觉得叙述没有问题,语言也很美,可是总在绕来绕去,一到应该冲过去的地方就绕开。"——不要绕开,要用身体动作冲过去。 +- **把动作当装饰**:动作不是心理描写的"点缀",而是替代——必须完全放弃直接心理分析,让动作独立承担表达内心的功能。 + +(/no-psychological-description) + +## 盲点与时代局限 + +- 余华用福克纳的短篇《沃许》论证心理描写不可靠,但福克纳自己的长篇(如《喧哗与骚动》)大量使用意识流式的心理描写——余华选择性地忽略了这个反例。 +- 本方法适用于极端情绪场景,但余华的表述有时像是普遍法则,实际上在平静内心场景中心理描写是有效的。 + +(/no-psychological-description) + +## 容易混淆的邻近方法 + +- **"show, don't tell" 通用原则**:本方法是 show-don't-tell 在极端情绪场景下的具体应用,但更精确——不是泛泛地"展示",而是特指"用身体和感官替代心理分析"。 +- **冰山理论(海明威)**:海明威的冰山理论是"省略",本方法是"转移"——从心理转移到身体,不完全相同。 + +(/no-psychological-description) + +## 与相邻单元的区分与配合 + +- 与 obstacle-crossing(写作障碍应对)的区分与配合:区分面——本方法是具体的写作技法(如何写极端情绪),obstacle-crossing 是写作过程的宏观策略(如何面对和制造障碍)。配合面——两者经常配合使用:心理描写本身就是三大障碍之一,跨越障碍需要无心理描写法。(注:obstacle-crossing 属作者培养类,未入综合 skill 库,仅存于 craft/books/。) +- 与 character-voice-discovery(人物声音发现)的区分与配合:区分面——本方法关注极端情绪下的身体呈现,character-voice-discovery 关注人物日常语言和行为的自发产生。配合面——人物有了自己的声音后,极端情绪下的身体反应会更自然。(注:character-voice-discovery 归 character-presentation 综合 skill。) +- 与 skeptical-narration(怀疑主义叙述)的区分:怀疑主义叙述关注叙述立场,本方法关注叙述技法。(注:skeptical-narration 归 narration-pov 综合 skill。) + +(/no-psychological-description) + +## 同一方法的多书视角 + +- Pinker 从认知科学给同一原则打底:一串具体动作激活镜像神经元,读者"运行"那个场景;体感细节(湿冷 / 沙哑 / 钻痛)比情绪标签(悲伤 / 恐惧)强 10 倍。他还给了中文语境的提醒:四字成语很多是套话,"具体"不等于成语(见 [show-vs-tell.md](show-vs-tell.md) 的中文适配节)。(/show-dont-tell) +- 毕飞宇的冰山法则在操作端给出验收:把"我觉得气氛很紧张""他很害怕"这种形容词式心理描写全部删掉,用一个具体动作替代;别告诉读者"紧张",用一个错误动作让读者自己紧张(见 [iceberg.md](iceberg.md))。(/bifeiyu-iceberg) +- **边界分工的说明**:余华的方法管极端情绪场景(内心"兵荒马乱"时),并明确平静场景可以直接写心理;Pinker 也指出全篇 show 会冗长,第一人称主观体验和全知叙述者的评述是合法手段。两者一致:无心理描写法是极端场景的替代方案,不是全书禁令。(/no-psychological-description;/show-dont-tell) diff --git a/framework/catalog/pi/skills/show-and-omission/references/iceberg.md b/framework/catalog/pi/skills/show-and-omission/references/iceberg.md new file mode 100644 index 0000000..638bab9 --- /dev/null +++ b/framework/catalog/pi/skills/show-and-omission/references/iceberg.md @@ -0,0 +1,142 @@ +# 冰山写作法:用一个动作扛多层信息 + +> 来源单元:《小说课》(毕飞宇)bifeiyu-novel-skill/bifeiyu-iceberg,《杀手》解析 + 海明威冰山理论(第 2 章)。 +> 本文件管"留白"的信息密度端:写出来的每个句子都要让读者读出第二层。用"不写"来写的反逻辑 / 飞白是它的极端形式,见 [anti-logic.md](anti-logic.md);极端情绪的身体呈现见 [extreme-emotion-body.md](extreme-emotion-body.md)。 + +## 原文引文 + +> 「他只写了'八分之一',其余的'八分之七'呢,都在'水下'。」 + +(/bifeiyu-iceberg) + +## 书中原文:《杀手》亨利快餐店那一段 + +《杀手》海明威在亨利快餐店那一段里,"一个字的氛围描写都没有"——但读完让人魂飞魄散。**为什么?**因为冰山在水下。(/bifeiyu-iceberg) + +服务员乔治一上来就问杀手阿尔:"**哪一份是你的?**"——这是一句废话。两个客人,记忆力再差也不会记不住。但海明威偏偏写了这一句废话。**这正是冰山**: + +``` +水面上的 1/8:乔治问"哪一份是你的" +水面下的 7/8: + - 乔治没有做笔录(紧张到忘记) + - 乔治没把握(再谨慎也不过) + - 整个餐厅气氛令人窒息 + - 两个杀手的压迫感被一个问句承载 +``` + +(/bifeiyu-iceberg) + +## 方法核心 + +**冰山理论不是"少写"——是"写有含量的少"**。你写出来的每个句子,必须承担它表面看不出来的重量。(/bifeiyu-iceberg) + +- 错误理解:写得越少越好。 +- 正确理解:写出来的每个细节都要让读者"读到第二层"。 + +## 书中案例 + +### 案例 1:海明威《杀手》"哪一份是你的" + +- **水面**:一个服务员问一句。 +- **水下**:整个故事的张力、人物心理、环境氛围全在这一句里。 + +(/bifeiyu-iceberg) + +### 案例 2:奈保尔《布莱克·沃滋沃斯》"来取走他的那一分钱" + +- **水面**:一个盲人乞丐"取"钱。 +- **水下**:他已经忘记自己是乞丐了,他当自己是公务员——性格、尊严、悲剧全在"取"vs"讨"的一字之差。 + +(/bifeiyu-iceberg) + +### 案例 3:蒲松龄《促织》"小虫" + +- **水面**:成名的儿子变成了一只小促织。 +- **水下**:全篇始终用"虫",唯独这里用"小虫"——父亲不认识儿子,儿子却认得父亲。 + +(/bifeiyu-iceberg) + +## 触发场景 + +当以下情况出现时,调用这个方法(/bifeiyu-iceberg): + +1. 你的对话/动作描写"看起来"平淡 → 检查水下。 +2. 你写了氛围但读者感受不到 → 把氛围藏进动作里。 +3. 你想说"气氛恐怖 X 已经吓傻" → ❌ 删掉,改用一个具体动作。 +4. 你的人物对话"自报家门"("我很紧张")→ ❌ 让动作说话。 +5. 短篇接近结尾、信息密度大 → 检验每句是否承担双重含义。 + +## 可执行步骤 + +### 步骤 1:定位你想写的信息 + +先想清楚:这一段想表达什么?列一个**水下清单**: + +``` +[ ] 人物心理状态 +[ ] 环境氛围 +[ ] 关系张力 +[ ] 主题暗示 +[ ] 情感重量 +``` + +### 步骤 2:选一个表面动作承载 + +找一个**具体动作 / 对话 / 物件**,让上面 5 个元素中的多个附着在上面。 + +> **原则**:能用一个动作承载 3 个元素 = 优秀;承载 1 个 = 浪费。 + +### 步骤 3:检验冰山比 + +写完一段,回头看: + +``` +水面字数 / 总字数 = 1/8 到 1/3 之间最理想 +``` + +太多 = 没给读者留白;太少 = 读者读不懂。 + +### 步骤 4:做"删字"测试 + +把"我觉得气氛很紧张"或"他很害怕"这种**形容词式心理描写**全部删掉,用一个**具体动作**替代。 + +**检验问题**: + +- [ ] 这段删掉后,水下的内容读者能自己"读出来"吗? +- [ ] 读者读完之后会想"原来如此",而不是"他告诉我"? + +(以上四步均出自/bifeiyu-iceberg) + +## 适用边界 + +- **适合**:短篇小说、对话、动作戏、意识流。 +- **不适合**:学术论文、说明书、儿童启蒙(需要明确表意的场景)。 +- **新手慎用**:冰山需要"水面"和"水下"高度匹配,水平不够时强行留白 = 读者读不懂。 + +(/bifeiyu-iceberg) + +## 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 把"留白"做成"省略" | 读者困惑 | 留白是有内容的省略,省略是偷懒 | +| 水下完全无迹可循 | 读者感受不到氛围 | 至少要有一个暗示 | +| 满篇都是冰山 | 读者累 | 关键场次用冰山,叙述段用正常密度 | + +(/bifeiyu-iceberg) + +## 一句话总结 + +> **别告诉读者"紧张",用一个错误动作让读者自己紧张。** + +(/bifeiyu-iceberg) + +## 与相邻方法的区分与跨域链接 + +- 与 bifeiyu-paiban(白描)形成对比:白描是"少即是多"在人物刻画上的应用,冰山是"少即是多"在信息密度上的应用。(注:bifeiyu-paiban 归 prose-craft 综合 skill。) +- 与 bifeiyu-anti-norm(反常)互补:反常是发现冰山的好工具——一个反常动作必有 7/8 在水下。(注:bifeiyu-anti-norm 归 character-presentation 综合 skill。) +- 与 bifeiyu-lyric-pass(抒情不抒发)同源:都是"克制"的不同表现。(注:bifeiyu-lyric-pass 归 prose-craft 综合 skill。) +- 与反逻辑同源:**反逻辑是冰山的极端形式——"水下"是没发生的事**(该出现的人缺席、该有的反应没有),见 [anti-logic.md](anti-logic.md)。 +- 与余华无心理描写法的关系:余华的方法是"转移"(从心理转移到身体),冰山是"省略"(把内容压到水下);两者在"删掉形容词式心理描写、用具体动作替代"这一步上汇合。(/no-psychological-description;/bifeiyu-iceberg) + +(/bifeiyu-iceberg) diff --git a/framework/catalog/pi/skills/show-and-omission/references/imagination-anchor.md b/framework/catalog/pi/skills/show-and-omission/references/imagination-anchor.md new file mode 100644 index 0000000..609ba91 --- /dev/null +++ b/framework/catalog/pi/skills/show-and-omission/references/imagination-anchor.md @@ -0,0 +1,144 @@ +# 给超现实的东西一个现实锚点:想象-事实转化法 + +> 来源单元:《我能否相信自己》(余华)wo-neng-fou-xiang-xin-zi-ji/imagination-to-fact,《强劲的想象产生事实》(1995)。 +> 本文件管奇幻、梦境、超现实情节的可信度。超现实场景中人物的反应同样适用无心理描写法(见 [extreme-emotion-body.md](extreme-emotion-body.md))。 + +## 原文引文 + +> "强劲的想象产生事实。" +> +> "想象应该有着现实的依据,或者说想象应该产生事实,否则就只是臆造和谎言。" +> +> "虚幻和想象之间的区别,就跟口技演员手里操纵的木偶和真人一样。" +> +> — 余华,《强劲的想象产生事实》 + +(/imagination-to-fact) + +## 方法核心 + +文学中的想象不是凭空捏造,而是**"强劲的想象产生事实"**——想象必须有现实依据,才能让读者信服。关键区分(/imagination-to-fact): + +- **想象**:有现实依据,能落地为读者可感的真实。读者不质疑其真实性,甚至觉得"这就是真的"。 +- **虚幻**:没有现实依据,不知所云。读者觉得"假""出戏"。 + +**马尔克斯的例子**:写俏姑娘雷梅苔丝飞上天,苦思冥想后看到院子里黑女人晾床单被风刮跑,茅塞顿开——用床单作为飞翔的载体。床单是现实的,风是现实的,"抓着床单飞上天"就从虚幻变成了想象,读者信服。(/imagination-to-fact) + +**文学的真实不等于现实的真实**。"文学的真实是不能用现实生活的尺度去衡量的,它的真实里还包括了想象、梦境和欲望。"毕加索说"艺术家应该让人们懂得虚伪中的真实"——文学的真实是"虚伪中的真实"。(/imagination-to-fact) + +## 书中案例 + +### 案例 1:马尔克斯用床单让俏姑娘飞上天 + +- **问题**:《百年孤独》中俏姑娘雷梅苔丝要飞上天,怎么写才可信? +- **方法论的使用**:马尔克斯苦思冥想,"她怎么也上不了天"。直到看到院子里一个洗衣服的黑女人晾床单,床单被风刮跑。他茅塞顿开:让雷梅苔丝抓着床单飞上天。床单是现实物品,风是现实力量,飞翔就有了现实锚点。 +- **结论**:"当我坐到打字机前的时候,俏姑娘雷梅苔丝就一个劲儿地飞呀,飞呀,连上帝也拦她不住了。" +- **结果**:成为文学史上最经典的魔幻现实主义场景之一。 + +(/imagination-to-fact) + +### 案例 2:卡夫卡《变形记》——人变甲虫 + +- **问题**:人变成一只巨大的甲虫,读者怎么会相信? +- **方法论的使用**:卡夫卡没有解释"为什么变甲虫",而是用极其写实的细节描写甲虫的身体(坚硬的背、许多细腿)、格里高尔的反应(看闹钟、想工作、担心赶不上火车)、家人的反应(秘书主任来访)。现实细节越扎实,甲虫这个超现实设定就越可信。 +- **结论**:经过八十年阅读检验,"是否真实的问题已经不存在了",《变形记》成为经典。 +- **结果**:成为现代文学的奠基之作。 + +(/imagination-to-fact) + +### 案例 3:马尔克斯区分想象与虚幻 + +- **问题**:马尔克斯曾写了一本童话《虚度年华的海洋》,朋友坦率告诉他不喜欢,认为"虚幻至少对你来说,真是不知所云"。 +- **方法论的使用**:马尔克斯幡然醒悟——"孩子们也不喜欢虚幻,他们喜欢想象的东西。"虚幻是口技演员的木偶,想象是真人。此后他的作品都坚持"强劲的想象产生事实"。 +- **结论**:区分想象和虚幻是写奇幻内容的关键。 +- **结果**:马尔克斯成为魔幻现实主义的代表作家。 + +(/imagination-to-fact) + +## 触发场景与语言信号 + +用户会在什么情境下需要这个方法(/imagination-to-fact): + +1. 写奇幻/超现实情节,读者反馈"太假了""出戏"。 +2. 想写魔幻现实主义但不知道怎么让虚构内容可信。 +3. 写梦境/幻觉/回忆场景时缺乏真实感。 +4. 脑洞很大但写出来像胡说八道。 +5. 想学习马尔克斯/卡夫卡的写作方法。 +6. 被反馈"设定不错但没有说服力"。 + +语言信号: + +- "写得假" "不可信" "出戏" +- "魔幻现实主义怎么写" "奇幻情节" "magical realism" "imagination" +- "脑洞写出来像胡说" +- "虚构真实感" "verisimilitude" +- "读者不相信我的设定" +- "梦境怎么写" "幻觉场景" + +## 可执行步骤 + +当这个方法被激活后,按以下步骤执行(/imagination-to-fact): + +1. **识别需要转化的想象内容** + - 哪些情节/设定是超现实的?(人变甲虫、人飞上天、死人说话等) + - 完成标准:明确需要"想象-事实转化"的具体内容。 +2. **寻找现实锚点** + - 为超现实内容找一个现实的载体/物品/动作/细节: + - 飞上天 → 抓着床单(被风刮跑的现实经验) + - 人变甲虫 → 描写甲虫身体的具体细节 + 人物的日常反应(看闹钟、想工作) + - 死人说话 → 描写死人的具体状态 + 活人的日常反应 + - 锚点必须是读者有现实经验的东西。 + - 完成标准:为每个超现实内容找到至少一个现实锚点。 +3. **用写实手法写超现实内容** + - 不解释"为什么会这样"(越解释越假)。 + - 用极其写实的细节描写超现实事件中的人物反应和环境。 + - 人物的反应应该是日常的(惊讶、困惑、继续生活),不是戏剧化的。 + - 完成标准:超现实内容周围的叙述是写实的、具体的、有细节的。 +4. **检查想象 vs 虚幻** + - 问自己:读者能在现实经验中找到这个想象的锚点吗? + - 如果完全没有现实依据,就是虚幻,需要添加锚点。 + - 如果有现实依据但处理得太抽象,需要增加具体细节。 + - 完成标准:想象内容有明确的现实支撑,读者不觉得"假"。 +5. **利用"虚伪中的真实"** + - 记住文学的真实不等于现实的真实。 + - 想象、梦境、欲望都是文学真实的一部分。 + - 不需要让一切符合现实逻辑,但需要让一切符合"文学的逻辑"(内在一致)。 + - 完成标准:作品有内在一致性,读者沉浸其中不质疑。 + +## 不要在以下情况使用 + +- **严格现实主义写作**:如果作品设定就是"完全符合现实",不需要超现实元素,也不需要转化。 +- **历史/纪实写作**:必须基于事实,不能用"想象"替代事实。 +- **硬科幻**:需要符合科学逻辑,不能用"文学真实"替代科学真实。 + +(/imagination-to-fact) + +## 失败模式(作者在书中警告) + +- **把虚幻当想象**:马尔克斯的教训——写了一本童话《虚度年华的海洋》,朋友说"虚幻至少对你来说,真是不知所云"。没有现实依据的离奇就是虚幻,不是想象。 +- **过度解释超现实**:越解释"为什么人会变甲虫",读者越觉得假。卡夫卡不解释,直接用写实细节呈现,反而可信。 + +(/imagination-to-fact) + +## 盲点与时代局限 + +- 余华主要讨论魔幻现实主义和现代主义文学,没有讨论网络文学/类型文学中如何建立设定可信度(需要更系统化的世界观构建)。 +- "强劲的想象产生事实"是经验性描述,没有给出判断"现实依据是否足够"的量化标准。 + +(/imagination-to-fact) + +## 容易混淆的邻近方法 + +- **"世界观构建"(worldbuilding)**:世界观构建是系统化地设定虚构世界的规则,本方法是为单个超现实元素找现实锚点。前者是宏观,后者是微观。 +- **"写实主义"**:写实主义追求完全符合现实,本方法是让超现实内容有现实感——不是写实,是"让虚构可信"。 + +(/imagination-to-fact) + +## 与相邻单元的区分与配合 + +- 与 detail-driven-climax(细节驱动高潮)的区别:本方法关注如何让虚构内容可信(现实锚点),detail-driven-climax 关注如何用细节驱动情节高潮。两者都用细节,但目的不同——一个是建立可信度,一个是驱动情节。(注:detail-driven-climax 归 foreshadow-payoff 综合 skill。) +- 与 certainty-uncertainty-tension(确定与不确定的张力)的区分与配合:区分面——本方法让超现实内容变得确定(可信),certainty-uncertainty-tension 保留不确定性。一个是"让读者相信",一个是"让读者回味"。配合面——想象的内容可以同时保留确定性(可信)和不确定性(多义):现实锚点让读者相信,保留的多义让读者回味,同一段想象内容可以两者兼得。(注:certainty-uncertainty-tension 归 narration-pov 综合 skill。) +- 与 no-psychological-description 的配合:超现实场景中的人物反应也需要用动作/视觉代替心理分析(见 [extreme-emotion-body.md](extreme-emotion-body.md))。 +- 现实锚点往往就是驱动高潮的细节:想象锚点与伏笔细节可以共用同一个物件。 + +(/imagination-to-fact) diff --git a/framework/catalog/pi/skills/show-and-omission/references/pov-knowledge-boundary.md b/framework/catalog/pi/skills/show-and-omission/references/pov-knowledge-boundary.md new file mode 100644 index 0000000..49ea7c4 --- /dev/null +++ b/framework/catalog/pi/skills/show-and-omission/references/pov-knowledge-boundary.md @@ -0,0 +1,49 @@ +# 视角人物的知识边界与信息差 + +> 来源单元:《The Sense of Style / 风格感觉》(Steven Pinker)sense-of-style/curse-of-knowledge,第 3 章,小说写作应用部分。 +> 本文件管叙事层的知识诅咒:视角人物只知道自己知道的。知识诅咒的认知机制、诊断与三破解(修订端)见 [reader-gap-diagnosis.md](reader-gap-diagnosis.md)。 + +## 方法核心:知识诅咒在叙事层的直接应用 = POV 角色只知道自己知道的 + +知识诅咒是小说写作的关键方法,尤其在多视角小说里几乎是核心工具。判断标准:**角色在 POV 段里说/想了只在他自己视角里可能的信息吗?**(/curse-of-knowledge) + +## 在小说里怎么用 + +(/curse-of-knowledge) + +- **多视角小说**:检查每个 POV 段里,角色说/想的信息是否只在他视角内。 + - 反例:写一个侦探在凶手 POV 段里说"凶手用的是 .38 口径"——侦探不知道这个,错。 +- **第一人称 POV**:"我"不能写"我"视角外的事(不能写别的房间发生了什么,除非"我"后来被告知)。 +- **第三人称限制 POV**:严格限制在角色视角内,内心独白只能来自该角色。 +- **多角色对话**:每个人的话只能基于"他此刻知道的信息"。 +- **"信息差"是叙事张力的引擎**:知识诅咒诊断 = 哪里有信息差;修复 = 让 POV 角色没看到/想到那个信息。 + +## 戏剧反讽:诅咒的反用 + +读者知道角色不知道,正是诅咒的精彩反用(《罗密欧与朱丽叶》里我们都知道朱丽叶没死,罗密欧不知道)。(/curse-of-knowledge) + +## 小说专属边界 + +- **全知叙述者**:不受知识诅咒,不该机械应用(但用太多读者会觉得"在作弊")。 +- **童话/寓言**(无明确 POV)——不适用。 +- **元小说**(故意打破视角)——是合法实验,不该当成 bug 修。 + +(/curse-of-knowledge) + +## 执行要点 + +1. 每个视角段落动笔前先写下:这个人物此刻**不该知道**什么。 +2. 逐句检查该段的对话与内心独白有没有越界(说出/想到视角外的信息)。 +3. 必须交代给读者的信息改由合法渠道进入:他人转述、事后得知、亲眼看见。 +4. 有意制造信息差时,先想清楚它服务哪种张力:读者知道角色不知道(戏剧反讽),还是角色知道读者不知道(悬念)。 + +判断标准:信息差是设计出来服务张力的,不是无意漏出去的。(执行要点据源单元小说应用部分整理;/curse-of-knowledge) + +## 中文落地说明 + +这条方法不涉及语言差异:中文小说的多视角、第一人称、第三人称限制视角同样适用,检查标准一致——每个视角人物只能说、只想他视角内的信息。中文古典小说里全知叙述者("话说""且说")是常态,用本方法时要先确认作品选择的是全知还是限制视角:选了限制视角就严格执行,选了全知就不必机械套用,但要知道全知用多了读者会觉得"在作弊"。(中文落地说明;方法本体来自/curse-of-knowledge) + +## 与相邻方法的区分 + +- 与知识诅咒本体(reader-gap-diagnosis)的关系:诅咒本体管"作者以为读者懂"(术语、跳步),是修订端的诊断;本文件管"角色知道了不该知道的",是写作端的视角纪律。同一个认知机制,两个应用面。 +- 与反逻辑(飞白)的配合:飞白是"该写的不写",视角边界是"不该写的不能写"——一个主动藏,一个被动守,见 [anti-logic.md](anti-logic.md)。 diff --git a/framework/catalog/pi/skills/show-and-omission/references/reader-gap-diagnosis.md b/framework/catalog/pi/skills/show-and-omission/references/reader-gap-diagnosis.md new file mode 100644 index 0000000..bb2c9d1 --- /dev/null +++ b/framework/catalog/pi/skills/show-and-omission/references/reader-gap-diagnosis.md @@ -0,0 +1,158 @@ +# 读者为什么读不懂:知识诅咒的诊断与三破解 + +> 来源单元:《The Sense of Style / 风格感觉》(Steven Pinker)sense-of-style/curse-of-knowledge,第 3 章 — The Curse of Knowledge。 +> 本文件管修订端的诊断:写出来的东西读者跟不上,作者却查不出问题在哪。知识诅咒在小说叙事层的应用(视角边界与信息差)见 [pov-knowledge-boundary.md](pov-knowledge-boundary.md);"用具象绕过诅咒"的具体方法见 [show-vs-tell.md](show-vs-tell.md)。 + +## 原文引文 + +> The curse of knowledge is the single best explanation I know of why good people write bad prose. It simply doesn't occur to the writer that her readers don't know what she knows — that they haven't mastered the patois of her guild, can't divine the missing steps that seem too obvious to mention, have no way to visualize a scene that to her is as clear as day. And so she doesn't bother to explain the jargon, or spell out the logic, or supply the necessary detail. +> +> — Steven Pinker, *The Sense of Style*, Chapter 3 + +(/curse-of-knowledge) + +## 方法核心:这是认知机制,不是态度问题 + +知识诅咒(curse of knowledge)是一个**认知机制**,不是态度问题:一旦你掌握了一个概念(一个术语 / 一个推导 / 一个场景),你就再也无法想象"不知道它"是什么感觉。(/curse-of-knowledge) + +具体有 5 个变体(Pinker 引用心理学研究): + +1. **自我中心(egocentrism)**:小孩子无法想象另一个孩子会从不同角度看三座山模型。成年人残留版本:写作者想象不出"读者没看到的步骤"。 +2. **后见之明偏误(hindsight bias)**:知道结果的人觉得结果"显然"。 +3. **错误共识(false consensus)**:我做这个决定很自然,所以别人也会这样决定。 +4. **虚幻透明(illusory transparency)**:我知道对话的幕后,所以以为对方也能听出讽刺。 +5. **心盲(mindblindness)**:不知道"不在场"的人没看到我所看到的事。 + +诅咒还会和**功能固着(functional fixity)**与**组块化(chunking)**叠加: + +- **功能固着**:熟悉一个概念后,你只想它的"功能"(用来做什么),忘了它的"形貌"(看起来像什么、怎么构成)。 +- **组块化**:专家把 5 个具体信息压成一个词(把 5 句话变成"决策"),写出来一句对新手是 5 句的容量。 + +**自我诊断信号**:写一句时感到"显然" / "不用说" / "显然" / "obviously"——几乎一定是诅咒发作。(/curse-of-knowledge) + +## 破解三招(Pinker 推荐) + +1. **关闭回路(close the loop)**:找目标读者的代表,把草稿给他们读,标记他们卡住的地方。靠"想得更努力换位思考"没用的,必须借外力。 +2. **隔夜重读**:写完放一夜,第二天的你和昨天的你已经不同,你会更接近"目标读者"的认知状态。 +3. **反向拆解组块化**:把抽象词(决策 / 杠杆 / 赋能)拆回具体动作(谁,做了什么动作,在什么场景)。 + +(/curse-of-knowledge) + +## 书中案例 + +### 案例 1:兔错觉的学术摘要(Pinker 自己的领域) + +- **问题**:一段认知科学期刊上的摘要,说的是一个简单的知觉实验("兔错觉"),但写成 "stimulus" / "poststimulus event" / "rabbit illusion and its variants" 这种术语,同行专家(Pinker 自己,在知觉研究领域 30+ 年)都读不懂。 +- **方法论的使用**:Pinker 重写这段:"受试者闭眼伸出手臂,实验者依次轻敲手腕、手肘、肩,受试者感觉像一连串轻敲沿手臂跑上去,像兔子跳一样。"把抽象还原成具体动作。 +- **结论**:同行读不懂同行写的摘要——知识诅咒连专家都不能免疫。 +- **结果**:Pinker 用此例论证"必须 close the loop"。一个专业领域的摘要,必须让该领域的另一个专家能读懂,都要靠外部反馈,不能靠"自己再努力"。 + +(/curse-of-knowledge) + +### 案例 2:给鸟器说明书(教学场景) + +- **问题**:一位教授给班上学生发了一份组装鸟食器的说明书,20 多分钟过去,没人能装上,大家都觉得是自己的问题。 +- **方法论的使用**:重新设计说明书,关键改动:把抽象描述("合适高度")改成具体数字("4½ inches from the bottom of the perch")。 +- **结论**:写说明书的人知道"什么是什么",但忘了"看上去是什么",功能固着让步骤看起来"显然"。 +- **结果**:找学生反馈(close the loop)之后,步骤改成"显然"不再显然,都能装上了。 + +(/curse-of-knowledge) + +### 案例 3:日常邮件里的术语 + +- **问题**:同事发邮件说 "Please effectuate a leverage of the existing core competency",看不懂,但又不能回邮件承认(显得不专业)。 +- **方法论的使用**:读这封邮件的人会归因为"对方故弄玄虚"或"我水平不够",几乎不会想到是知识诅咒。 +- **结论**:诅咒的隐匿性是它最危险的地方——写作者和读者都看不到。 +- **结果**:Pinker 引 Hanlon's Razor:"用愚蠢(理解不了)足以解释,就不要用恶意(故意刁难)揣测"——但他反转:把这个原则用在自己身上,当读者读不懂,第一时间是"我没写清楚"。 + +(/curse-of-knowledge) + +## 触发场景与语言信号 + +用户会在什么情境下需要这个方法(/curse-of-knowledge): + +1. 用户写完一篇文章,收到反馈"读不懂"但自己检查不出哪里有问题——需要诅咒诊断。 +2. 用户即将开始一个非虚构写作项目(论文 / 报告 / 教程 / 公文),想要从一开始就设计"读者友好"而不是事后改。 +3. 用户给非专业读者解释一个自己擅长的概念(写科普 / 给客户讲方案 / 教新人),反复被问"简单点说"。 +4. 用户用同一种方式(术语满篇 / 跳过步骤)写了好多年,怀疑"是不是我写作方式有问题"。 +5. 用户是老师 / 培训师,反复被学生说"听不懂",想知道为什么。 + +语言信号(用户的话里出现这些就应激活): + +- "为什么我写的东西别人读不懂" / "明明很显然" / "我以为大家都懂" +- "专家也说我写得不清晰" / "同行读不下去" / "被批术语太多" +- "我讲得这么清楚,怎么还有人问" / "我是不是太专业了" +- "curse of knowledge" / "why do smart readers not get this" / "they don't know what I know" / "why is this jargon" +- "我每次都被问'这是什么'" / "解释再多,同事还是不懂" + +## 可执行步骤 + +当这个方法被激活后,按以下步骤执行(各步完成标准来自源单元)(/curse-of-knowledge): + +1. **自我诊断:这段在写给谁?这段依赖了读者已经知道的什么?** + - 完成标准:写作者能列出"读者读这段前,必须已经知道的 3 个前置信息"。如果一个都列不出,这段抽象层级太高;如果列出但没有显式给出,这段在跳步。 +2. **逐句扫描"显然" / "obviously" / "众所周知" / "不用说"这种话** + - 完成标准:全文每处"显然"标记出来,思考"对哪个读者层级是显然?"如果是"对我是显然",几乎一定是诅咒,改写。 +3. **逐句扫描"术语 / 缩写 / 行业黑话"** + - 完成标准:把所有术语列出,问"对一个该领域的入门读者,这词能解释吗?"。如果不能,第一次出现时要附简短解释;如果该术语可以用更简单的同义词替代,替代。 +4. **三破解之一:找读者反馈(close the loop)** + - 完成标准:把草稿发给至少 1 个目标读者的代表,让他标记他卡住的地方。不要"问写得清不清楚"(这种问题对方会说清楚),要"让他读完后讲一遍"(这样能看出他真懂还是假懂)。 +5. **三破解之二:隔夜重读(read after a gap)** + - 完成标准:写完一稿,至少隔一夜再读。第二天读时,"显然"不再显然的地方会自动暴露。 +6. **三破解之三:反向拆解组块化(de-chunking)** + - 完成标准:把抽象词("决策" / "杠杆" / "赋能" / "做这个分析")拆回具体动作(谁 / 做了什么 / 在什么场景)。如果拆不开,那个抽象词可能是"作者自己都没想清楚"的标签。 +7. **用"我从未"双重否定自检**:"如果我从未听过这个概念,我读这段,哪个词是第一个我需要查的?"找到那个词,看是否需要解释或换掉。 + - 完成标准:至少识别 1 个"自己写的、自己却要查"的词,解释或换掉。 + +## 不要在以下情况使用 + +- **内容本来就不该被一般人懂**:前沿学术论文 / 行业内部备忘 / 暗号——这类文本的目标就不是让外行读懂,诅咒诊断不适用。 +- **写给同行的专业文献**:知识诅咒的反应用在这里,期刊论文就该用术语。但即便如此,摘要应给非专业读者,全文可保持术语。 +- **写作目的就是筛选读者**:营销 / 招聘 JD / 投行 pitch——写作者本就想让"不专业的人"退出,知识诅咒成了"过滤器",反而有效。 +- **用户没写,只是在"想要表达"阶段**:curse-of-knowledge 假设已经有草稿,还没写之前该用 classic-style(确定姿态)。(注:classic-style 未入综合 skill 库。) +- **教学讲义里"该用术语"的部分**:大一物理课讲 F=ma 之前必须用专业术语,不能用"力" + "质量" + "加速度"反复说(虽然诅咒理论本身提醒教师检查"显然")。 + +(/curse-of-knowledge) + +## 失败模式(作者在书中警告) + +- **把"换位思考"当破解**:Pinker 明确说光靠"想得更努力"没用,必须 close the loop(外部反馈)。写作时默念"读者可能不懂"不解决问题,因为诅咒让你看不到自己看不到的东西。 +- **把诅咒归因于态度**:知识诅咒是认知机制,不是傲慢。把读者的不理解归因于"他们没文化"只会强化诅咒。 +- **反馈只问"清不清楚"**:这是元层面的问题,读者会客气地说"清楚"。要让他复述,不要让他评分。 + +(/curse-of-knowledge) + +## 盲点与时代局限 + +- 写于 2014,当时还没有 LLM 写作工具。今天的诅咒还包括"AI 生成的默认空泛"(e.g.,"在当今快速变化的时代,我们要…"这种空洞话),经典风格的破解对 AI 腔也有效,但要先识别是"AI 腔"而非"人写烂"。 +- Pinker 的"找读者反馈"默认存在一个"愿意读草稿的目标读者"。在很多场景(内部备忘 / 公开博文)没有这种读者,必须用其他破解(隔夜重读 / 找非目标读者代读)替代。 + +(/curse-of-knowledge) + +## 容易混淆的邻近方法 + +- **Dunning-Kruger 效应**:知识水平低的人高估自己,知识诅咒是反方向——知识水平高的人想象不到自己拥有的知识。这两个不是同一个机制,治疗方式也不同。 +- **"以读者为中心"写作建议**:这是常识,没有"为什么"也没有"怎么破",知识诅咒提供了具体的认知机制 + 三个可执行破解。 +- **认知负荷理论(cognitive load theory)**:知识诅咒是"信息选择"层面的问题,认知负荷是"工作记忆容量"层面的问题。两者相关但不同——诅咒让你选错了信息(太多术语),认知负荷让你选对信息后还放不下(句法嵌套太深)。 + +(/curse-of-knowledge) + +## 与相邻方法的区分(源单元内引用) + +- 与 classic-style 的区分与配合:区分面——classic-style 提供"姿态"(解药),curse-of-knowledge 提供"诊断"(病灶)。前者是"应该怎么写",后者是"为什么会写成这样"。配合方向——诅咒破解 → 经典风格可生效:先把诅咒诊断出来、补上缺失的步骤,经典风格的姿态才落得下去。(注:classic-style 未入综合 skill 库。) +- 与 web-tree-string 的区别:web-tree-string 解决"句法层级让读者累",curse-of-knowledge 解决"术语和跳步让读者看不懂"。前者是句子结构问题,后者是内容选择问题。(注:web-tree-string 未入综合 skill 库。) +- 与 metadiscourse-killer 的区分与配合:区分面——metadiscourse-killer 删"作者谈论写作本身的话",curse-of-knowledge 删"作者无意识地假设读者已经知道的步骤"。前者是自我指涉,后者是信息缺失。配合面——元话语是诅咒的"自我看不见"表现:作者看不见自己在绕着自己说话,正如看不见读者缺了什么信息,两个方法治的是同一种看不见。(注:metadiscourse-killer 为非虚构专用单元,裁剪未入库,仅存于 craft/books/。) +- 与 zombie-noun-revival 的配合:zombie 名词是诅咒的典型表现。(注:zombie noun 的中文落地例子见 [show-vs-tell.md](show-vs-tell.md) 的"过度抽象模式"节。) +- 与 show-don't-tell 的关系:诅咒是病灶,show 是治疗——用具象绕过诅咒,见 [show-vs-tell.md](show-vs-tell.md)。 + +(/curse-of-knowledge) + +## 中文落地说明 + +Pinker 以英文写作场景立论,中文落地时: + +1. **中文的"显然"信号词**:除"显然 / 不用说 / 众所周知"外,"大家都知道""不言而喻""顾名思义""懂的自然懂"同样几乎一定是诅咒发作。 +2. **中文的组块化词**:源单元给出的拆词例子本身就是中文——"决策 / 杠杆 / 赋能 / 做这个分析",这类词在中文公文腔、互联网黑话里密集出现,反向拆解直接可用(中文适配)。 +3. **中文术语邮件的对应物**:源单元案例 3 的 "Please effectuate a leverage of the existing core competency" 在中文语境对应"抓手、闭环、对齐颗粒度"式堆砌;读者同样会归因于"对方故弄玄虚"而不是知识诅咒,Hanlon's Razor 反转(第一时间想"我没写清楚")同样适用。 + +(中文落地说明;方法本体来自/curse-of-knowledge) diff --git a/framework/catalog/pi/skills/show-and-omission/references/show-omission-checklist.md b/framework/catalog/pi/skills/show-and-omission/references/show-omission-checklist.md new file mode 100644 index 0000000..4796a9b --- /dev/null +++ b/framework/catalog/pi/skills/show-and-omission/references/show-omission-checklist.md @@ -0,0 +1,109 @@ +# 展示与留白检查清单 + +> 汇总六个源单元的可执行检查项,按写作进程排列:写作中 → 修订阶段 → 完稿验收。 +> 每条注明来源;方法细节与案例见 references/ 对应文件。 + +## 一、写作中:抽象标签扫描 + +写情绪、氛围、性格评价时逐条核对(/show-dont-tell): + +- [ ] 全文搜过抽象标签:英文 effective / successful / important / optimal / professional / innovative / high-quality / meaningful / efficient;中文"很 / 十分 / 充满 + 情绪词"与评价式形容词(勇敢 / 专业 / 重要 / 有效) +- [ ] 每个标签都问过"具体是什么":哪个动作 / 数字 / 场景 / 对话让你想用这个词 +- [ ] 拆不出具体内容的标签已删或已换——拆不开,说明作者自己没看清那个场景 +- [ ] 每一段都能回答"读者在这里应该看到、听到、触到什么" +- [ ] 只传信息(时间、地点、电话号码、定义、总结)的地方允许直接告知,不为 show 而 show +- [ ] 中文里没有拿四字套话当具象("灯红酒绿""心如刀绞"是成语库存,不是画面)(中文适配) + +## 二、写作中:极端情绪场景(无心理描写) + +确认人物处于狂喜 / 极度悲伤 / 恐惧 / 愤怒 / 杀人后 / 求爱等"兵荒马乱"时刻时执行(/no-psychological-description): + +- [ ] 段落里没有"他感到…""她心想…""心中充满…"式直接心理陈述(判停:人物内心平静则跳过本清单,可直接写心理,但不超过段落 1/3) +- [ ] 至少写了 3 种身体/感官维度:动作 / 视觉 / 听觉 / 身体状态(姿势、呼吸、体温、肌肉) +- [ ] 给角色一个"不由自主"的小动作:反复检查、走来走去、突然停下、机械性重复 +- [ ] 读者只凭动作就能感到情绪,不需要一句解释 +- [ ] 没有"先用心理陈述兜底、再补一个动作"的点缀式写法——动作是替代,不是装饰 + +## 三、写作中:超现实内容(想象锚点) + +写奇幻 / 梦境 / 超现实情节时逐条核对(/imagination-to-fact): + +- [ ] 列出了全部超现实设定(人变甲虫、人飞上天、死人说话等) +- [ ] 每个设定配了至少一个现实锚点:读者经验里有的物品 / 力量 / 动作 / 细节(床单之于飞天,闹钟与迟到之于变甲虫) +- [ ] 超现实部分周围是写实笔法:人物反应日常(惊讶、困惑、继续生活),不戏剧化 +- [ ] 没有解释"为什么会这样"(越解释越假) +- [ ] 全书内在一致:不符合现实逻辑可以,但必须符合作品自己的逻辑 + +## 四、写作中:冰山(一个动作扛多层信息) + +写关键场次、对话、短篇结尾时执行(/bifeiyu-iceberg): + +- [ ] 写前列了水下清单:人物心理状态 / 环境氛围 / 关系张力 / 主题暗示 / 情感重量 +- [ ] 选了一个具体动作 / 对话 / 物件承载,附着 3 个以上元素算优秀,只扛 1 个算浪费 +- [ ] 冰山比在 1/8 到 1/3 之间(水面字数 / 总字数):太多没留白,太少读不懂 +- [ ] 做过删字测试:"我觉得气氛很紧张""他很害怕"式形容词句已删,换成一个具体动作 +- [ ] 读者读完想的是"原来如此",不是"他告诉我" + +## 五、写作中:反逻辑与飞白 + +写秘密、暗流、复杂人物关系时执行(/bifeiyu-anti-logic): + +- [ ] 列过"按逻辑谁该有什么反应"的清单,标出实际没写 / 反着写的地方 +- [ ] 每一处"没写"都问过归因:没想到 → 补上;刻意 → 深挖;藏 → 设计飞白 +- [ ] 反常反应有明确指向:不该反应的人反应 → 揭示隐藏关系;该反应的人无反应 → 揭示心理距离;该反应的人反常反应 → 揭示深藏性格 +- [ ] 飞白处写了周围人的反应,没写主角的心思,读者能从周围推导主角 +- [ ] 每处空白都留了暗示——读者事后能反推"为什么没写";推不出就加暗示或删掉 +- [ ] 密度可控:短篇 1-2 处,中篇 3-5 处,长篇每章约 1 处 +- [ ] 确认不是动作戏或悬疑推理——这两类要逻辑严密,不用反逻辑 +- [ ] 没有滥用巧合:反逻辑是结构选择,巧合是偷懒 + +## 六、写作中:视角知识边界 + +写多视角 / 第一人称 / 第三人称限制视角时执行(/curse-of-knowledge): + +- [ ] 每个视角段落动笔前写过:这个人物此刻不该知道什么 +- [ ] 该段对话与内心独白没有越界(没说、没想视角外的信息;反例:侦探在凶手 POV 段说"凶手用的是 .38 口径") +- [ ] 第一人称没写"我"不在场的事(除非后来被告知) +- [ ] 第三人称限制的内心独白只来自该视角人物 +- [ ] 每个角色的话只基于他此刻知道的信息 +- [ ] 信息差是设计出来服务张力的(戏剧反讽或悬念),不是无意漏出去的 +- [ ] 全知叙述者没有用太多(用太多读者觉得"在作弊") + +## 七、修订阶段:读者读不懂的诊断 + +收到"读不懂 / 跟不上 / 术语太多"反馈,或自己怀疑跳步时执行(/curse-of-knowledge): + +- [ ] 能列出"读者读这段前必须已经知道的 3 个前置信息";列不出 = 抽象层级太高,列出但没显式给出 = 跳步 +- [ ] 全文标过"显然 / obviously / 众所周知 / 不用说 / 大家都知道 / 不言而喻"——每一处问"对哪个读者层级显然?","对我显然"就改写 +- [ ] 术语 / 缩写 / 行业黑话列过清单:入门读者能解释的留下,不能的第一次出现附简短解释,有更简单同义词就替代 +- [ ] 组块化抽象词(决策 / 杠杆 / 赋能 / 做这个分析)已拆回具体动作(谁 / 做了什么 / 在什么场景);拆不开的删 +- [ ] "我从未"双重否定自检:至少找到 1 个"自己写的、自己却要查"的词 +- [ ] close the loop:找至少 1 个目标读者代表读完**复述一遍**(不是问"清不清楚") +- [ ] 隔夜重读过一遍:第二天"显然"不再显然的地方已暴露 + +## 八、修订阶段:画面自检(show 验收) + +- [ ] 通读时逐段问"读者读完脑中应该出现什么画面",答不上的段落还在 tell(/show-dont-tell) +- [ ] "如果只能记一句"测试:目标读者读完能说出一个具体场景,而不是"它很有效"(/show-dont-tell) +- [ ] 抽象/具象比例反映内容需要:不是全 show(啰嗦)也不是全 tell(抽象)(/show-dont-tell) + +## 九、完稿验收:留白核对 + +- [ ] 留白处都有内容:水下至少有一个暗示痕迹,没有"直接不写"的偷懒省略(/bifeiyu-iceberg;/bifeiyu-anti-logic) +- [ ] 没有满篇冰山:关键场次用冰山,叙述段保持正常密度(/bifeiyu-iceberg) +- [ ] 飞白检验自问过:"我从没写到主角的心思,但读者读出来了吗?"(/bifeiyu-anti-logic) +- [ ] 全篇没有"形容词式心理描写"残留(我觉得气氛很紧张 / 他很害怕)(/bifeiyu-iceberg) + +## 十、快速排错表 + +| 症状 | 诊断 | 处方 | 来源 | +|------|------|------|------| +| 读者说"没有画面感 / 太抽象" | 抽象标签堆砌,还在 tell | 按第一节扫描替换:标签 → 动作 / 数字 / 场景 / 对话 | /show-dont-tell | +| 情绪场景苍白、像心理学教科书 | 用了直接心理分析 | 关掉心理通道,按第二节写身体感官 | /no-psychological-description | +| 读者说"写得假 / 出戏" | 超现实内容没有现实锚点,是虚幻不是想象 | 按第三节补锚点,删解释,周围写实 | /imagination-to-fact | +| 对话动作平淡、没第二层 | 水面没有扛水下 | 按第四节列水下清单,换一个动作承载 | /bifeiyu-iceberg | +| 读者困惑、读不懂留白 | 水下无迹可循,或把留白做成省略 | 加暗示痕迹;关键场次才用冰山 | /bifeiyu-iceberg;/bifeiyu-anti-logic | +| 秘密没藏住 / 反逻辑没人读出来 | 空白处没留暗示,或反逻辑点太多 | 每处空白留可反推痕迹;短篇压到 2 处以内 | /bifeiyu-anti-logic | +| 视角穿帮(人物知道了不该知道的) | POV 越界 | 按第六节逐句检查,信息改由转述 / 事后得知进入 | /curse-of-knowledge | +| 读者说"读不懂 / 跳步 / 术语多" | 知识诅咒发作 | 按第七节诊断:前置信息、"显然"扫描、close the loop、隔夜重读 | /curse-of-knowledge | +| 心理描写绕来绕去,该冲过去的地方绕开 | 90% 作家的通病:绕开极端场景 | 用身体动作冲过去,不绕 | /no-psychological-description | diff --git a/framework/catalog/pi/skills/show-and-omission/references/show-vs-tell.md b/framework/catalog/pi/skills/show-and-omission/references/show-vs-tell.md new file mode 100644 index 0000000..dab7fad --- /dev/null +++ b/framework/catalog/pi/skills/show-and-omission/references/show-vs-tell.md @@ -0,0 +1,201 @@ +# 把抽象标签换成具体场景:展示而非告知 + +> 本文件管"展示"的总原则和抽象标签的替换方法。极端情绪场景的身体呈现见 [extreme-emotion-body.md](extreme-emotion-body.md);一个动作扛多层信息见 [iceberg.md](iceberg.md);读者读不懂的诊断见 [reader-gap-diagnosis.md](reader-gap-diagnosis.md)。 + +## 原文引文 + +> Classic style minimizes abstractions, which cannot be seen with the naked eye. It says: even when we write about abstract topics, we should treat them as if they were objects and forces that would be recognizable to anyone standing in a position to see them. +> +> — Steven Pinker, *The Sense of Style*, Chapter 2 + +(/show-dont-tell) + +古典风格把抽象最小化——抽象是肉眼看不见的东西。它说:即使我们写抽象主题,也要把它们当作站在某个位置上就能看到的事物和力量来处理。(/show-dont-tell,白话转述) + +## 为什么 show 强于 tell:认知基础 + +"Show, don't tell" 在 Pinker 这里有具体的认知科学基础,不只是文学修辞(/show-dont-tell): + +- 读者处理"具体动作"时,大脑的**镜像神经元(mirror neurons)**激活,部分"运行"那个动作(感受到动作)。 +- 读者处理"抽象标签"(高效 / 重要 / 优化)时,只在脑的语义层处理,没有感官激活。 +- 结果:读者被"告知"后是"理解",被"展示"后是"体验"。 + +## 方法核心:Pinker 四步法(从抽象到具象) + +1. **识别抽象标签**:凡是用 "effective" / "successful" / "important" / "optimal" / "professional" / "innovative" 这种形容词的,都是 tell。 +2. **问"具体是什么"**:"effective" = 什么具体动作 / 数字 / 场景让作者觉得 effective?答:"在 X 时间内完成了 Y,没有 Z 错误"——这就是 show。 +3. **替换为具象**:抽象形容词 → 数字 / 动作 / 场景 / 对话。 +4. **"读者能想象吗"自检**:通读,问"读者读完脑中应该出现什么画面"。如果没有,还在 tell。 + +(/show-dont-tell) + +## 对照例:Tell 与 Show + +- Tell: "The presentation was effective."(一个抽象标签) +- Show: "The CEO took notes, asked three follow-up questions, and stayed for twenty minutes after the talk ended."(三个具体动作,读者能想象) + +- Tell: "The team performed well."(抽象) +- Show: "In three months, the team reduced the bug count from 47 to 4, and shipped on schedule."(数字 + 动作) + +(/show-dont-tell) + +## Pinker 反对的"过度抽象"模式 + +这些名词化短语都属于 tell(也是 zombie noun,僵尸名词): + +- "做出一个决定" → 决定 +- "进行一个调查" → 调查 +- "提供解决方案" → 解决 + +(/show-dont-tell) + +## Pinker 自己的 show 范本 + +- **Dawkins**:"We are going to die, and that makes us the lucky ones. Most people are never going to die because they are never going to be born."(用"死"的具体状态,不是"存在"的抽象讨论) +- **Greene**:"invisible fog uniformly spread through space"(用"雾"让读者想象暗能量) +- **Pinker 的兔错觉重写**:"受试者闭眼伸出手臂,实验者依次轻敲手腕、手肘、肩,受试者感觉像一连串轻敲沿手臂跑上去,像兔子跳一样。"(用一连串具体动作) + +(/show-dont-tell) + +## 书中案例 + +### 案例 1:兔错觉的"告知 vs 展示"重写 + +- **问题**:一个学术期刊摘要,用 "stimulus" / "poststimulus event" / "rabbit illusion" 描述一个简单的知觉实验——Pinker 自己(知觉领域 30+ 年)都读不懂。 +- **方法论的使用**:Pinker 把这段重写为"具体动作"——闭眼、伸手臂、被敲手腕、敲手肘、敲肩、有兔子跳的感觉。 +- **结论**:学术摘要用"刺激"标签描述实验,同行读不懂;用"动作"描述,一般读者能懂。 +- **结果**:这是 Pinker 论证 "show, don't tell" 在科学写作中最有说服力的案例。 + +(/show-dont-tell) + +### 案例 2:Brian Greene 的暗能量说明 + +- **问题**:"暗能量"是高度抽象的物理概念。 +- **方法论的使用**:Greene 把暗能量比喻为"均匀分布在空间中的看不见的雾"——读者能想象"有东西在推"。 +- **结论**:即使是数学化的物理,也能用具象(雾)表达,不丢精度。 +- **结果**:Greene 的科普成为畅销书,是科学写作的范本之一。 + +(/show-dont-tell) + +### 案例 3:Goldstein 的哲学问题 + +- **问题**:"个体同一性"是抽象的哲学问题。 +- **方法论的使用**:Goldstein 把问题用"她"这个具体人设承载:"是什么让她是她,而不是别人"。 +- **结论**:抽象问题用具象人设,读者能跟着想。 +- **结果**:Pinker 引此为例,说"哲学散文很少能写得这样清楚"。 + +(/show-dont-tell) + +## 触发场景与语言信号 + +用户会在什么情境下需要这个方法(/show-dont-tell): + +1. 用户写完一段评估 / 描述 / 总结,抽象标签堆满,想要具象化。 +2. 用户被反馈"我读不出你到底在说什么" / "没有具体例子"——需要 show。 +3. 用户写 PPT 旁白 / 演讲稿,担心太抽象,想要可视觉化的描述。 +4. 用户写培训材料 / 教程,想要让学员"看到"怎么操作——需要动作化。 +5. 用户改一篇文章,想把"形容词堆砌"换成"具体场景"。 + +语言信号(用户的话里出现这些就应激活): + +- "没有画面感" / "太抽象" / "读者脑子里没有画面" +- "形容词太多了" / "像宣传文案" / "太空" / "太泛" +- "show don't tell" / "too abstract" / "feels generic" / "I can't picture it" +- "没有具体例子" / "no concrete detail" / "how do I make this vivid" +- "什么是'有效'" / "怎么把'重要'写具体" + +## 可执行步骤 + +当这个方法被激活后,按以下步骤执行(各步完成标准来自源单元)(/show-dont-tell): + +1. **全文搜抽象标签**:"effective / successful / important / optimal / professional / innovative / high-quality / meaningful / efficient" 等。 + - 完成标准:至少识别 5 处抽象标签,标记在文档中。 +2. **每个标签问"具体是什么"**:这个标签背后,作者看到的"具体动作 / 数字 / 场景"是什么? + - "effective" = 多少时间内完成了什么,没有出什么错? + - "successful" = 实现了哪个具体的指标,谁的反应? + - "important" = 为什么?对谁?缺了会怎样? + - "professional" = 哪个具体行为让作者觉得 professional? + - 完成标准:每个标签都有"具象版本"。 +3. **替换为具象**:用数字 / 动作 / 场景 / 对话 / 具体感官细节替代抽象标签。 + - 完成标准:改写率 > 80%。 +4. **"读者能想象吗"自检**:通读,问"读者读完脑中应该出现什么画面"。如果没有,还在 tell。 + - 完成标准:每一段都能回答"读者应该看到什么"。 +5. **"如果只能记一句"测试**:让一个目标读者读完后,问"你脑中记的最清晰的画面是什么?"。如果他说的是抽象概念("它很有效"),还在 tell;如果他说的是具体场景(那个人做了什么),是 show。 + - 完成标准:目标读者能描述具体场景,而非"这文章讲的是有效"。 +6. **平衡**:不要为了 show 而 show——一些必要的抽象(定义 / 分类 / 总结)还是需要的。判断标准:这段是否依赖读者脑中"看到"才能理解?如果是,show;如果只是传递信息(电话号码 / 日期),tell 没问题。 + - 完成标准:文章的抽象/具象比例大致反映内容需要,不是全 show(显得啰嗦)或全 tell(显得抽象)。 + +## 小说落地:怎么用 + +Show, don't tell 是小说创作的核心理念(Pinker 借的),在小说里比非虚构更重要、更深(/show-dont-tell): + +- **角色情绪**:"她感到愤怒" → 她摔门、握拳、用一种克制到近乎陌生的声音说话。 +- **场景氛围**:"阴森的森林" → 树枝像骨指戳向天空,脚下踩到软绵绵的东西。 +- **故事节奏**:一连串动作 vs 抽象总结,用动作推进。 +- **对话**:"我很高兴" → 角色说话的方式(语气、动作、表情)+ 之后发生的事。 +- **角色塑造**:不用"她很勇敢",让她在危险时做只有勇敢的人会做的事。 + +**镜像神经元视角**(Pinker 给了认知科学基础): + +- 一串具体动作激活镜像神经元,读者"运行"那个场景。 +- 抽象标签(高效 / 重要 / 创新)在小说里**完全无效**——读者读小说不是来"理解标签"的。 +- 体感细节(湿冷 / 沙哑 / 钻痛)比情绪标签(悲伤 / 恐惧)强 10 倍。 + +**同一方法的多书视角**:余华的无心理描写法把这条原则推到极端情绪场景——不写心理分析,写身体和感官(见 [extreme-emotion-body.md](extreme-emotion-body.md));毕飞宇的冰山法则从信息密度一端说同一件事——别告诉读者"紧张",用一个错误动作让读者自己紧张(见 [iceberg.md](iceberg.md))。 + +## 小说专属边界 + +以下情况不该机械 show 化(/show-dont-tell): + +- 文学修辞故意反 show(意识流、抽象诗化叙述如《了不起的盖茨比》开头)——是合法表达。 +- 第一人称 POV 主观体验("我感到一阵晕眩")——主观体验是合法的,不该全部 show 化。 +- 全知叙述者的"评估"(在哈代、托尔斯泰笔下)——是叙述特权,不该一律 show 化。 + +## 不要在这些情况使用 + +- **诗歌 / 文学散文**:那里 show-don't-tell 有更复杂的传统,包含主观体验和意识流,不是 Pinker 的"客观呈现"。 +- **法律 / 学术的高度抽象领域**:一些概念必须保持抽象(正义 / 自由 / 效率)才能讨论,show 反而失精度。 +- **新闻报道的"概要"段落**:新闻导语和概要需要快速传递信息,show 不适合,应该在主体里 show。 +- **作者的"想要模糊"**:有时作者就是想让读者感觉"模糊"(营造氛围 / 制造悬念 / 写文学),show 反而破坏意图。 +- **元评论 / 哲学讨论(含神学)**:用户写的是抽象观念为主(哲学 / 神学),那里"具象"不是目标;"存在" / "意识"这类主题本身就是抽象,强行具象反而失深度。 + +(/show-dont-tell) + +## 失败模式(作者在书中警告) + +- **"形容词 = 烂"的简化**:形容词本身不是问题,"空的形容词"才是。"X 是红色"(具体)不是 tell,"X 是漂亮"(空)是 tell。 +- **"show 永远好"的过度**:一些场景需要抽象(总结 / 定义),全 show 反而冗长。 +- **"具体 = 数字"的简化**:数字是 show 的一种,但动作、场景、对话、感官细节都是 show,不只是数字。 +- **"作者自己看到的就是 show"**:作者脑子里的"画面"是经过认知诅咒的,可能不共享给读者。要 close the loop,让目标读者说"我看到了什么"。 + +(/show-dont-tell) + +## 盲点与时代局限 + +- 写于 2014,当时还没有 LLM 写作。今天 LLM 输出的"AI 腔"大量是 tell——空泛形容词 + 抽象副词 + 没有具体动作,show-don't-tell 是直接对症。 +- Pinker 主要讲英文。中文的 show 也有其特点——中文常用四字成语(但很多是 zombie cliché),也有具象的传统(白描)。show 在中文里更需小心:不是所有"具体"都好,有些"具体"是 cliché(如"灯红酒绿"),需要 show 但非 cliché。 +- 没有处理"读者不想看"的情况:即便 show 完美,如果读者根本不想读这个主题,任何 show 都救不了。 + +(/show-dont-tell) + +## 容易混淆的邻近方法 + +- **"多用动词少用形容词"的笼统建议**:这是 show 的简化版,但 show 不只是词性选择——动作、场景、对话、感官细节都算,不仅限于动词。 +- **"数据可视化"的设计建议**:那是 show 的视觉版本,适用于数据展示,不适用于纯文字写作。 +- **"叙事医学 / 叙事心理学"的"讲故事"建议**:那是 show 的一种(故事化),但 show 不需要完整故事,一个动作 / 一句对话也是 show。 + +(/show-dont-tell) + +## 与相邻方法的区分 + +- 与知识诅咒的区别:curse-of-knowledge 是"作者以为读者懂"的认知机制,show-don't-tell 是"用具象绕过诅咒"的具体方法。**诅咒是病灶,show 是治疗。**(/show-dont-tell) + +## 中文适配 + +Pinker 以英文立论,中文落地时注意(标注"中文适配"): + +1. **中文的"具体"不等于四字成语**:"灯红酒绿""心如刀绞"是现成套话(zombie cliché),读者脑中不会生成画面,读到的是别人的旧句子;要给出这一篇独有的细节。这一条直接来自源单元的盲点小节("有些'具体'是 cliché(如'灯红酒绿')"),中文白描传统(寥寥几笔写实物实态)是 show 的本土资源。 +2. **中文抽象标签的搜法**:英文清单(effective/important 等)在中文里对应"很 / 十分 / 充满 + 情绪词"(很悲伤、十分愤怒、充满矛盾)和评价式形容词(勇敢、专业、重要、有效、高质量、有意义)。扫描时按中文的这些形态搜。 +3. **中文名词化 tell**:"做出一个决定 / 进行一个调查 / 提供解决方案"这类动词名词化短语,在中文公文腔里尤其密集,Pinker 的 zombie noun 清单在中文里直接可用。 + +(中文适配;基础内容来自/show-dont-tell) diff --git a/framework/catalog/pi/skills/story-ending/SKILL.md b/framework/catalog/pi/skills/story-ending/SKILL.md new file mode 100644 index 0000000..380d629 --- /dev/null +++ b/framework/catalog/pi/skills/story-ending/SKILL.md @@ -0,0 +1,67 @@ +--- +name: story-ending +description: | + 小说收尾阶段激活。当用户问"结尾怎么写"、担心烂尾、觉得最后几章拖尾或结尾无力、 + 在开放式与闭合式结局之间拿不定主意、想从终局倒推前文、系列小说要协调本集结局与系列结局、 + 或需要判断读者读完是"被关起来"还是"被打开"时使用。 + 关键 trigger:"怎么结尾" / "收尾" / "烂尾" / "拖尾" / "结尾无力" / "结尾策略" / "结局设计" / + "倒推" / "从最后一章写起" / "chain of execution" / "完成还是打开" / "收束还是扩展" / + "戛然而止" / "意犹未尽" / "被关起来" / "被打开" / "ending"。 + 不适用于:以"无结尾"本身为表达的开放实验文学与反叙事解构作品、短抒情诗与散文、 + 刻意反高潮的平铺直叙、必须闭环的事务性场景(合同签署、手术完成、机器启动) + 与必须收束的紧急信息("立即撤离"类)。 + 与 foreshadow-payoff 交接:收束前未兑伏笔债归 foreshadow-payoff;终局姿态与倒推路径归本 Skill。 + 与 story-structure 交接:全书里程碑/四箱/中段结构成因归 story-structure;只谈收尾姿态用本 Skill。 + 与 narrative-momentum 交接:结尾前金币/势/弃读归后者。 +--- + +# story-ending 结尾设计 + +结尾要回答两个问题:终局在哪里,终局给读者什么姿态。前者是工程——先定结尾再倒推路径;后者是姿态——把读者关进一个紧凑的整体,还是放他带着更大的世界离开。 + +## 方法索引 + +按创作动作组织。方法细节、操作步骤、案例全文、原文摘录都在 references 里,本文件只做指针。 + +- **写下终局画面**:动笔前先定最后一幕的核心画面或最后一句,具体到地点、时间、动作、人物状态,不用主题陈述代替 → references/fix-final-scene.md +- **倒推债务清单**:从终局倒推每个终局元素该在前文哪里埋伏或建立,逐条列出;无法前置就改终局,不要硬写 → references/fix-final-scene.md +- **选收尾策略**:从十种收尾策略(闭合圆环、回扣开头、时间框架、空间框架、兑现、尾声、问题-解法、适配引语、看向未来、动员读者)里选,短篇 1 种、长篇 2-3 种嵌套,叠加超过 3 种显得刻意 → references/ending-strategies.md +- **层层嵌套结尾**:全书末章、章末段、段末句、句末词都要回响终局,每章末有一个小结尾与终局形成镜像、伏笔或主题回响 → references/execution-chain.md +- **找自然止点砍拖尾**:手盖住最后一段问"如果在这里结束呢?",逐段上移,直到再少一段就觉得缺 → references/natural-stop.md +- **选收尾姿态**:完成是把所有线索收束、把读者关起来;扩展是留下未答的问题、放读者带着更大的世界离开;两种姿态都合法,但小说承载的人性内容多,应优先扩展 → references/expansion-completion.md +- **诊断姿态并补代价**:判断读者读完是"被关进紧凑的整体"还是"被打开一个比书更大的世界";选扩展就加一个仪式性收束防止被当成没写完,选完成就留一个带节奏的开口防止把读者关死 → references/expansion-completion.md +- **边界与常见误区**:不适用场景、失败模式与常见误区、作者的盲点与时代局限、易混淆方法与相邻 skill 区分 → references/pitfalls-and-boundaries.md + +伏笔的埋设与回收归 `foreshadow-payoff`,章间钩子与中段奖励归 `narrative-momentum`,整体结构与开篇归 `story-structure`,整体形式诊断归 `novel-diagnosis`;本 skill 只管结尾本身。 + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|---------| +| references/fix-final-scene.md | 先有结尾再写路径的总纪律、终局画面要求与判停问法、倒推债务清单、Rowling 与 Hemingway 案例、英文原文摘录全量 | +| references/ending-strategies.md | 十种收尾策略及选择标准、开放式结局"有意 vs 无意"判断、兑现陈词滥调误区 | +| references/execution-chain.md | Chain of Execution 嵌套结尾、《了不起的盖茨比》绿光案例、逐章检验、系列双层结尾与网文分卷收尾(中文适配) | +| references/natural-stop.md | Rachmaninoff 拖尾警告、手盖法找自然止点、拖尾的信号/机制/预警 | +| references/expansion-completion.md | 完成 vs 扩展两种姿态、征兆与检验公式、代价与风险、《战争与和平》/贝多芬《第五交响曲》/《使节》案例全文、原文摘录全量、Clark 与福斯特的规则冲突与调和 | +| references/pitfalls-and-boundaries.md | 不适用边界、失败模式与常见误区索引、作者盲点、激活场景与语言信号、易混淆方法与相邻 skill 区分 | +| references/_coverage.md | 覆盖对照表(唯一追溯文件):全部方法点、案例、引文的来源落点 | + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 红线 + +- 只给当前创作阶段的建议,不越权改设定主权、不绕过检测链、不复制粘贴其它 Skill 的 owner 定义。 +- 无用户明确授权不得替用户定稿或提交 Git。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/pi/skills/story-ending/references/_coverage.md b/framework/catalog/pi/skills/story-ending/references/_coverage.md new file mode 100644 index 0000000..a933264 --- /dev/null +++ b/framework/catalog/pi/skills/story-ending/references/_coverage.md @@ -0,0 +1,16 @@ +# story-ending 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| aspects-of-the-novel/expansion-vs-completion | references/expansion-completion.md | +| aspects-of-the-novel/expansion-vs-completion | references/execution-chain.md | +| aspects-of-the-novel/expansion-vs-completion | references/ending-strategies.md | +| aspects-of-the-novel/expansion-vs-completion | references/natural-stop.md | +| aspects-of-the-novel/expansion-vs-completion | references/pitfalls-and-boundaries.md | +| writing-tools-clark/write-toward-ending | references/fix-final-scene.md | +| writing-tools-clark/write-toward-ending | references/execution-chain.md | +| writing-tools-clark/write-toward-ending | references/ending-strategies.md | +| writing-tools-clark/write-toward-ending | references/natural-stop.md | +| writing-tools-clark/write-toward-ending | references/pitfalls-and-boundaries.md | diff --git a/framework/catalog/pi/skills/story-ending/references/ending-strategies.md b/framework/catalog/pi/skills/story-ending/references/ending-strategies.md new file mode 100644 index 0000000..d490339 --- /dev/null +++ b/framework/catalog/pi/skills/story-ending/references/ending-strategies.md @@ -0,0 +1,41 @@ +# 十种收尾策略与选择标准 + +## 十种收尾策略 + +Clark 给出 10 种收尾策略,各条括注为落地释义(中文适配): + +1. **闭合圆环**——结尾回到开头的场景、意象或句子,首尾成环(落地释义) +2. **tieback(回扣开头)**——收束时系回开篇,与开头形成呼应(落地释义) +3. **时间框架**——用一个时间跨度收束(从何时到何时)(落地释义) +4. **空间框架**——用一个地点 / 空间收束(落地释义) +5. **兑现**——兑现前文的承诺,结算伏笔债务(落地释义;兑现的登记端归 `foreshadow-payoff`) +6. **尾声**——主结尾之后加一段尾声,交代后事(落地释义) +7. **问题-解法**——以"提出问题—解决问题"的结构收束(落地释义) +8. **适配引语**——用一句贴切的引语收束(落地释义) +9. **看向未来**——结尾指向人物或世界在故事之后的去向(落地释义;开放式结局常落在这里) +10. **动员读者**——把行动交给读者,邀请读者去做点什么(落地释义) + +## 选择标准(判断标准) + +- 选定 1-2 种主策略:**短篇 1 种,长篇 2-3 种嵌套**。 +- **判停条件:不要"叠加"超过 3 种,会显得刻意。** + +## 开放式结局:是策略之一,不是"没结尾" + +- 开放式结局是 10 种策略之一(落在"看向未来 / 留白"一带),不是"无结尾"。 +- **关键判断:这个"开放"是作者有意的,还是无意的?** 有意的开放是设计,无意的开放是没写完。 +- **开放式结局也要有"锚点"**:即使是开放式结局,也应有 1 个"锚点"(最后一句 / 最后一个动作)给读者抓住。开放的是答案,不是连抓手也撤掉。 +- 福斯特的补充视角:开放式结局是"叙事结构的特征",而"扩展"是"作者对读者意识的姿态"——前者可以是后者,但不一定是。两者区分详见 references/expansion-completion.md 与 references/pitfalls-and-boundaries.md。 +- 把"没写完"说成"扩展"是给写作失败辩护,是误区,见 references/pitfalls-and-boundaries.md。 + +## 误区:兑现陈词滥调(失败模式全量) + +- **失败模式**:用"他们从此幸福地生活在一起"等套话结尾。 +- **信号**:读者觉得"又是这个"。 +- **机制**:作者没找到属于自己的"独特终局"。 +- **预警**:10 种策略选错,或未本地化——回到本文件重选策略。 + +## 中文落地 + +- 十种策略名为中文译名,可直接用于中文网文、类型小说与严肃文学的收尾设计;选型标准(短篇 1 种、长篇嵌套、不超 3 种)不变。(中文适配) +- 中文网文"分卷收尾"在十种策略里没有现成对应,要单独设计,见 references/execution-chain.md 的中文适配条。 diff --git a/framework/catalog/pi/skills/story-ending/references/execution-chain.md b/framework/catalog/pi/skills/story-ending/references/execution-chain.md new file mode 100644 index 0000000..b461bf4 --- /dev/null +++ b/framework/catalog/pi/skills/story-ending/references/execution-chain.md @@ -0,0 +1,49 @@ +# 执行链:结尾是嵌套结构,不是单点(Chain of Execution) + +## 方法细节 + +结尾不是单点——是嵌套结构,四层逐级回响终局: + +```text +全书末章 → 章节末段 → 段末句 → 句子末词 +``` + +与终局锚定(references/fix-final-scene.md)合起来构成完整框架:先定终局是"锚",执行链是让锚的回声渗透到每一层收束位置。 + +## 案例(保留原文细节) + +### Fitzgerald《了不起的盖茨比》——绿光 + +- **问题**:长篇 160 页,如何让"主题"(美国梦的破灭)贯穿? +- **方法论的使用**:第 1 章末的"绿光"(盖茨比在码头上望向黛西家)和最后一章的"绿光"互为镜像——首章末预演终章。Gatsby 第 1 章末的"绿光"预演 160 页后的"绿光"。Chain of Execution 的金标准。 +- **结论**:结尾是嵌套结构——全书末 / 章末 / 段末 / 句末都应回响终局。 +- **结果**:成为"主题回响"+"嵌套结尾"的金案例。 + +## 逐章检验(可执行步骤) + +- **操作**:逐章检查章末——每章末有没有一个"小结尾",与终局形成镜像、伏笔或主题回响。 +- **完成标准**:每章末有 1 个"小结尾",与终局形成镜像 / 伏笔 / 主题回响。 + +## 失败模式:开头/结尾无关联(全量) + +- **失败模式**:开头和结尾是"两个不同的故事"。 +- **信号**:读者读完后回想开头,觉得"和结尾没关系"。 +- **机制**:作者没先定结尾,写到中段失去方向。 +- **预警**:Chain of Execution 检验失败——回到 references/fix-final-scene.md 重新锚定终局。 + +## 系列小说的双层结尾 + +系列小说的"本集结局"和"系列结局"要协调,典型用户情境是"系列小说不知道'本集结局'和'系列结局'怎么协调——担心读者失去耐心"。 + +用 Chain of Execution 的"双层结尾"处理:**本集结尾要预演系列结尾**(伏笔 / 镜像 / 主题回响),但**不能直接剧透**。 + +担心读者失去耐心的,本卷先结算本卷债务,系列终局只做回声。(中文适配) + +## 中文适配:网文分卷收尾 + +网文分卷收尾是 Chain of Execution 的变体:**本卷末先结算本卷债务,再给下一卷留钩子**。注意两条: + +- 留钩子属于章间悬念(归 `narrative-momentum`),**不能替代本卷终局的回响**; +- 十种收尾策略里没有"留钩子"的现成对应,要单独设计。 + +(中文适配;Clark 的盲点自查也承认:中国网文"留钩子"结尾和"开放式收尾"是 Clark 框架之外的形态。) diff --git a/framework/catalog/pi/skills/story-ending/references/expansion-completion.md b/framework/catalog/pi/skills/story-ending/references/expansion-completion.md new file mode 100644 index 0000000..f278a96 --- /dev/null +++ b/framework/catalog/pi/skills/story-ending/references/expansion-completion.md @@ -0,0 +1,107 @@ +# 收尾姿态二选一:完成 vs 扩展(Completion vs Expansion) + +## 方法定位 + +小说/艺术应追求的**审美姿态二选一**: + +- **完成(Completion)**:倾向于收束,把听众/读者"关"起来。戏剧、有界面的艺术可以采用。 +- **扩展(Expansion)**:倾向于打开,像交响曲终了时"那些编织起整部乐曲的音符和曲调都摆脱了束缚,它们在整体的节奏中找到了各自的自由"。**小说应追求后者。** + +## 原文摘录(全量) + +> "'扩展'。这是小说创作者必须牢牢抓住的概念。不是'完成', 而是'扩展'。不是'收束', 而是'打开'。当一曲交响乐终了, 我们会感觉那些编织起整部乐曲的音符和曲调都摆脱了束缚, 它们在整体的节奏中找到了各自的自由。" + +> "小说也能这样吗?《战争与和平》里难道不是已经有了些这样的意味?——我们的讲座从这部小说开始, 现在也该当以它作为结束。这样庞大浩繁的一部巨著。然而, 当我们沉浸其中, 难道不是有宏大的和弦在我们身后奏响吗?" + +> — E. M. 福斯特, 《小说面面观》第八讲 模式与节奏 + +## 方法细节 + +### 1. 承认两种姿态都合法 + +戏剧(拉辛的《贝蕾妮丝》)可以追求"完成"(美是舞台上的女皇);小说应追求"扩展"(因为小说承载了"人性的肥满内容")。 + +执行时的完成标准:明确说出"完成/扩展都合法,但小说应优先扩展,戏剧可以优先完成"。 + +### 2. 完成的征兆 + +- 作品结束,读者感到"被关在了一个紧凑的整体里" +- 所有问题都得到回答,所有线索都收束 +- 收尾"戛然而止"——婚姻/死亡等仪式性结尾 + +### 3. 扩展的征兆 + +- 作品结束,读者感到"被打开了一个比书更大的世界" +- 关键问题未回答,反而提出新问题 +- 收尾"意犹未尽"——托尔斯泰式的"宏大和弦在身后奏响" + +### 4. 检验公式 + +- 作品结束时,读者是感到"被关在了一个紧凑的整体里"(完成)还是"被打开了一个比书更大的世界"(扩展)? +- 注意:**扩展不等于"未完成"**(那是写作失败)。扩展是"故意打开,让你带着更大的世界离开"。 + +### 5. 扩展的代价与完成的风险 + +- **扩展的代价**:容易被读者误解为"没写完"。 +- **完成的风险**:容易让读者感到"被关起来",失去主动思考的空间。 + +### 关键认识 + +**扩展 ≠ 拖戏,完成 ≠ 烂尾。两者都需要写作功力。** 福斯特把"扩展"作为小说的标志:戏剧可以追求"完成",但小说家如果追求"完成"就阉割了小说的人性内容。 + +## 案例(全文保留) + +### 案例 1:托尔斯泰《战争与和平》——扩展的范本 + +- **问题**:《战争与和平》"庞大浩繁",战略战术的罗列都有,结束时它给人什么感觉? +- **方法论的使用**:福斯特诊断——"当我们沉浸其中, 难道不是有宏大的和弦在我们身后奏响吗? 当我们读完整个故事, 难道不是感觉其中的桩桩件件, 甚至包括战略战术的罗列, 都变成了比当初更加醒目、更加壮观的存在吗?" +- **结论**:这是"扩展"的范本——读完时,一切都"比当初更加醒目、更加壮观"。 +- **结果**:福斯特把《战争与和平》同时作为开篇和结尾——因为它是"扩展"的代表。 + +### 案例 2:贝多芬《第五交响曲》——音乐中"扩展"的对照 + +- **问题**:音乐中有"扩展"吗? +- **方法论的使用**:福斯特明示——"当管弦乐团完成演奏, 曲终弦静, 我们依旧能听到某种从未实实在在被奏响的东西。开场乐章、行板, 以及联合组成了第三部分的三声中部—谐谑曲—三声中部—终曲—三声中部—最后乐章, 一齐涌上人心头, 相互延展交汇, 成为一个统一的整体。这个统一整体, 这个全新的产物, 就是一部浑然一体的交响曲" +- **结论**:交响曲是"扩展"的范本——终了时,听众感到的统一整体"从未实实在在被奏响过",是"涌上心头"的。 +- **结果**:借此福斯特把小说的"扩展"对照音乐,说明这是艺术的高级形态。 + +### 案例 3:亨利·詹姆斯《使节》——模式 vs 扩展的反例 + +- **问题**:詹姆斯追求"完整闭环"(沙漏模式),这是"完成"还是"扩展"? +- **方法论的使用**:福斯特诊断——詹姆斯的"美"是"完成型"的,阉割了人物/情节/幻想/预言,让人物像阿肯纳顿时期的埃及艺术,"巨大的头颅, 细小的下肢, 但依然充满魅力"。 +- **结论**:沙漏模式 = 完成的极致,但"美如期而至, 只是模样太霸道了些"——小说不需要这种完成。 +- **结果**:借此福斯特说明,"完成"是合法的审美选择,但小说家应警惕它阉割人性的风险。 + +## 操作步骤(可执行) + +1. **承认两种姿态都合法** + - 完成标准:明确说出"完成/扩展都合法,但小说应优先扩展,戏剧可以优先完成"。 +2. **诊断当前作品的姿态** + - 完成标准:评估"它结束时,读者/听众感到被关起来还是被打开"。 + - 给出具体征兆:"X 在 Y 段落戛然而止(完成)/ X 在 Z 段落提出新问题(扩展)"。 +3. **选择姿态** + - 完成标准:明确说"我选完成" / "我选扩展",并说明理由。 + - 理由模板:"因为 X 是 [小说/戏剧/产品/活动],所以 [扩展/完成] 更合适"。 +4. **设计具体结尾** + - 完成标准:至少 1 条具体修改(如"在结尾段加入一个未回答的问题,让读者带走"或"加入一个仪式性收束,让读者感到完成")。 + - **不要空话(如"留下想象空间")——给可操作修改。** +5. **检查"完成"的潜在风险 / "扩展"的潜在代价** + - 完成标准:明确说"完成的风险是 [阉割人性/失去主动思考] / 扩展的代价是 [被误解为没写完]"。 + - 设计对策:对完成,加 1 个"小乐句"式节奏;对扩展,加 1 个"仪式性收束"。 + +### 完成与扩展可以组合 + +"完成 + 扩展"不矛盾:仪式感结尾(完成)之后加 1 个"小乐句"式开放元素(扩展),读者既得到闭环又带着余味离开。 + +## Clark 与福斯特的规则冲突与调和 + +Clark 的十种收尾策略里有多种"完成型"收束(闭合圆环、tieback、兑现、问题-解法,见 references/ending-strategies.md),福斯特则明确警告小说追求"完成"会阉割人性。两书规则都保留,冲突按以下方式调和: + +- Clark 的闭合策略是**可用工具**,用于结算作品自身的债务(线索回收、承诺兑现); +- 福斯特的警告是**用后的姿态检查**:结算完债务,还要看读者是被关死还是被打开; +- 调和做法即福斯特第 5 步的对策——完成式收尾要加 1 个"小乐句"式节奏开口,别让读者关在里头。 + +## 中文落地 + +- 福斯特自认的盲点之一是"西方文学中心的视角——东方叙事的'留白'传统(中国画、禅宗)与'扩展'有相似性,但未充分讨论"。中文写作正好接得上这个传统:留白、留余味、"言有尽而意无穷"是中文读者熟悉的审美,扩展式结尾在中文语境里不容易被当成没写完。 +- **(中文适配)** 但网文连载环境里,长期不闭环会消耗读者耐心:扩展要建立在"本卷债务已结算"的基础上(见 references/execution-chain.md 的分卷收尾条),打开的是世界,不是欠条。 diff --git a/framework/catalog/pi/skills/story-ending/references/fix-final-scene.md b/framework/catalog/pi/skills/story-ending/references/fix-final-scene.md new file mode 100644 index 0000000..11e386c --- /dev/null +++ b/framework/catalog/pi/skills/story-ending/references/fix-final-scene.md @@ -0,0 +1,59 @@ +# 先定终局,再写路径 + +## 方法定位 + +Clark 给长篇/中篇写作的核心纪律:**先有结尾,再写路径**。不需要完整大纲,但需要"最后一幕的核心画面 / 最后一句 / 最后一个字"。 + +这是"嵌套结构 + 倒推"复合框架的地基: + +- **单层**:先定终局(本文件) +- **多层**:终局 / 章末 / 段末 / 句末形成回声网络(→ references/execution-chain.md) +- **反推**:从终局反推全书债务(本文件"倒推债务清单") + +## 原文摘录(全量) + +> I did not write from an outline, or even from much of a plan, but I knew that in the final chapter +> the good guy, who is afraid of heights and lightning, would be fighting the bad guy at midnight, +> atop a giant bridge, in a hurricane. In other words, I didn't know the stopping points along the +> way, but I wrote with an ending in mind. +> +> — Roy Peter Clark, *Writing Tools* (Tool 39) + +中文译文(译文为中文落地而附,非原书文字):我没有按大纲写作,甚至没什么像样的计划,但我知道在最后一章里,一个恐高、怕闪电的好人,会在午夜、飓风之中、一座大桥的顶端,和坏人搏斗。换句话说,我不知道沿途的停靠站在哪,但我是心里装着结尾往前写的。 + +## 方法细节 + +### 终局画面先行 + +动笔前用一两句话写下"最后一幕的核心画面"或"最后一句"。 + +- **完成标准**:画面是"具体的"——地点、时间、动作、人物状态都清楚,不是"主题陈述"。 +- **判停条件**:若用户写不出终局画面,改问两个问题——"故事最后一个画面应该是什么情绪?" / "读者合上书时,应该看到什么?" + +注意顺序:终局画面先于路径存在,但**不要求**完整大纲。Clark 本人写书时"不知道沿途的停靠站",只知道终局(见上引原文)。 + +### 倒推债务清单 + +终局定下后,从终局倒推"必须在前文埋伏 / 建立"的元素清单。 + +- **操作**:每个终局元素(人、物、场景、信息)都要回答——它必须在前文哪里埋伏或建立?逐条列出。 +- **完成标准**:每条"终局元素"都有对应的"前文位置"或"前文创建任务"。 +- **判停条件**:若终局元素与前文无关,加契诃夫之枪(伏笔登记与兑现归 `foreshadow-payoff`);若无法前置,**改终局**,不要硬写。 + +## 案例(保留原文细节) + +### 案例 1:J. K. Rowling 从最后一章写起 + +- **问题**:写 7 卷长篇,如何避免中段塌陷、保证"终局连贯"? +- **方法论的使用**:Rowling 承认她从最后一章写起——先知道"哈利与伏地魔的最终对峙"是什么样的,再反推前 6 卷如何铺垫。J. K. Rowling《哈利·波特》第一个字写的就是最后一章。 +- **结论**:先定结尾比先定开头对长篇小说结构更重要。 +- **结果**:成为"先定结尾倒推动笔"工作流的核心论据。 + +### 案例 2:Hemingway《老人与海》的最后一句 + +Hemingway《老人与海》的最后一句"他终于驶进港口,梦见狮子"在动笔前就已存在——终局先于全书。 + +## 中文落地 + +- **(中文适配)** Clark 的盲点自查里承认:"从最后一章写起"在长篇奇幻中可行(JK Rowling),但在中国当代文学(严肃文学)中罕见——后者更常"先定情绪基调",而非"先定终局画面"。中文落地时可以先定终局的**情绪**("结尾该是什么味道"),再用判停问法把情绪落成具体画面。 +- 中文网文的"留钩子"结尾(留悬念给下集)和"开放式收尾"(主角不死、敌人未灭)在 Clark 框架之外,是中文语境特有的结尾形态,处理见 references/execution-chain.md 的中文适配条。 diff --git a/framework/catalog/pi/skills/story-ending/references/natural-stop.md b/framework/catalog/pi/skills/story-ending/references/natural-stop.md new file mode 100644 index 0000000..23ec245 --- /dev/null +++ b/framework/catalog/pi/skills/story-ending/references/natural-stop.md @@ -0,0 +1,26 @@ +# Rachmaninoff 警告:手盖法找自然止点,砍掉拖尾 + +## 方法定位 + +Clark 的收尾警告:**绝不要"拖尾"**(Rachmaninoff 式——像拉赫玛尼诺夫协奏曲一样没完没了)。结尾之后多出来的每一段,都在稀释终局。 + +## 操作步骤:手盖法 + +- **操作**:用手盖住最后一段,问"如果在这里结束呢?",然后反复上移——盖住最后两段、三段……直到找到"自然止点"。 +- **判停标准**:上移到"再少一段就觉得缺"的位置,那里就是自然止点;止点之后的内容全砍。(中文适配) + +## 失败模式:拖尾式收尾(全量) + +- **失败模式**:最后几段"反复总结主题 + 复述情节 + 补道德教训"。 +- **信号**:读者读到最后一段觉得"可以结束了"。 +- **机制**:作者不舍得放手,觉得"我还没说完"。 +- **预警**:Clark 的检验法——"手盖住最后一段,问'如果在这里结束呢?'",反复上移找自然止点。 + +## 与其他动作的衔接 + +- 砍掉拖尾后,回头跑一遍 references/execution-chain.md 的逐章检验,确认砍掉的部分没有带走终局回声。 +- 拖尾和"扩展"是两回事:拖尾是稀释,扩展是打开。把注水当扩展是误区,见 references/pitfalls-and-boundaries.md。 + +## 中文落地 + +中文里对应的毛病叫"画蛇添足""狗尾续貂";判断标准一样——读者在最后某一段已经觉得"可以合上书了",后面的就是拖尾。(中文适配) diff --git a/framework/catalog/pi/skills/story-ending/references/pitfalls-and-boundaries.md b/framework/catalog/pi/skills/story-ending/references/pitfalls-and-boundaries.md new file mode 100644 index 0000000..bc68219 --- /dev/null +++ b/framework/catalog/pi/skills/story-ending/references/pitfalls-and-boundaries.md @@ -0,0 +1,107 @@ +# 边界、误区、盲点与激活场景 + +本文件集中承载不适用边界、失败模式与常见误区、作者盲点与时代局限、易混淆方法与相邻 skill 区分、激活场景与语言信号。 + +## 不适用场景(不要在这些情况使用本 skill) + +- **开放式实验文学**——故意不收束的作品。 +- **反叙事的解构作品**——用"无结尾"本身作为表达。 +- **短抒情诗 / 散文**——抒情节奏不靠"结局"收束。 +- **刻意反高潮的平铺直叙**——比如某些新写实主义小说。 +- **真正需要闭环的事务**——如合同签署、手术完成、机器启动,必须收束,不能"打开"。 +- **必须收束的紧急信息**——"立即撤离",不能让听众带着"还有别的方案"离开。 +- **重复使用同一类型作品**——一次决策后不必每次都重新评估。 +- **极其简短的内容**——一条推文、一句话邮件,不需要"扩展"姿态。 + +## 常见误区与失败模式(索引 + 全量) + +### Clark 三条 + +1. **"Rachmaninoff 式"拖尾**:失败模式是最后几段"反复总结主题 + 复述情节 + 道德教训"。信号:读者读到最后一段觉得"可以结束了"。机制:作者不舍得放手,觉得"我还没说完"。预警:手盖法反复上移找自然止点。→ 细节与操作见 references/natural-stop.md +2. **"开头/结尾无关联"**:失败模式是开头和结尾是"两个不同的故事"。信号:读者读完后回想开头,觉得"和结尾没关系"。机制:作者没先定结尾,写到中段失去方向。预警:Chain of Execution 检验失败。→ 细节见 references/execution-chain.md +3. **"兑现陈词滥调"**:失败模式是用"他们从此幸福地生活在一起"等套话结尾。信号:读者觉得"又是这个"。机制:作者没找到属于自己的"独特终局"。预警:10 种策略选错,或未本地化。→ 细节见 references/ending-strategies.md + +### Forster 四条 + +4. **追求"完成"到阉割人性**——詹姆斯式,普洛克路斯忒斯之床。把人物和情节削足适履,砍掉小说的人性内容。案例细节见 references/expansion-completion.md 案例 3。 +5. **追求"扩展"到拖戏**——现代电视剧/小说的注水,误把"拖"当"扩展"。扩展是读完一切更醒目,不是更松散。 +6. **强行收束于"婚姻/死亡"**——多数小说的"虎头蛇尾"。把仪式性事件当唯一收束手段。 +7. **把"未完成"当"扩展"**——写作失败的辩护。先回答这个"打开"是作者故意的还是写不下去的遮羞布(与 Clark 的"有意 vs 无意"判断合流,见 references/ending-strategies.md)。 + +## 作者的盲点 / 时代局限 + +### Clark 的盲点 + +- Clark 主要讲西方叙事(美国长篇小说 + JK Rowling 英式奇幻 + 经典文学)。中文网文"留钩子"结尾(留悬念给下集)和"开放式收尾"(主角不死、敌人未灭)需要单独讨论——这些是 Clark 框架之外的形态。 +- "从最后一章写起"在长篇奇幻中可行(JK Rowling),但在中国当代文学(严肃文学)中罕见——后者更常"先定情绪基调",而非"先定终局画面"。 + +### Forster 的盲点 + +- **音乐 vs 小说类比的限制**——音乐有"终了"但无"页码",小说有"最后一页",二者形式不同。 +- **1927 年的视角**——没看到 60 年代后的"开放结局"(新浪潮电影)的极端。 +- **西方文学中心的视角**——东方叙事的"留白"传统(中国画、禅宗)与"扩展"有相似性,但福斯特未充分讨论。 + +## 容易混淆的邻近方法论 + +### Clark 侧:inciting-incident、chekhov-gun、开放式结局 + +- 与 `inciting-incident` 的区别:那是"启动事件"(开头),这是"终局事件"(结尾)。对称结构。(inciting-incident 现归 `story-structure`) +- 与 `chekhov-gun` 的区别:那是"埋伏"(承诺),这是"兑现"(履行)。前者为结尾铺路,后者是结尾本身。(chekhov-gun 现归 `foreshadow-payoff`) +- 与"开放式结局"的区别:开放式结局是 10 种策略之一,不是"无结尾"。关键判断:作者有意还是无意的开放? + +### Forster 侧:戏剧结构、开放式结局、续集 + +- **vs 戏剧结构(Dramatic Structure)**——戏剧结构是"完成的极致",不是"扩展";但现代戏剧早已拒绝亚里士多德。 +- **vs 开放式结局(Open Ending)**——开放式结局是"叙事特征",扩展是"读者意识的姿态";前者可以是后者,但不一定。 +- **vs 续集(Sequel)**——续集是"另写一部",扩展是"在一部内打开"——不能混为一谈。 + +## 与相邻 skill 的区分 + +### Clark 侧:story-engine、chekhov-gun、gold-coins、internal-cliffhanger + +- 与 `story-engine` 的区别:那个是"贯穿全书的核心问题"(问题驱动),这个是"先定终局再反推"(答案驱动)。前者问"故事要回答什么",后者问"故事要在哪里结束"。(story-engine 现归 `concept-design`) +- 与 `chekhov-gun` 的区别:那个是"埋伏笔"(承诺),这个是"兑现伏笔"(履行)。前者是债务建立,后者是债务结算。 +- 与 `gold-coins` 的区别:那个是"沿途给奖励",这个是"终局给大奖"。前者是中段,后者是结尾。(gold-coins 现归 `narrative-momentum`) +- 与 `internal-cliffhanger` 的区别:那个是"维持叙事钩子"(局部),这个是"收束整本"(全局)。(internal-cliffhanger 现归 `narrative-momentum`) + +### Forster 侧:pattern-vs-rhythm、time-vs-value-life、开放式 vs 封闭式结局 + +- 与 `pattern-vs-rhythm` 的区别:扩展/完成是**作品终点的姿态**,模式/节奏是**作品整体的形式感**;前者管结尾,后者管全程。(pattern-vs-rhythm 现归 `novel-diagnosis`) +- 与 `time-vs-value-life` 的区别:扩展/完成是**作者姿态**,时间/价值是**体验诊断**;前者管作品选择,后者管体验效果。(time-vs-value-life 现归 `novel-diagnosis`) +- 与"开放式结局 vs 封闭式结局"的区别:后者是"叙事结构的特征",扩展/完成是"作者对读者意识的姿态"。 + +## 激活场景与语言信号 + +### 用户情境 + +1. 写到 80% 进度,发现"最后 3 章不知道写什么",担心烂尾。 +2. 写完长篇觉得"拖尾"——最后 5000 字其实是第 3 段结尾,不是终局。 +3. 系列小说不知道"本集结局"和"系列结局"怎么协调——担心读者失去耐心。 +4. 网文写到最后几章,担心"付费点后"读者弃读。 +5. 短篇不知道"最后一句"该怎么收。 +6. **写小说/剧本/演讲/课程结束的章节**——决定结尾是"收束"还是"打开"。 +7. **设计产品发布/活动收尾/演示结尾**——选"完成"(清晰闭环)还是"扩展"(留下思考空间)。 +8. **做一份报告/讲演**——决定"用结论收束"还是"用问题打开"。 +9. **策划一个有"结束感"的事件**——婚礼、毕业典礼、纪念活动,选"仪式闭环"还是"开放留白"。 +10. **读一个作品/看一个演出**——评估"它结束得让我被关起来,还是被打开了"。 +11. **教学/讲课时**——决定一节课的结尾是"总结"还是"留个悬而未决的问题"。 + +### 语言信号 + +- "怎么结尾" / "如何结尾" +- "烂尾" / "结尾无力" +- "ending" / "倒推写作" / "write toward an ending" +- "chain of execution" +- "结尾策略" / "结局设计" +- "结局如何设计" / "收尾" +- "从最后一章写起" +- "本集结局" / "系列结局" +- "我该怎么收尾" +- "完成 vs 打开 / 收束 vs 扩展" +- "X 让我感到被关起来 / 被打开" +- "X 戛然而止 / 意犹未尽" +- "我想让听众/读者带着 X 离开" +- "怎么结尾?" +- "X 是闭环 / 开放" +- "X 结束得太突兀 / X 结束得拖沓" +- "我要给 X 留白 / 收口" diff --git a/framework/catalog/pi/skills/story-planning/SKILL.md b/framework/catalog/pi/skills/story-planning/SKILL.md new file mode 100644 index 0000000..07f54fc --- /dev/null +++ b/framework/catalog/pi/skills/story-planning/SKILL.md @@ -0,0 +1,93 @@ +--- +name: story-planning +description: | + 激活场景:用户在规划新故事、做故事蓝图或节拍表;纠结"凭灵感写还是按计划写";有一个想法想变成完整故事; + 凭灵感写作卡在中段、故事乱、不知道接下来写什么;写完一稿想诊断故事哪里出了问题。 + 关键 trigger:"节拍表 / beat sheet / 什么是节拍表 / 节拍表是什么 / 故事大纲 / 故事规划 / story planning / + 故事蓝图 / 写之前要做什么 / 我应该怎么规划故事 / 灵感写作 / pantsing / 计划写作 / plotting / 凭灵感写 / + 凭感觉写 / 短篇怎么开始 / 小说怎么写 / 故事写作步骤 / 我想写小说 / 我有一个想法 / 怎么把想法变成完整故事 / + 故事没头没尾 / 卡在故事中段 / 接下来写什么 / 写到第 5 稿还在找故事"。 + 不适用于:故事结构本身的定义(四箱、六里程碑见 story-structure);场景、对话、叙述层面的改稿技巧; + 作者日常写作习惯与心态调节;非虚构写作;实验性非线性写作(节拍表假设线性)。 + 与 concept-design 交接:只有模糊 idea、引擎不清 → concept-design;概念已定、要节拍表与工作流 → 本 Skill。 +--- + +# 故事规划工作流(story-planning) + +一句话定位:把"找故事"挪到动笔之前——先决定工作流,再准备和酝酿素材,用节拍表摊开全局,然后一气呵成地动笔。 + +## 方法索引 + +按创作动作组织;方法细节、案例、引文都在 references 里,这里只给一句话和指针。 + +### 选工作流:凭灵感还是做计划 + +- 凭灵感写不是不规划,是用 3-5 稿代替规划,是最昂贵的一种;三种工作流,多数人该选 Plotter → references/plan-vs-pantsing.md +- 知情灵感有两个前提:King 级的结构内化,或愿意付 5 稿重写的代价 → references/plan-vs-pantsing.md +- 自评流程:判断自己是哪一型 → 问是不是 King → 在 30 分钟节拍表与 5 个月重写之间二选一 → references/plan-vs-pantsing.md + +### 写前准备:找想法、备素材 + +- 找一个坐下来就能完成的简单想法,且它必须对你有情感价值 → references/draft-flow.md +- 用 1-2 天做前期准备:想透 1-3 个主要人物及其背景,细到"门把手的质地",哪怕根本不写进书里 → references/draft-flow.md + +### 酝酿:让无意识干活 + +- 放下 1-3 天不动笔,做梦梦到它是好信号,等"想写"的冲动自然出现再动笔 → references/draft-flow.md + +### 蓝图:用节拍表摊开全局 + +- 一个场景一条 bullet,每条写这一场的任务(mission)和关键内容,可重排、廉价修改 → references/beat-sheet.md +- 节拍表 ≠ 大纲:节拍表一行,大纲一段,大纲是节拍表的扩展,先做节拍表后做大纲 → references/beat-sheet.md +- 排序后逐一验证四箱(布局/反应/进攻/解决)与六里程碑的位置,结构定义见 story-structure → references/beat-sheet.md +- 节拍表双用途:写前规划全局,写后诊断哪里不好 → references/beat-sheet.md + +### 动笔:锚定首尾、一气呵成 + +- 动笔前定下第一句和最后一句:第一句是跳板,最后一句是降落点,中间不会迷路 → references/draft-flow.md +- 不等完美开头、不等完美状态、不中途修改,短篇应当天写完保住情绪 → references/draft-flow.md + +### 收尾:搁置再读,节拍表复盘 + +- 完稿立刻放一边,至少隔一夜(通常 2-3 天)再用陌生人的眼光重读 → references/draft-flow.md +- 写完也能做节拍表:从完稿反向列 bullet,看哪一场没有任务、哪一场位置不对 → references/beat-sheet.md + +### 跨书差异说明(两条都保留) + +- 篇幅分工:布兰德六阶段针对 5000-30000 字短篇("当天完成"是短篇标准,对长篇不适用);Brooks 节拍表针对长篇(一个故事约 60 个场景)。各管各的篇幅,详见 references/draft-flow.md 的"盲点"节与 references/beat-sheet.md 的"两种用法"节。 +- 两种节奏:布兰德让无意识酝酿领路,警告写作中途用理性干预;Brooks 让理性规划领路,动笔前摊开全局。两者不冲突,可串联——先用布兰德的前三阶段找素材并酝酿,长篇再上 Brooks 的节拍表,动笔时回到布兰德的一气呵成纪律。 + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|---------| +| references/plan-vs-pantsing.md | 灵感写作 = 用草稿做规划、三种工作流与作者立场、知情灵感两条件、Stephen King 案例、普通 Pantser 与"我没时间规划"反例、四步自评操作、触发场景与语言信号、失败模式/盲点/易混、中文适配 | +| references/beat-sheet.md | 节拍表定义原文与中文转译、本质、≠ 大纲、两种用法、为什么有效、操作法、蓝天使与作者 5 部小说案例(与 pantsing 单元同案去重合并)、直接开写反例、7 步操作(含四箱百分比与六里程碑校验)、触发场景、失败模式/盲点/易混、中文适配 | +| references/draft-flow.md | 短篇六阶段完整流程(找想法/前期准备/酝酿/充满信心地写/一气呵成/搁置重读)、R 段原文、福特方法等三案例全文、7 步操作(含诊断提问与判停)、四条不可跳、触发场景、失败模式/盲点/易混、相邻方法区分(含裁剪单元注记)、中文适配 | +| references/_coverage.md | 三个源单元的覆盖对照表 | + +## 脚本 + +| 脚本 | 用途 | +|------|------| +| references/planning-workflow-checklist.md | 规划工作流台账:工作流自评、节拍表制作与结构校验清单、短篇六阶段卡壳诊断、完稿后复盘 | + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落。 + +## 红线 + +- 只给当前创作阶段的建议,不越权改设定主权、不绕过检测链、不复制粘贴其它 Skill 的 owner 定义。 +- 无用户明确授权不得替用户定稿或提交 Git。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/pi/skills/story-planning/references/_coverage.md b/framework/catalog/pi/skills/story-planning/references/_coverage.md new file mode 100644 index 0000000..25e0939 --- /dev/null +++ b/framework/catalog/pi/skills/story-planning/references/_coverage.md @@ -0,0 +1,10 @@ +# story-planning 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| becoming-a-writer/story-draft-flow | references/draft-flow.md | +| story-engineering/workflow-beat-sheet | references/beat-sheet.md | +| story-engineering/workflow-pantsing-is-planning | references/beat-sheet.md | +| story-engineering/workflow-pantsing-is-planning | references/plan-vs-pantsing.md | diff --git a/framework/catalog/pi/skills/story-planning/references/beat-sheet.md b/framework/catalog/pi/skills/story-planning/references/beat-sheet.md new file mode 100644 index 0000000..8415500 --- /dev/null +++ b/framework/catalog/pi/skills/story-planning/references/beat-sheet.md @@ -0,0 +1,181 @@ +# 节拍表:用一行一条把故事全局摊开 + +来源:(Larry Brooks,《Story Engineering》(2011),Part 8 · Getting It Written) + +## 原文摘录 + +> "A beat sheet is a list of short, bulleted descriptions that define each scene in your story. They may not even be scenes at first, just moments and ideas. If you have sixty scenes in your story, create a beat sheet with sixty entries that describe the mission and the content for each scene. Each entry on the beat sheet describes what the scene does in context to story exposition. It explains why it is there." +> +> — Larry Brooks, *Story Engineering* (2011), Part 8 + +() + +中文转译(中文适配):节拍表是一份简短的 bullet 描述清单,定义你故事里的每一个场景。一开始它们甚至可以还不是场景,只是一些瞬间和想法。如果你的故事有 60 个场景,就做一份有 60 个条目的节拍表,每个条目描述该场景的任务和内容。节拍表上的每个条目都描述这个场景在整个故事铺陈中起什么作用——它解释这个场景为什么在那里。 + +## 节拍表是什么 + +节拍表是写正文之前的**最小单元规划**——把每个未来场景/节拍写成 1 行 bullet,描述 mission + 内容。它先于 outline,是"故事在脑/纸上完整走一遍"。 + +本质: + +- 1 故事 = 60 个场景(平均) +- 1 场景 = 1 行 bullet +- bullet 含:场景的 mission + 场景的关键内容 +- bullet 可重新排序,廉价修改 + +() + +## 节拍表 ≠ 大纲 + +- 大纲是"段落式",100+ 字 +- 节拍表是"列表式",1 行 +- 大纲是节拍表的扩展(从 1 行扩到 1 段) +- 节拍表先做,大纲后做 + +() + +## 节拍表的两种用法 + +1. **Pre-draft(写前)**:写正文前做,看到全局 +2. **Post-draft(写后)**:写完一稿后做,诊断"哪里不好" + +() + +## 为什么有效 + +- "找故事"在写正文前完成,不用 5 稿重写 +- 看完整序列 = 可优化全局 +- bullet 廉价修改(vs 重写章节) + +() + +## 操作法 + +- 准备:便利贴/索引卡/白板/Markdown 列表/任何能"看到全局"的工具 +- 列出:60 个 bullet +- 每个 bullet 含:场景 mission + 关键内容 +- 排序:验证 4 箱 + 6 里程碑位置 +- 修改:任何不对的地方直接动 bullet + +() + +## 案例全文 + +### 案例 1:蓝天使飞行表演 — 节拍表类比 + +- **方法**:飞行员表演前,围桌口头走完整流程 +- **结论**:"看到全局"是专业表演的关键 +- **类比**:节拍表 = 写作的"飞行员预演" + +() + +### 案例 2:作者自述 — 5 部小说都用节拍表(合并案例) + +同一案例出现在同书两个单元: 案例 2 与 案例 2,同书同案例同角度,按合并规则去重留最全: + +- **方法**:5 部小说写正文前,必做节拍表 +- **结果**:5 部全出版,1 本 8 周写完,1 本年度最佳 +- **验证**:节拍表 + 6 核 = 高效写作;同时支撑 pantsing 单元"Plotter 高效"的论点 + +(、workflow-pantsing-is-planning;合并说明为本次合并所加) + +### 案例 3:反例 — 直接开写 + +- **问题**:写作者直接开写,不做节拍表 +- **诊断**:写到 50% 发现"前面要改",但已经写完,改起来痛苦 +- **方法**:改用节拍表(即使 Post-draft),列出 60 个 bullet,重新排序 +- **结果**:看清楚问题,改起来明确 + +() + +## 操作步骤 + +1. **选 1 个故事(新/旧)** + - 完成标准:用户指定 1 个故事 + - 新 = 写前 + - 旧 = Post-draft +2. **准备工具** + - 完成标准:便利贴/白板/Markdown 列表(任选) +3. **列 bullet(目标 60 个)** + - 完成标准:60 个 bullet(可少于 60,不可多于 100) + - 每个 bullet 含: + - 场景 mission(1 句) + - 关键内容(1-2 句) +4. **排序 + 验证 4 箱** + - 完成标准:验证 4 箱位置 + - 0-25% = Setup + - 25-50% = Response + - 50-75% = Attack + - 75-100% = Resolution +5. **验证 6 里程碑** + - 完成标准:6 个里程碑都在 + - 任何缺 = 补 bullet +6. **修改** + - 完成标准:列出"哪些 bullet 要改/删/并" + - 廉价修改(vs 重写) +7. **(可选)转大纲** + - 完成标准:把 bullet 扩到段落 = 大纲 + +() + +## 触发场景 + +1. **新项目启动**:"我要写新故事,怎么规划?" +2. **改稿诊断**:"我写完一稿,但故事乱" +3. **写作卡壳**:"我不知道接下来写什么" +4. **Pantser 转 Plotter**:"我以前凭灵感写,现在想做规划" + +语言信号: + +- "节拍表 / beat sheet" +- "故事大纲 / 故事规划 / story planning" +- "我应该怎么规划故事 / 写之前要做什么" +- "故事蓝图 / story blueprint" + +() + +## 与相邻方法的区分 + +- **故事结构(structure-*)**:是"结构"(4 箱/6 里程碑,节拍表用这些),合并库中见综合 skill story-structure +- **工作流哲学(反对纯灵感)**:与本单元互补,见本包 references/plan-vs-pantsing.md +- **本单元**:是"具体规划工具"(节拍表本身) + +(;指针为本次合并更新到合并库) + +## 边界 + +### 不要在以下情况使用 + +- 写 flash fiction/中短篇——节拍表 overkill +- 写实验性/非线性——节拍表假设线性 +- 已经是大纲——节拍表已包含 + +### 作者警告的失败模式 + +- bullet 太详细——节拍表是 1 行,大纲是 1 段 +- bullet 只写"内容"不写"mission"——mission 让排序有依据 +- bullet 太多(> 100)——故事太长/太散 +- bullet 太少(< 30)——故事可能不够细 + +### 作者盲点 + +- 假设节拍表只用于 Pre-draft——Post-draft 同样有效(用于诊断) +- 假设节拍表 = 大纲——节拍表更小,大纲是扩展 +- 假设节拍表只 1 种格式——任何"看到全局"的形式都行 + +### 易混方法论 + +- "Outline"——大纲,是节拍表的扩展 +- "Story Bible"——是完整世界设定,远比节拍表宽 +- "Snowflake Method"——是从 1 句扩展到全文,不是节拍表 + +() + +## 中文适配 + +- 中文落地工具:原文的便利贴/索引卡/白板,对应中文写作者常用的码字卡片、思维导图、Excel/Markdown 列表,要求不变——能一眼看到全局。 +- 篇幅换算:Brooks 假设的纸书长篇约 60 个场景;中文网文动辄百万字,不要给全书做一张节拍表,按卷做——开一卷之前先把这一卷的场景列出来,一场景一条 bullet,每卷条数参照 30-100 的区间。 +- 中文网文连载流程里,节拍表就是"粗纲"工具;平台或编辑要求交细纲时,沿操作步骤第 7 步把每条 bullet 扩成一段即成细纲。 +- 四箱中文译名本包用:布局(Setup)/反应(Response)/进攻(Attack)/解决(Resolution);六里程碑的定义在综合 skill story-structure,这里只当校验槽位用,不重复定义。 + +(本节为本次合并补充的中文落地说明) diff --git a/framework/catalog/pi/skills/story-planning/references/draft-flow.md b/framework/catalog/pi/skills/story-planning/references/draft-flow.md new file mode 100644 index 0000000..377aad5 --- /dev/null +++ b/framework/catalog/pi/skills/story-planning/references/draft-flow.md @@ -0,0 +1,233 @@ +# 短篇完整流程:从一个想法到完稿的 6 阶段 + +来源:(多萝西娅·布兰德,《成为作家》第十四章) + +## 原文摘录 + +> "你现在还没有开始写呢。你正在做的工作是前期准备。过一两天, 你将全神贯注于这些细节当中。 +> 你将理性地分析这些细节, 如果必要的话, 还要去读些参考书, 补充你的事实。 +> 然后做梦你都会梦到它。你将把这些人物分开一个一个地思考, 再把他们合在一起。 +> 你打算为这个故事做一切努力, 轮番运用你的理性思考和无意识冥想。 +> 现在, 立即开始写作。就像你自己进行第六章里的时间练习一样, +> 不要找任何借口, 拒绝任何居场的感觉, 只是开始写作。 +> 你开始写作之前, 把故事的第一句话和最后一句确定下来, +> 你会发现这非常有好处。这样你就可以用第一句作为跳板, 延伸你的故事, +> 用最后一句作为降落点。 +> 这个故事还应该在开始的当天完成。" +> +> — 多萝西娅·布兰德,《成为作家》第十四章 + +() + +## 六阶段流程总览 + +写一个完整故事(短篇 5000-30000 字)的 **6 阶段流程**。每个阶段有明确动作,不能混淆。 + +### 阶段 1:找到一个简单的想法(从清晨素材中找) + +- **来源**:清晨随手写的、开会时冒出的、生活中观察到的、读书时联想的(中文写作者可用自己的素材笔记替代,见文末中文适配) +- **标准**:这个想法必须**简单**——一个你"坐下来就能完成"的东西 +- **不要**:想写一部"涵盖我整个人生观"的长篇(那是更大的项目) +- **要**:找"小"——一个片段、一段对话、一个场景、一个瞬间 +- **判断**:这个想法对你"有情感价值"吗?有,就继续;没有,放下 + +### 阶段 2:前期准备(1-2 天,理性分析) + +- **不要马上动笔!** 这个阶段是"前期准备",不是"开始写" +- **具体动作**: + - 确定主要人物(1-2 个,最多 3 个) + - 想象他们的生活背景:长相、教育、家庭、工作、性格 + - 即使你"不会写到"这些细节,**想象它们能让你写得更可信** + - 福特的名言:"**除非我了解我要写的那个地方的最远的历史,我绝不开始动笔**" +- **持续时间**:1-2 天 +- **关键**:理性 + 无意识交替("轮番运用你的理性思考和无意识冥想") + +### 阶段 3:酝酿(做梦阶段,1-3 天) + +- 放下稿子,让无意识接管 +- 做梦都会梦到它——这是好信号 +- **不要粗暴拒绝"还没准备好"**的感觉,让它再沉一沉 +- 等待"**想写**"的冲动自然出现 +- 持续时间:1-3 天 + +### 阶段 4:充满信心地写作(立即开始) + +- **不要"等完美的开头"**——如果想不到好开头,把它放在一边,稍后再写 +- **不要"等完美状态"**——立即开始 +- **不要"中途修改"**——一气呵成 +- **减少重读**——只时不时读 1-2 个句子,确认方向 +- **关键技巧**:动笔前确定**第一句 + 最后一句** + - 第一句 = 跳板 + - 最后一句 = 降落点 + - 中间无论怎么写,都不跑题 + +### 阶段 5:一气呵成(当天写完) + +- **"在开始的当天完成"**——情绪状态要在同一天内保持 +- 中间可以暂停(喝水/休息),但**不要放下超过几个小时** +- 如果实在写不完:起身前**约定下次时间**,形成"催眠式"连续性 +- 完成的标志:写完最后一个字,合上文档 + +### 阶段 6:搁置 + 批评式阅读(2-3 天后再读) + +- 写完**立刻放一边**,不重读 +- 最少隔一夜,通常 2-3 天,实在等不及 1 周 +- 然后用"陌生人眼光"重读 + +(;裁剪单元注记为本次合并所加) + +## 为什么这 6 阶段是必要的 + +- 阶段 1-2 = 给无意识**素材** +- 阶段 3 = 让无意识**整合素材** +- 阶段 4-5 = 让意识 + 无意识**协作输出** +- 阶段 6 = 让意识**客观评价**(避免被写作时的情绪污染) + +() + +## 关键警告:四条不可跳 + +- 阶段 1-2 不能跳过(无意识没有素材) +- 阶段 3 不能省略(无意识需要时间整合) +- 阶段 4-5 不能拆分("中间停几天再写" = 风格割裂) +- 阶段 6 不能提前(写完立刻读 = 必然觉得烂) + +() + +## 案例全文 + +### 案例 1:布兰德的"前期准备" — 福特的方法 + +- **问题**:不知道写故事前要准备到什么程度 +- **方法论的使用**:福特:"我必须了解窗户的形状、门把手的质地、厨房的装潢、衣服的布料、鞋子的皮革、马车劳动的方式, 以及汽车标的种类等等。" +- **结论**:"**我在书中根本不会用到这些东西**。但是如果我不知道他的手指握的是哪种门把手, 我如何能 — 为了我自己满意 — 让我的人物握住它?" +- **结果**:写出来的人物动作**可信**,因为作者知道每个细节(即使不写出来) + +() + +### 案例 2:布兰德的"充满信心地写作"原则 + +- **问题**:不知道何时动笔 +- **方法论的使用**:"如果想不到一个好的开头, 就把它放在一边, 稍后再写" + "立即开始写作" +- **结论**:不要"等完美开头",也不要"没准备好就动笔";用**第一句 + 最后一句**锚定,立即开始 +- **结果**:故事能写完,且不跑题 + +() + +### 案例 3:布兰德的"一气呵成" — 写作风格的一致性 + +- **问题**:写到一半放下几天,前后风格割裂 +- **方法论的使用**:"**这个故事还应该在开始的当天完成**" +- **结论**:中间停太久 = 情绪状态切换 = 风格割裂("像拼接的棉被") +- **结果**:同一天写完 = 风格统一,情绪连贯 + +() + +## 操作步骤 + +激活后按以下步骤执行: + +1. **诊断:用户卡在 6 阶段的哪一步** + - 完成标准:用户能指出"我卡在阶段 X" + - 提问:"你现在的状态是 — 有想法?在准备?在酝酿?在写?在写完?在重读?" + - 判停条件:若用户说"我都还没开始" → 路由到阶段 1 +2. **阶段 1:帮用户找到"简单的想法"** + - 完成标准:用户能用 1-2 句话说出他的想法 + - 提问:"你现在最想写的**一个**东西是什么?不用大,一个场景/一段对话/一个瞬间" + - 判停条件:若用户说"我想写一部涵盖我整个人生观的长篇" → 缩到"长篇中你想先写的**一个**场景" +3. **阶段 2:帮用户列"前期准备清单"** + - 完成标准:用户能列出主要人物 + 他们的 3-5 个背景细节 + - 关键:不需要"完美",需要"够用"(福特的方法是"我要知道",不是"我要写到") +4. **阶段 3:建议"放下几天"** + - 完成标准:用户承诺"准备完后,放下 1-3 天,不动笔,让它沉" + - 关键:这是无意识整合时间,不是"拖延" +5. **阶段 4:帮用户确定"第一句 + 最后一句"** + - 完成标准:用户能给出第一句和最后一句 + - 关键:这两个锚点让你"不会迷路" + - 提问:"这个故事**开始**时,第一个画面/声音/动作是什么?**结束**时,最后一个画面/声音/动作是什么?" +6. **阶段 5:让用户承诺"当天写完"** + - 完成标准:用户能说出"我 X 时候开始,当天 X 点前写完" + - 关键:给自己一个 deadline;写不完就起身约定下次(见 `scheduled-writing`,已裁剪单元) +7. **阶段 6:让用户承诺"2-3 天后重读"** + - 完成标准:用户承诺"写完后立刻放一边,至少隔一夜再重读" + - 详见 `set-aside-the-manuscript`(已裁剪单元) + +(;裁剪单元注记为本次合并所加) + +## 触发场景 + +1. **"我想写一个短篇小说,不知道从哪开始"**——经典起步场景 +2. **"我有一个想法,怎么变成完整故事"**——有 idea,没流程 +3. **"我写故事没头没尾"**——缺结构 +4. **"我卡在故事中段"**——缺流程中的某个步骤 +5. **"我该按什么流程写一个故事"**——直接询问流程 +6. **"我有一个场景,怎么扩成完整故事"**——反向:局部到整体 +7. **"我写完一篇不知道算不算'完'"**——缺"写完"的标准 + +语言信号(用户的话里出现这些就应激活): + +- "我想写小说" +- "我有一个想法" +- "故事没头没尾" +- "怎么写完整故事" +- "短篇怎么开始" +- "我卡在中段" +- "我有个场景想扩" +- "我写完不知道算不算完" + +() + +## 边界 + +### 不要在以下情况使用 + +- **写长篇(> 30000 字)**——短篇流程不适用,长篇有自己的结构(三幕/英雄之旅等);长篇规划改用本包节拍表,见 references/beat-sheet.md(补充指针为本次合并所加) +- **已经能流畅写完整故事的人**——这是基础,不是优化 +- **非虚构/技术写作**——故事写作的 6 阶段不适用,那是调研-写作-审校的流程 +- **用户只想"写一个片段"**——那是 `fiction-scene-craft` 或 `fiction-dialogue` 范围(合并库中见综合 skill scene-craft、dialogue-craft) +- **用户的"想法"是模糊的**——阶段 1 需要"简单",模糊的想法属于动笔前的心理障碍,不是流程能解决的 + +### 作者在书中警告的失败模式 + +- **写时读太多**(ce12):写到一半读别人作品,自己的调子被污染 +- **模仿风格**(ce02):模仿别人的"味道",永远追不上 +- **写完就删**(ce04):写完立刻重读觉得烂 +- **模仿别人的内容**(f10 边界):因为别人用过某题材成功,你就跟着用 +- **公开宣告**(ce03):写之前跟朋友讲构思,招来嘲讽 + +### 作者的盲点/时代局限 + +- **1934 年没有"碎片化阅读"**——当时读长篇是常态,现在读者注意力更短 +- **"前期准备 1-2 天"在今天可能太短**——复杂题材需要更长 +- **不区分"严肃文学"和"类型小说"**——流程一样,但类型小说对"情节结构"要求更严 +- **"当天写完"对长篇不适用**——布兰德的"当天"是短篇标准 +- **没考虑"AI 协作"**——今天可以用 AI 做前期准备(列人物清单/查资料),不是"自己"准备 + +### 容易混淆的邻近方法论 + +- **"写小说"的 7 步法(通用)**——类似结构,但更工业化 +- **"雪花写作法"(Snowflake Method)**——类似,但强调"10 步扩展",不是 6 阶段 +- **"英雄之旅"(Hero's Journey)**——是**结构**,不是流程 +- **"三幕剧"**——是**结构**,不是流程 + +() + +## 与相邻方法的区分 + +原书相邻 skill,指针更新到合并库: + +- **与 `fiction-opening` 的区别**:story-draft-flow 是"整个流程"(6 阶段);fiction-opening 是"阶段 4"(开头怎么写)的具体技术。前者是宏观,后者是微观。fiction-opening 在合并库中归综合 skill story-structure(开篇部分)。 +- **与 `fiction-scene-craft` 的区别**:story-draft-flow 是"故事整体"(短篇完稿);fiction-scene-craft 是"故事内部"(场景与节奏)。前者是 size,后者是 craft。合并库中见综合 skill scene-craft。 +- **与 `fiction-dialogue` 的区别**:对话是阶段 4-5 的内部技术,合并库中见综合 skill dialogue-craft。(本条由原单元 frontmatter related_skills 补充) +- **与"搁置手稿"的区别**:本流程包含阶段 6(搁置 + 批评式阅读);搁置手稿是阶段 6 的具体技术。前者是流程,后者是单步细节。该方法未入本技能库,原指针按原文保留。 +- **与"定时写作"的区别**:定时写作是"每天 15 分钟"的纪律;本流程是"写一个完整故事"的纪律。前者是日常,后者是项目。该方法未入本技能库,原指针按原文保留。 + +## 中文适配 + +- 《成为作家》为中译本,六阶段流程、诊断提问、福特方法可直接用于中文短篇写作自查与教学,不需要转译。 +- 阶段 1 的素材来源是原书的"清晨页笔";中文写作者用自己已有的素材本、随手记、备忘录等素材积累习惯替代即可,标准不变:想法要小、要有情感价值。 +- "当天完成"是短篇标准;中文网文的日更连载模式不适用,连载的连续性问题改用节拍表按卷规划解决,见本包 references/beat-sheet.md。 +- 布兰德的盲点条款在中文语境同样成立:类型小说(悬疑、仙侠、言情)比严肃文学更吃情节结构;复杂题材的前期准备 1-2 天通常不够。 +- 阶段 6 的搁置重读与完稿心态,原书另有专章讲述,未入本技能库;此处只保留"搁置 + 批评式阅读"这一步骤本身。 + +(本节为本次合并补充的中文落地说明) diff --git a/framework/catalog/pi/skills/story-planning/references/plan-vs-pantsing.md b/framework/catalog/pi/skills/story-planning/references/plan-vs-pantsing.md new file mode 100644 index 0000000..e441b83 --- /dev/null +++ b/framework/catalog/pi/skills/story-planning/references/plan-vs-pantsing.md @@ -0,0 +1,162 @@ +# 灵感写作实际是用草稿做规划 + +来源:(Larry Brooks,《Story Engineering》(2011),Introduction · Outlining vs. Organic Storytelling) + +## 原文摘录 + +> "The less story planning writers do before they begin the drafting process, the deeper hole they dig for themselves. Too often they don't even recognize the pit they're in, so when the rejection slips arrive they don't have a clue as to why. Newer writers who don't understand those fundamentals, and who try to write the same way? Not so much. It pours out of their head and basically spills all over the place. Two words: a mess." +> +> — Larry Brooks, *Story Engineering* (2011), Introduction + +() + +中文转译(中文适配):写作者在动笔之前做的故事规划越少,给自己挖的坑就越深。太多人甚至意识不到自己已经在坑里,所以退稿信寄来时,他们根本不知道原因。不懂这些基本功、还想照样写的新手呢?更糟。东西从他们脑子里倒出来,基本溅得到处都是。两个词:一团糟。 + +## 核心断言:"凭灵感写" = 用 3-5 稿做规划 + +- "凭灵感写"(pantsing)实际是"用 3-5 稿做故事规划"的另一种说法——你以为在写正文,实际在反复找故事。 +- 草稿不能规划故事,草稿只是把当下脑子里的东西倒出来。 +- 如果你脑子里的东西没结构,倒出来还是没结构。 +- "灵感写作"实际是"用 5 稿重写",极其低效,应该改成"用 30 分钟节拍表 + 1 稿正文"。 + +() + +## 三种工作流 + +1. **Pantser(纯灵感)**:不规划,直接写,写 5+ 稿 +2. **Plotter(按计划)**:节拍表 + outline + 1 稿 +3. **Informed Pantser(知情灵感)**:不写节拍表,但脑中有结构感 + +作者立场:Plotter > Informed Pantser > Pantser(对普通写作者而言)。 + +() + +### 知情灵感的两个条件 + +- 你是 King 那种天才(知道结构但不必写下来) +- 你愿意接受"5 稿重写"的代价 + +两个都不满足,就该老老实实做节拍表。 + +() + +## 操作法 + +- 接受现实:用草稿找故事 = 低效 +- 选:节拍表(30 分钟)vs 5 稿重写(5 个月) +- 多数人应选节拍表 + +() + +## 案例全文 + +### 案例 1:Stephen King — 知情 Pantser + +- **方法**:King 不写节拍表,但他脑中"已知道结构" +- **理由**:King 是天才,已 60+ 年写作,结构内化 +- **结论**:对 King 有效,对普通人无效 +- **警示**:不要学 King,学你 5 年后能成为的他 + +() + +### 案例 2:作者 5 部小说 — Plotter(合并案例) + +同一案例出现在同书两个单元: 案例 2 与 案例 2,同书同案例同角度,按合并规则去重留最全,最全版本落在 references/beat-sheet.md 的"案例 2"(含"1 本年度最佳"与"节拍表 + 6 核 = 高效写作"的验证)。本单元的论点(Plotter 高效:5 部小说都先做节拍表,5 部全出版,1 部 8 周写完)由该案例完整覆盖。 + +(;合并说明为本次合并所加) + +### 案例 3:反例 — 普通 Pantser + +- **问题**:写作者写到第 5 稿还在"找故事" +- **诊断**:用草稿做规划,极度低效 +- **方法**:改用节拍表,1 稿即用 +- **结果**:效率提升 5 倍 + +() + +### 案例 4:反例 — "我没时间规划" + +- **问题**:写作者说"灵感写作才自然,规划扼杀灵感" +- **诊断**:这是"灵感写作"派自我安慰,不是事实 +- **方法**:演示节拍表(30 分钟)效果 +- **结果**:写作者体验后改 Plotter + +() + +## 操作步骤 + +1. **自评:我现在的工作流是什么?** + - 完成标准:用户能说出"我是 Pantser / Plotter / Informed Pantser" + - 提示:看你写第 1 稿前有没有节拍表 +2. **判断:我是 King 吗?** + - 完成标准:用户诚实回答 + - 是(有 60 年写作经验)= 可继续 Pantser + - 不是 = 应转 Plotter +3. **选择:30 分钟节拍表 vs 5 稿重写** + - 完成标准:用户选 1 个 + - 多数人选 30 分钟节拍表 +4. **试用 1 次节拍表** + - 完成标准:用户做 1 稿节拍表(具体做法见本包 references/beat-sheet.md) + - 试用 = 知行 + +(;第 4 步原文指向 workflow-beat-sheet,合并库中即本包 references/beat-sheet.md) + +## 触发场景 + +1. **工作流选择**:"我应该怎么写作?" +2. **卡壳诊断**:"我写到第 5 稿还在'找故事'" +3. **辩论**:"凭灵感写 vs 计划写" +4. **教学**:"我教写作,怎么解释这个" + +语言信号: + +- "灵感写作 / pantsing / organic writing" +- "凭灵感写 / 凭感觉写" +- "plotting / 计划写作 / 大纲" +- "我写不下去 / 我找不到故事" + +() + +## 与相邻方法的区分 + +- **节拍表**:是"具体规划工具"(节拍表本身),见本包 references/beat-sheet.md;本单元是"工作流哲学"(为什么不用 pantsing),两者互补。 +- **故事结构(structure-*)**:是"结构本身",合并库中见综合 skill story-structure,与本单元互补。 + +(;指针为本次合并更新到合并库) + +## 边界 + +### 不要在以下情况使用 + +- 已经是 Plotter,想优化规划(用节拍表,见 references/beat-sheet.md) +- 已经是天才(King 那种)——不需要改 +- 实验性/非结构化写作——节拍表不适用 + +### 作者警告的失败模式 + +- 把"灵感写作"当"自然"——实际是"低效" +- 把"大纲扼杀灵感"当真——大纲是脚手架,不是枷锁 +- 把"知情灵感"当"我也能"——知情灵感需要先"知情"(知道结构) + +### 作者盲点 + +- 假设"结构" = "公式"——实际不是 +- 假设所有写作者都想要"出版"——实验作家可能不在意 +- 假设"高效"是唯一目标——有人享受 5 稿重写的过程 + +### 易混方法论 + +- "Discovery Writing"(不同作家)——类似,但更尊重 Pantser +- "Snowflake Method"——是 Plotter 的一种,1 句扩展 +- "Save the Cat"——接近,但 Snyder 强调"15 节拍" + +() + +## 中文适配 + +- pantsing / plotting 在中文写作圈没有完全对应的固定译法,常见说法是"灵感派/大纲派"或"体验派/规划派";本包译作"纯灵感/按计划/知情灵感",引用原文术语时两个都写。 +- 中文网文日更场景:"想到哪写到哪"地日更就是 pantsing,而且连载里 5 稿重写的代价更高——读者等不起。Brooks 的断言照样成立:开新一卷之前花 30 分钟把这一卷的节拍表列出来,连载比边写边找稳得多。 +- 中文类型小说(悬疑、仙侠、言情)的故事骨架与读者预期绑定更紧,"知情灵感"需要的结构内化程度比 Brooks 描述的更高,新手别走 King 路线。 +- Discovery Writing 在中文写作者中同样存在;Brooks 自己承认它接近自己的立场、只是"更尊重 Pantser",两派分歧主要是姿态,操作上都要先有结构感。 + +(本节为本次合并补充的中文落地说明) diff --git a/framework/catalog/pi/skills/story-planning/references/planning-workflow-checklist.md b/framework/catalog/pi/skills/story-planning/references/planning-workflow-checklist.md new file mode 100644 index 0000000..3bad365 --- /dev/null +++ b/framework/catalog/pi/skills/story-planning/references/planning-workflow-checklist.md @@ -0,0 +1,96 @@ +# 规划工作流台账 + +用法:按篇幅分两条轨道。短篇(5000-30000 字)先做第 1 节自评,再走第 3 节六阶段;长篇或多卷连载用第 2 节节拍表。完稿后的诊断走第 4 节。每节有"过关线",不达标按标注回退。判断标准全部来自本包 references/ 各文件,这里只是填写骨架;方法细节、案例与引文见各节标注的落点。 + +--- + +## 1. 工作流自评(→ references/plan-vs-pantsing.md) + +1. 写第 1 稿之前,你做不做节拍表或任何形式的场景清单? + - □ 做 → 你是 Plotter,本节过关,直接进第 2 节 + - □ 不做,凭感觉写 → 继续往下填 +2. 不写清单,但你"脑中已经能看到结构"吗? + - □ 能 → 知情灵感(Informed Pantser)候选,继续往下填 + - □ 不能 → 纯灵感(Pantser),继续往下填 +3. King 之问:你有几十年写作积累、结构已经内化了吗? + - □ 有 → 可以继续现在的工作流 + - □ 没有 → 应该转 Plotter +4. 二选一:30 分钟的节拍表,对 5 个月的 5 稿重写。我选:____ +5. 承诺:下一部新作/下一卷开写前,先做一次节拍表。□ + +过关线:能说出自己是哪一型;不是 King 就选节拍表。"大纲扼杀灵感"不算不选的理由——大纲是脚手架,不是枷锁。 + +## 2. 节拍表制作与结构校验(→ references/beat-sheet.md) + +### 2.1 准备 + +- 工具(任选其一,要求一眼看到全局):□ 便利贴/码字卡 □ 索引卡 □ 白板 □ Markdown 列表 □ 思维导图/Excel +- 故事:____(新故事 = 写前规划;已有完稿 = Post-draft 诊断) + +### 2.2 列 bullet + +一场景一行,每条必须含两件事: + +| # | 场景任务 mission(1 句:这一场在故事铺陈中做什么,它为什么在那里) | 关键内容(1-2 句) | +|---|---|---| +| 1 | | | +| 2 | | | +| 3 | | | +| … | | | + +数量线:目标 60 条(长篇平均)。多于 100 条 = 故事太长/太散;少于 30 条 = 可能展开不够。当前共 ____ 条。 + +失败自检:□ 没有 bullet 写成了一整段(节拍表一行,大纲一段) □ 没有 bullet 只写内容不写任务(mission 是排序的依据) + +### 2.3 排序与结构校验 + +四箱位置校验(四箱与六里程碑的定义见综合 skill story-structure,这里只当校验槽位): + +| 箱 | 应在位置 | 实际对应的 bullet 编号范围 | 在位? | +|---|---|---|---| +| 布局 Setup | 0-25% | | □ | +| 反应 Response | 25-50% | | □ | +| 进攻 Attack | 50-75% | | □ | +| 解决 Resolution | 75-100% | | □ | + +六里程碑核对(任何缺 = 补 bullet): + +| 里程碑 | 对应 bullet 编号 | 缺? | +|---|---|---| +| 里程碑 1 | | □ | +| 里程碑 2 | | □ | +| 里程碑 3 | | □ | +| 里程碑 4 | | □ | +| 里程碑 5 | | □ | +| 里程碑 6 | | □ | + +### 2.4 修改与转大纲 + +- 列出要动的地方:要改的 bullet ____;要删的 ____;要并的 ____;要重排的 ____ +- 这是全文最廉价的修改阶段:能在这里动的,别留到正文重写。 +- (可选)转大纲:把每条 bullet 扩成一段,就是大纲。□ 已转 □ 不需要 + +过关线:bullet 数量在 30-100 条、每条有 mission、四箱在位、六里程碑不缺。 + +## 3. 短篇六阶段卡壳诊断(→ references/draft-flow.md) + +先回答诊断问题:"你现在的状态是——有想法?在准备?在酝酿?在写?在写完?在重读?"定位到阶段,只做对应行。若"都还没开始",从阶段 1 走。 + +| 阶段 | 过关线 | 判停条件 | +|---|---|---| +| 1 找简单想法 | 能用 1-2 句说出想法;想法简单(坐下来就能完成)且对你有情感价值 | 想写"涵盖整个人生观的长篇" → 缩到"长篇里你最想先写的一个场景";没有情感价值 → 放下换 | +| 2 前期准备(1-2 天) | 能列出 1-3 个主要人物和每人 3-5 个背景细节(长相、教育、家庭、工作、性格) | 标准是"够用"不是"完美":福特要的是"我要知道",不是"我要写到" | +| 3 酝酿(1-3 天) | 承诺"放下 1-3 天,不动笔,让它沉";做梦梦到它是好信号 | "还没准备好"的感觉不要粗暴拒绝,但也不是无限拖延——等"想写"的冲动自然出现 | +| 4 充满信心地写作 | 能给出第一句和最后一句(跳板与降落点) | 想不到好开头就把它放一边、稍后再写,不等完美状态 | +| 5 一气呵成 | 能说出"我 X 时开始,当天 X 点前写完" | 写不完:起身前约定下次时间,形成催眠式连续性;暂停可以,放下别超过几个小时 | +| 6 搁置 + 批评式阅读 | 承诺"写完立刻放一边,至少隔一夜(通常 2-3 天)再重读" | 写完立刻重读 = 必然觉得烂,禁止 | + +四条不可跳自检:□ 准备没跳过(无意识要有素材) □ 酝酿没省略(素材要时间整合) □ 写作没拆成两天(拆了风格割裂) □ 重读没提前(提前必然觉得烂) + +## 4. 完稿后诊断(Post-draft,→ references/beat-sheet.md"两种用法") + +- 从完稿反向列节拍表:实际写出来的每个场景一条 bullet,写清这一场的任务和内容。 +- 逐条对照检查:哪一场没有任务?哪一场位置不对(对照四箱百分比)?哪两场其实该并?哪一场该删? +- 重读和诊断都要在搁置至少一夜之后做,用陌生人的眼光。 + +过关线:能指出具体哪几条 bullet 要改/删/并/重排,而不是只说"故事乱"。 diff --git a/framework/catalog/pi/skills/story-structure/SKILL.md b/framework/catalog/pi/skills/story-structure/SKILL.md new file mode 100644 index 0000000..36e40b4 --- /dev/null +++ b/framework/catalog/pi/skills/story-structure/SKILL.md @@ -0,0 +1,81 @@ +--- +name: story-structure +description: | + 激活场景: 为长篇/中篇小说或剧本搭结构骨架、改稿时做结构诊断、判断开头与关键节点该放在哪、 + 处理"中段塌陷""故事没启动""赌注不升""开头抓不住读者"等结构问题、写前确认短中长篇体裁。 + 关键 trigger: "故事结构 / 四箱 / 三幕 / 6 里程碑 / first plot point / FPP / 第一情节点 / midpoint / 中点 / + 煽动事件 / inciting incident / 触发事件 / Setup 段 / 开篇五件事 / 中段塌陷 / 赌注没升 / up the ante / + 不知道怎么开头 / 想不到第一句 / 开头抓不住读者 / 开头没冲突 / 主角的日常没被打破 / 开头像介绍背景 / + 短中长篇体制 / 主角转主动 / 主角太英雄 / 故事节奏 / pinch point / 夹点 / 故事没启动"。 + 不适用于: 非叙事内容(纯数据/公文)、没有可识别人物主角线的纯设定集、意识流与抒情散文(不靠外部事件推动)、 + 新闻导语与学术摘要类非虚构开头、单场景内的微观写作(归 scene-craft)、作者写作习惯与心理状态(作者培养类)。 + 与 narrative-momentum 交接:「中段塌陷」的结构成因(里程碑/赌注/四箱)归本 Skill;弃读、章末钩子、势链/金币/内悬念归后者。 +--- + +# 故事结构 (story-structure) + +管长篇叙事的结构全链路:先按体裁选对尺子,再搭"四箱 + 六里程碑"骨架,然后把开头、启动、转折逐段放对位置,全程抬升赌注,最后用诊断表改稿。 + +## 方法索引 + +### 动笔之前 + +- **定体制**:短篇、中篇、长篇是三种完全不同的体制,不是长短问题——短篇看"瞬间",中篇看"转折",长篇看"命运",写前先用体制确认表选对尺子。→ references/length-system.md +- **写开头**:想不出完美第一句就跳过,用第一句当跳板、最后一句当降落点,五种开头方法里默认用画面/动作开头。→ references/opening.md + +### 搭整体骨架 + +- **四箱切段**:全篇按功能切成 Setup(0-25%)/Response(25-50%)/Attack(50-75%)/Resolution(75-100%),每段功能不能提前也不能延后。→ references/four-boxes.md +- **六里程碑定点**:在四箱内定六个固定位置的节点(Hook、第一情节点、两个夹点、中点、第二情节点),位置是硬约束,功能比强度重要。→ references/six-milestones.md + +### 写开篇段(0-25%) + +- **Setup 五使命**:Setup 段要完成赌注、共情、背景故事、内在恶魔、钩子加伏笔五件事,缺一件后面 75% 都受影响。→ references/setup.md +- **触发事件与赌注加码**:找一个彻底打破主角生活平衡的瞬间事件(1-15%),之后每 3-5 章把赌注跨维度抬升一级,停在原地故事就死。→ references/inciting-incident.md +- **煽动事件不是第一情节点**:开篇惊天大事只负责点火,赋予意义的时刻留给 25% 处,用三问区分两者。→ references/inciting-vs-fpp.md +- **第一情节点**:25% 处让对抗力量亮相、主角接任务、赌注明确,三条缺一不可,戏剧强度不是标准。→ references/first-plot-point.md + +### 写中段(25-75%) + +- **第二段主角是漫游者**:25-50% 主角只能跑、躲、分析、观察、重算、计划招募,主动对抗和解决问题是禁忌,攒够"做不到"中点转向才有戏。→ references/part2-wanderer.md +- **中点转向**:50%±3% 处让主角从被动转主动,形式可以是觉醒、承诺、新盟友或新赌注,没有中点四箱塌成两箱。→ references/midpoint.md + +## 引用索引 + +| 文件 | 覆盖内容 | +|---|---| +| references/length-system.md | 短中长篇三种体制、各自硬规则、跨体裁转换红线、案例(《杀手》《促织》《红楼梦》《项链》) | +| references/opening.md | 三条铁律、首尾双锚点、五种开头方法及例句、开头失败模式与盲点 | +| references/four-boxes.md | 四箱切段与各段功能、三个分界点、案例(《达·芬奇密码》《末路狂花》)、诊断步骤与边界 | +| references/six-milestones.md | 六里程碑位置表、三组功能、位置硬约束、案例与"应有 vs 实际"诊断 | +| references/setup.md | Setup 段五使命与建议顺序、打勾诊断、案例与篇幅越界问题 | +| references/inciting-incident.md | 触发事件定义与判据、赌注加码楼梯、案例(9/11、《国王的演讲》)、每 3-5 章自检 | +| references/inciting-vs-fpp.md | 煽动事件与第一情节点的区别、三问判断法、操作法、案例(《末路狂花》《借刀杀人》)、Field 术语冲突标注 | +| references/first-plot-point.md | FPP 三必要功能、强度不是标准、位置约束、案例(《末路狂花》《禁闭岛》《达·芬奇密码》) | +| references/part2-wanderer.md | 第二段六类允许动作与三个禁忌、合法例外、案例与巡查步骤 | +| references/midpoint.md | 中点两功能与四种形式、50%±3% 硬约束、三种假中点、案例(《冷山》等) | +| references/_coverage.md | 唯一追溯文件:源单元 → 落点小节与内容对照 | + +## 脚本 + +- references/structure-checklists.md —— 结构诊断工作表:体制确认表、四箱切段表、六里程碑定位与"应有 vs 实际"诊断表、Setup 五使命打勾表、开篇事件三问、FPP 验证表、漫游者巡查表、中点验证表、加码楼梯表与每 3-5 章赌注自检;新稿搭骨架按第 0 节的十步顺序走。 + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 红线 + +- 只给当前创作阶段的建议,不越权改设定主权、不绕过检测链、不复制粘贴其它 Skill 的 owner 定义。 +- 无用户明确授权不得替用户定稿或提交 Git。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/pi/skills/story-structure/references/_coverage.md b/framework/catalog/pi/skills/story-structure/references/_coverage.md new file mode 100644 index 0000000..9fa8c14 --- /dev/null +++ b/framework/catalog/pi/skills/story-structure/references/_coverage.md @@ -0,0 +1,17 @@ +# story-structure 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| becoming-a-writer/fiction-opening | references/opening.md | +| bifeiyu-novel-skill/bifeiyu-system | references/length-system.md | +| story-engineering/structure-first-plot-point | references/first-plot-point.md | +| story-engineering/structure-four-boxes | references/four-boxes.md | +| story-engineering/structure-inciting-vs-plot-point | references/inciting-vs-fpp.md | +| story-engineering/structure-inciting-vs-plot-point | references/inciting-incident.md | +| story-engineering/structure-midpoint | references/midpoint.md | +| story-engineering/structure-part2-wanderer | references/part2-wanderer.md | +| story-engineering/structure-setup-five-missions | references/setup.md | +| story-engineering/structure-six-milestones | references/six-milestones.md | +| writing-tools-clark/inciting-incident | references/inciting-incident.md | diff --git a/framework/catalog/pi/skills/story-structure/references/first-plot-point.md b/framework/catalog/pi/skills/story-structure/references/first-plot-point.md new file mode 100644 index 0000000..b922502 --- /dev/null +++ b/framework/catalog/pi/skills/story-structure/references/first-plot-point.md @@ -0,0 +1,110 @@ +# 第一情节点(First Plot Point)必须在 1/4 位置 + +> 与煽动事件的区别见 `inciting-vs-fpp.md`;Setup 段的五件事见 `setup.md`;它在四箱中的位置见 `four-boxes.md`。 + +## 原文摘录 + +> "The very end of Part 1—the arrival of the First Plot Point moment—is the first full view of the story's primary antagonistic force... the bad guy, if you will. Full doesn't mean that the true nature of the antagonistic force is by any means complete, but rather, it's the first time the hero (and the reader) actually gets a notion of the nature and extent of the opposing force." +> +> — Larry Brooks, *Story Engineering* (2011), Part 5 + +## 方法骨架 + +First Plot Point(FPP)是故事的"启动时刻"——对抗力量亮相, 主角接到任务, 故事从 Setup 进入 Response。FPP 必须在 25% 位置(硬约束)。 + +**FPP 的 3 个必要功能**: +1. **对抗力量亮相**: 读者第一次完整看到主要对抗力量是什么 +2. **主角接任务**: 主角被推向新方向(新目标/新身份/新威胁) +3. **赌注明确**: 读者知道"主角将失去什么/获得什么" + +**3 个功能缺一不可**。最常见的失败: 主角接任务了, 但对抗力量没亮相(读者不知道威胁); 或对抗力量亮相了, 但主角没接任务(角色是被动地卷入)。 + +**FPP 的"戏剧强度"不是标准**: +- FPP 可以是"对话"(Thelma 的"我们跑吧") +- FPP 可以是"微妙"(Shutter Island 的幽灵耳语) +- FPP 可以是"动作"(大爆炸、追车) +- **关键是功能, 不是强度** + +**位置约束**: +- 小说 300-400 页: FPP 在 75-100 页 +- 剧本 110 页: FPP 在 25-30 页 +- 短篇: 单场景, FPP 几乎立刻 +- 不可偏离 25%±3% 太多 + +## 书中案例 + +### 案例 1: Thelma & Louise(《末路狂花》)的 FPP +- **位置**: 31 分钟(剧本 110 页的 28%)——略晚, 接近 25% +- **形式**: 只是一段对话, "我们不回头" +- **功能**: 对抗力量(警长追捕)亮相 + 主角接任务(亡命天涯)+ 赌注(自由 vs 监狱)明确 +- **关键**: 不是杀人事件(19:30, 太早), 而是"决定跑" + +### 案例 2: Shutter Island(《禁闭岛》)的 FPP +- **位置**: 88/369 页(24%)——几乎完美 +- **形式**: 幽灵般的耳语 "Laeddis is here" +- **功能**: 对抗力量(主角的疯狂)亮相 + 任务(找到 Laeddis)明确 +- **关键**: 戏剧强度极低, 但功能完整 + +### 案例 3: The Da Vinci Code(《达·芬奇密码》)的 FPP +- **位置**: 约 100/454 页(22%)——略早 +- **形式**: Saunière 死后, Langdon 收到神秘信息 +- **功能**: 对抗力量(神秘组织)亮相 + 任务(解读信息)明确 +- **关键**: 戏剧动作(杀人)是 inciting, FPP 是"主角接任务" + +### 案例 4: 反例——FPP 缺失 +- **问题**: 写作者写到 25% 还没让主角接任务 +- **方法论的使用**: 诊断发现: FPP = 0 +- **结论**: 故事没启动, 读者 25% 时还不知"主角要做什么" +- **结果**: 增补 FPP 场景, 故事节奏改善 + +## 可执行步骤 + +1. **找出当前 FPP** + - 完成标准: 用户能指认 1 个 FPP 候选场景 + - 提示: 找"主角接到新任务/新身份/新威胁"的瞬间 +2. **验证 3 个功能** + - 完成标准: 3 问全 yes + - 对抗力量亮相了吗? + - 主角接任务了吗? + - 赌注明确了吗? +3. **验证位置** + - 完成标准: 在 25%±3% 范围 + - 偏早(20% 之前)= Setup 段不足 + - 偏晚(30% 之后)= Setup 段过满, Response 段被压缩 +4. **强度判断(不是标准)** + - 完成标准: FPP 可以弱强度, 关键功能到位 + - 不要因为"不够精彩"就重写一个更"大"的 +5. **修稿建议** + - 完成标准: 给出 1-2 个具体改写方案 + +## 边界 + +### 不要在以下情况使用 + +- 已经在区分 inciting 和 FPP(用 `inciting-vs-fpp.md`) +- 整体 4 箱诊断(用 `four-boxes.md`) +- 多 POV 故事——每个 POV 独立诊断 + +### 作者警告的失败模式 + +- 把"开篇大事件"当 FPP——大事件往往是 inciting +- 把"主角第一次行动"当 FPP——行动 ≠ 接任务 +- 把"对抗力量完美解释"当 FPP——FPP 只需"亮相", 不需完整解释 + +### 作者盲点 + +- FPP 默认"主对抗力量"——反派小说 FPP 是反派的对手亮相 +- 假设 FPP 是"动作场景"——实际常是对话/决策 +- 假设 FPP 必须"大"——强度不是标准 + +### 易混方法论 + +- "Inciting Incident"(Field)——是 FPP 之前的引子, 不是 FPP 本身(注意 Field 与本用法的术语冲突,见 `inciting-vs-fpp.md` 的术语冲突说明) +- "Inciting Incident"(不同书)——概念混用, 本书用法不同 +- "Catalyst"(Story Grid)——接近, 但 Story Grid 给了更多功能要求 + +## 中文落地(中文适配) + +- 位置按字数换算:30 万字长篇的 FPP 落在 6.6 万-8.4 万字(25%±3%,即 22%-28%);网文黄金三章是商业例外,FPP 常被压到前 3 章内,此时要检查 Setup 五使命是否被挤掉(见 `setup.md` 的中文适配)。 +- 中文小说里 FPP 常以"对话/消息/一封信"的形式出现(家书、密令、讣告、师门传讯),强度低没关系,三功能齐全即可——与 Shutter Island 的耳语同理。 +- 武侠/仙侠的"灭门惨案"常发生在开篇:它是 inciting,不是 FPP;主角在约四分之一处"决意复仇/拜师学艺/下山追查"的那场戏才是 FPP。 diff --git a/framework/catalog/pi/skills/story-structure/references/four-boxes.md b/framework/catalog/pi/skills/story-structure/references/four-boxes.md new file mode 100644 index 0000000..023212a --- /dev/null +++ b/framework/catalog/pi/skills/story-structure/references/four-boxes.md @@ -0,0 +1,111 @@ +# 四箱结构:Setup / Response / Attack / Resolution + +> 长篇(及电影剧本)的宏观骨架。箱内的具体节点见 `six-milestones.md`。 + +## 原文摘录 + +> "You are always either setting something up, responding to what you've set up, attacking the problem, or resolving the problem. The available resources of concept, character, and theme are there to make those four phases of the story dramatic and meaningful." +> +> — Larry Brooks, *Story Engineering* (2011), Part 5 + +## 方法骨架 + +整本小说/剧本/电影, 按功能可切成 4 个 25% 段落, 各自有唯一功能。这是故事工程的"物理定律"——任何故事都必然经过这 4 段, 跨段功能错位 = 故事错。 + +**4 段的功能**: + +| 段 | 位置 | 功能 | 主角状态 | +|---|---|---|---| +| Setup | 0-25% | 建立赌注/角色/伏笔/钩子 | 孤儿, 无任务 | +| Response | 25-50% | 对 First Plot Point 的反应/摸索 | wanderer, 被动 | +| Attack | 50-75% | 主动进攻/觉醒/翻转局势 | attacker, 主动 | +| Resolution | 75-100% | 收束/高潮/主题兑现 | 完成或失败 | + +**关键洞察**: +- 4 段不是"4 幕", 是"2 个 50%(Setup+Response / Attack+Resolution)各 2 段" +- 25% / 50% / 75% 是硬约束——非到 1/4 不给任务, 非到 1/2 不觉醒 +- 每段功能**不能提前**或**不能延后**——Setup 段让主角"接任务" = 错位 +- 段内是"任务驱动"——每段内 1 个主要戏剧任务, 配合次要情节 + +**2 段分界点的功能**: +- **First Plot Point (25%)**: Setup → Response, 对抗力量亮相, 任务下达(详见 `first-plot-point.md`) +- **Midpoint (50%)**: Response → Attack, 主角从被动转主动(详见 `midpoint.md`) +- **Second Plot Point (75%)**: Attack → Resolution, 重大反转/最后信息, 给高潮充能 + +**为什么是 4 箱不是 3 幕**: +- 3 幕隐含 Setup 是 50%, 但 Setup 段只能 25%(否则 Attack 段没戏) +- 4 箱 = 2 幕各 2 段, 更精确 + +## 书中案例 + +### 案例 1: The Da Vinci Code(《达·芬奇密码》) +- **Setup (0-25%)**: Langdon 在卢浮宫被告知 Saunière 谋杀, 不知道为何被追 +- **Response (25-50%)**: 整段跑, 不知道谁在追, 不知道为什么 +- **Attack (50-75%)**: Midpoint 后他开始反击, 用符号学破解密码 +- **Resolution (75-100%)**: 找到圣杯真实位置, 揭露阴谋 +- **4 段都对位, 节奏紧凑** + +### 案例 2: Thelma & Louise(《末路狂花》) +- **Setup**: 0-25%, 两位主角日常, 酒吧偶遇 +- **First Plot Point (25%)**: 杀人 + 决定跑(31 分钟) +- **Response**: 25-50%, 整段跑, 警长在追 +- **Midpoint (50%)**: 决定不停下来, 加速跑 +- **Attack**: 50-75%, 主动决策(抢劫便利店/对抗警察) +- **Resolution (75-100%)**: 飞车冲下悬崖 +- **完美的 4 箱应用** + +### 案例 3: 反例——Setup 段过满 +- **问题**: 写作者 1/4 段就把对抗力量全面展开 +- **方法论的使用**: 诊断发现: 4 箱错位——Setup 段 50% 工作量 +- **结论**: Attack 段没戏, Resolution 段仓促 +- **结果**: 改稿时让 Setup 段回到 25%, 把"全面展开"移到 Response 段 + +## 可执行步骤 + +1. **把故事切成 4 段** + - 完成标准: 用户能说"我的故事, Setup 是 0-25%, Response 25-50%, Attack 50-75%, Resolution 75-100%" + - 用页数或场景数 +2. **验证每段功能** + - 完成标准: 4 段都过如下检查: + - Setup: 主角接任务了吗?(没 = 正确) + - Response: 主角主动攻击了吗?(没 = 正确) + - Attack: 主角主动进攻了吗?(是 = 正确) + - Resolution: 故事收束了吗?(是 = 正确) +3. **诊断错位** + - 完成标准: 任何"过早"或"过晚"都被列出 + - 例: "主角在 20% 就接了任务"(太早)或 "主角在 60% 还在 wanderer"(太晚) +4. **修结构(用节拍表工具)** + - 完成标准: 列出每段内的关键场景(1-3 个) + - 工具: 节拍表(规划工作流 skill story-planning 的 beat-sheet 方法) + +## 边界 + +### 不要在以下情况使用 + +- 中短篇/flash fiction——4 箱不适用, 单场景或单弧线(体裁判断见 `length-system.md`) +- 群像小说 / 多 POV——4 箱框架对每个 POV 独立使用 +- 实验性叙事(倒叙/非线性)——4 箱的"时间顺序"假设被打破, 需调整 + +### 作者警告的失败模式 + +- 4 箱不均分——25% 是平均值, 实际可 20%/30%/30%/20% 微调 +- 把 4 箱当死规则——文学/实验小说可有意打破 +- 忽略次要情节——次要情节可有自己的 4 箱, 但不可跨主情节 + +### 作者盲点 + +- 4 箱基于商业小说/好莱坞结构——欧洲艺术电影/日本文学不适用 +- 默认"线性时间"——非线性小说需重新理解 +- 默认"单一 POV"——多 POV 需对每个 POV 独立 4 箱 + +### 易混方法论 + +- "Three-Act Structure"(Field/Syd)——是粗略版, 4 箱是其细化 +- "Save the Cat 15 Beats"(Snyder)——是 4 箱内 15 个固定节拍 +- "Hero's Journey 12 Stages"(Campbell/Vogler)——是原型模式, 不是结构框架 + +## 中文落地(中文适配) + +- 中文长篇小说没有"页"的概念,位置按**字数比例**换算:30 万字的长篇,25% ≈ 7.5 万字,50% ≈ 15 万字,75% ≈ 22.5 万字;章回体可按回数换算(120 回的 25% = 第 30 回)。 +- 网络小说的"卷"不保证与 25% 对齐:诊断时以字数比例为准,不要硬把分界点塞到卷边界;若某卷恰好跨越分界点,检查功能落在哪一章即可。 +- 群像章回体(如多线并进的家族小说):对每条主角线独立做一次四箱,与本书"多 POV 独立四箱"同理。 diff --git a/framework/catalog/pi/skills/story-structure/references/inciting-incident.md b/framework/catalog/pi/skills/story-structure/references/inciting-incident.md new file mode 100644 index 0000000..1ebcf54 --- /dev/null +++ b/framework/catalog/pi/skills/story-structure/references/inciting-incident.md @@ -0,0 +1,130 @@ +# 触发事件与赌注加码:把故事启动并不断升级 + +> 触发事件与第一情节点的区别见 `inciting-vs-fpp.md`;第一情节点本身见 `first-plot-point.md`。 + +## 原文摘录 + +> The inciting incident, writes McKee in his book *Story*, radically upsets the balance of forces in +> the protagonist's life. … While the inciting incident is crucial, the big bang that propels the story, +> it is never enough. The writer must raise the stakes for the main characters—in gambling slang, must +> "up the ante." +> +> — Roy Peter Clark, *Writing Tools* (Tool 55) + +## 方法骨架 + +### 触发事件(inciting incident)是什么 + +Clark 借编剧理论家 Robert McKee 的定义:触发事件是一个**具体的瞬间事件**,**彻底打破**主角原有的生活平衡(McKee 原话:"radically upsets the balance of forces in the protagonist's life")。 + +- **位置**: 通常出现在故事的 5-15%(第一幕内, 常在第 1 章末),是"故事真正开始"的那一秒钟。Brooks 的补充:它可以在 Setup 段任何位置,通常早于 25%,可以是开篇 1-5 页内。 +- **判断标准**: 能否用一句话回答"故事是从哪一天、哪一秒钟开始的"? 答不上来 = 故事还没启动。 +- **戏剧强度**: 极高——爆炸、死亡、发现、失踪。 +- **功能**: 引起紧张, 暗示有事要发生;**不**赋予"意义/任务/赌注"——赋予意义是 25% 处第一情节点的工作。 +- **必须是事件, 不是状态**: "主角渐渐意识到 X" / "主角慢慢长大"是状态变化, 不是事件,要改写为一个**具体动作**(接到电话 / 推门发现 / 错过末班车)。 +- **反直觉点**: 触发事件不一定是坏事,也可以"看似正面"——中奖、获赠、奇遇,都可能"be careful what you wish for",把主角推入更大的麻烦。 + +两家的关系说法:没有 inciting = 故事开局无聊;Inciting 是"火",第一情节点是"开始扑火"。 + +### 加码(up the ante) + +赌博隐喻。**触发事件只是大爆炸,不够**;之后每一段时间(每章 / 每幕 / 每 1/4 体量)必须**升高赌注**。 + +- 赌注从"个人尴尬"→"家庭危机"→"国家命运"这样**逐级抬升**;若停在原地,故事就死。 +- 触发事件是**单点**、加码是**序列**;两者必须同时存在,只做一半故事都会塌。 + +**Clark 的工作口诀**:先找到那一刻(定位 inciting incident),再数清楚从那一刻起发生了**几次赌注升级**(画出 ante 的台阶),最后自检——最近 3-5 章里赌注是否真的升了? + +### 画加码楼梯 + +- 从触发事件之后开始,列出"赌注升高的节点",列 5-7 级,每级用一句"从 X 升级到 Y"。 +- 每升一次,问:"这次比上次严重在哪?(范围更大? 代价更不可逆? 涉及更多人? 时限更短?)" +- 升级必须**跨维度**——个人 → 家庭 → 社群 → 公众 → 国家 → 文明;只升"压力"不升"维度"(每次都是"主角更焦虑了",全是个人内心戏),到 1/2 处读者已麻木。 +- 若"第 3 级 = 第 2 级"——这就是 ante 没升,故事在原地打转,需**重新设计赌注维度**(从"个人尴尬"升到"家庭破裂"升到"公众事件"升到"国家危机")。 + +## 书中案例 + +### 案例 1: Robert McKee《Story》——触发事件的"理论锚点" +- **问题**: 编剧圈内部已经用"inciting incident"几十年,但新闻和非虚构作者不熟悉这个概念。 +- **方法论的使用**: Clark 直接引用 McKee 的定义("radically upsets the balance of forces in the protagonist's life"),把"打破平衡"作为触发事件的**可操作判据**;并配上 Dorothy / 龙卷风的通俗例子,让非虚构读者也能秒懂。 +- **结论**: 理论锚 + 通俗例 = 把专业编剧概念降维到长篇小说作者可用。 +- **结果**: Clark 借 McKee 把"故事如何启动"从"凭感觉开篇"变成"可定位的事件",Tool 55 因此成为全书 55 个工具里**结构层**最重的一支。 + +### 案例 2: 9/11 +《The King's Speech》——触发事件 + 5 级加码 +- **问题**: 怎样把"触发 + 加码"的双层机制在一篇文章里同时演示? +- **方法论的使用**: + - **触发事件(单点)**: Clark 写自己 2001 年 9 月 11 日早上在 Florida 看 *Today Show* 的那一刻——Matt Lauer 突然被打断、第二架飞机撞入南塔——"A bolt from the blue. The inciting incident of our lifetimes." + - **加码(连续)**: Clark 列出 9/11 之后十年"赌注如何被持续抬高"——机场搜身、阿富汗伊拉克战争、刑讯、监听、经济衰退、移民和穆斯林被污名化、奥巴马击毙本·拉登;从"震惊"一路抬到"国家制度被撼动"。 + - **电影对照**: Clark 用《The King's Speech》(《国王的演讲》)给出**5 步加码时间表**——父亲去世(1) → 哥哥退位(2) → 希特勒上台(3) → 希特勒用 radio(4) → 新国王必须 radio 演讲(5)——"from a mild form of personal humiliation at the beginning, to the fate of the nation at the end." +- **结论**: 同一个故事,触发事件是**单点**、加码是**序列**;两者必须同时存在,只做一半故事都会塌。 +- **结果**: 9/11 段落成为 Clark 讲"触发事件力量"的金案例;《King's Speech》5 步列表成为"如何画 ante 楼梯"的标准范本。 + +### 触发事件的范例(Brooks 一侧) + +- 《末路狂花》(Thelma & Louise): 19:30 酒吧杀人事件——戏剧强度极高,但它只是煽动,不是第一情节点。 +- 《借刀杀人》(Collateral): 开场出租车顶掉下一具尸体——极高强度的煽动事件。 +- 反例:写"开篇 1 页主角父亲被谋杀"并立即把它当第一情节点用,等于故事启动过早,Setup 段被挤掉(详见 `inciting-vs-fpp.md` 案例 3)。 + +## 可执行步骤 + +1. **定位触发事件(给故事找出"那一刻")** + - 让用户用一句话回答:"你的故事是从哪一天、哪一秒钟、哪一个事件开始的?" + - 检验该事件是否**符合 McKee 定义**:"radically upsets the balance of forces in the protagonist's life"——即主角的日常**真的**被打碎了,不是"生活里出了一点小麻烦"。 + - 完成标准: 用户能用一句话定位一个**具体、可识别的瞬间事件**,且该事件前后主角生活平衡**可对比**(前: 稳定 / 后: 被打破)。 + - 判停条件: 若用户的"触发事件"其实是"主角慢慢长大" / "主角渐渐觉醒"——这是状态变化,**不是事件**,需改写为一个**具体动作**(接到电话 / 推门发现 / 错过末班车)。 +2. **列出加码时间表(画出 ante 的楼梯)** + - 从触发事件之后开始,让用户列出"赌注升高的节点"——每升一次,问:"这次比上次严重在哪?(范围更大? 代价更不可逆? 涉及更多人? 时限更短?)" + - 套用《King's Speech》模板: 列 5-7 步,每步用一句"从 X 升级到 Y"。 + - 完成标准: 一份**按时间顺序**的加码表,**至少 5 级**;每一级比上一级**赌注更高**(可量化: 影响范围 / 不可逆程度 / 时间压力 / 涉及角色数)。 + - 判停条件: 若用户的加码表里"第 3 级 = 第 2 级"——这就是 ante 没升,故事在原地打转,需让用户**重新设计赌注维度**(从"个人尴尬"升到"家庭破裂"升到"公众事件"升到"国家危机")。 +3. **每 3-5 章自检赌注(中段不塌陷的保险机制)** + - 写完每 3-5 章,问用户:"最近这段的赌注,比 3-5 章前更高吗? 如果删掉这段,故事会失去什么?" + - 若"删掉这段不影响赌注"——这段就是"中段塌陷"的元凶,需要**重写或删除**。 + - 完成标准: 用户能在每个 3-5 章节点**自证赌注升级**;若不能,需触发一次"加码回炉"。 + - 判停条件: 若整本书只有"开篇 + 结尾"两次赌注,中间是平的——这是中段塌陷的典型结构,**必须**插入至少 2-3 个中间加码点(可借助"be careful what you wish for"——新获得的东西变成新威胁)。 + +空白表格见 `../references/structure-checklists.md` 的"加码楼梯表"与"每 3-5 章赌注自检"。 + +## 边界 + +### 不要在以下情况使用 + +- **短篇集**——每篇独立成章,不需要"贯穿全书的加码楼梯";用每篇独立的 hook 即可。 +- **意识流 / 散文 / 抒情独白**——这类作品的目标是"内省流动",不靠外部事件推动;"打破平衡"的标准不适用。 +- **纯设定型世界观(无主角线)**——如 worldbuilding wiki、设定集——没有"主角生活平衡"可打破。 +- **没有可识别人物的非虚构**(纯数据报告 / 政策白皮书)——"主角"概念不成立。 +- **同一事件的多个视角重写**——触发事件已经发生(既定事实),加码方法论不适用;视角与呈现方式改用电影化视角/镜头距离(见场景执行 skill scene-craft)或细节马赛克(见人物呈现 skill character-presentation)。 + +### 作者在书中警告的失败模式 + +- **开篇没触发事件**——失败模式: 长篇在开篇就"建立世界"但**不打破平衡**——读者不知道"故事在解决什么问题"因而弃读。信号: 第一章读完,主角的生活和第一章前**完全一样**。机制: 人脑的注意力是**问题驱动的**——没有"问题"就没有"想知道答案"的拉力。 +- **中段没加码**——失败模式: 开篇有触发,但从 1/4 体量开始赌注不再升高,情节原地打转,读者在 2/3 处弃读。信号: 把 1/3 和 2/3 的章节互换位置,故事不受影响——意味着中间没变化。 +- **触发事件不"事件化"**——失败模式: 把触发写成"主角渐渐意识到 X" / "主角慢慢长大"——这是**状态变化**,不是**事件**;读者无法"看到"那一秒,因而无从感受"打破平衡"。 +- **加码只升"压力"不升"维度"**——失败模式: 每次加码都是"主角更焦虑了",但赌注的**类型**没变(全是个人内心戏);到 1/2 处读者已麻木。修正: 加码必须**跨维度**——个人 → 家庭 → 社群 → 公众 → 国家 → 文明(参照《King's Speech》5 步)。 + +### 作者的盲点 / 时代局限 + +- Clark 写于 2006 年(英文版),主要讲**新闻 + 电影剧本**——对**长篇小说**的迁移需要适配: + - 电影剧本的触发事件常在**前 10 页**,长篇小说常在**5-15% 体量**;若照搬"开篇立刻爆发"会牺牲长篇必要的"日常建立"——Clark 没给这个"延迟"提供明确指引。 + - Clark 引用 McKee 的例子(Dorothy、Rudolph、King's Speech)几乎都是**单人主角 + 单线情节**;对**多视角长篇**、**群像小说**、**POV 切换**结构里的"多个触发事件"如何对齐,Tool 55 没说。 + - 中文网络长篇特有的"卷 / 章回 / 阶段奖励"结构,与"每 3-5 章加码"的节奏**不完全一致**——需让用户自己调整加码频率。 + +### 容易混淆的邻近方法论 + +- **与"故事引擎"(Clark Tool 31)的混淆**: 那个管"贯穿全书的核心问题/叙事燃料"——是一根**持续燃烧的轴**;本条管"启动 + 升级"——是**第一下点火**和之后**每次加油**。前者是"为什么读到最后",后者是"为什么第一章要翻过去 + 为什么中段不弃读"。诊断: 若问题指向"故事动力" / "核心问题" / "不知道写什么",先找概念与前提类 skill(concept-design);若指向"故事从哪一秒开始" / "中段为什么没劲" / "赌注怎么升",用本条。 +- **与"金币"的区别**: "金币"方法管"沿途给读者的奖励"(小钩子、小反转、小爽点),是**回报侧**;本条管"赌注本身升高",是**压力侧**。一个让读者"想继续看",另一个让读者"不敢不看"。(两者都在叙事动力 skill narrative-momentum。) +- **与"段内悬崖"的区别**: "段内悬崖"方法管"段末钩子"——单章 / 单场景的**局部**悬念;本条管**全局赌注**——从开篇到结尾的**宏观**升级。前者是"章末转折",后者是"全书走势"。 +- **与"契诃夫之枪"的区别**: "契诃夫之枪"管"道具埋设和回收"——是**物件线**;本条管"事件链和赌注台阶"——是**事件线**。一个回答"这把枪什么时候响",另一个回答"为什么这一枪越打越响"。(伏笔类见 foreshadow-payoff。) +- **与"主线推进"的混淆**: 主线推进 = 情节往前走;触发事件 + 加码 = 情节**越走越危险**。前者可以平推,后者必须有台阶感。 + +### 组合使用(跨域指针) + +- **与伏笔与回收 skill(foreshadow-payoff)组合**: 加码可借助"埋下但延迟爆炸的物件"。 +- **与结尾设计 skill(story-ending)组合**: 加码的最后一级就是"为结尾蓄势"。 +- **与叙事动力 skill(narrative-momentum)组合**: 加码的章节里塞段末钩子。 + +## 中文落地(中文适配) + +- 网文的"卷 / 章回 / 阶段奖励"结构与"每 3-5 章加码"不完全一致:落地时按**卷定大台阶、按章定小台阶**——每卷赌注升一个维度(门派 → 江湖 → 朝堂 → 天下),卷内每 3-5 章升一次压力;阶段奖励(升级、夺宝)可以充当加码的可见刻度。 +- 电影剧本式"前 10 页爆发"照搬到中文长篇会牺牲日常建立;中文长篇的触发事件放在 5-15% 体量时,前段用 Setup 五使命(见 `setup.md`)填实。网文连载是例外:黄金三章把触发事件压到第 1-3 章,属于商业节奏对位置的合法改写。 +- "好事变坏事"(be careful what you wish for)在中文语境里对应常见的"奇遇反噬"开局:中奖、得传承、入仙门,开局是好事,随后把主角推入更大麻烦——用法与 Clark 所述一致。 diff --git a/framework/catalog/pi/skills/story-structure/references/inciting-vs-fpp.md b/framework/catalog/pi/skills/story-structure/references/inciting-vs-fpp.md new file mode 100644 index 0000000..90d4a16 --- /dev/null +++ b/framework/catalog/pi/skills/story-structure/references/inciting-vs-fpp.md @@ -0,0 +1,109 @@ +# 煽动事件 ≠ 第一情节点:开篇大事件和故事启动是两回事 + +> 触发事件的定义与加码见 `inciting-incident.md`;第一情节点单点深入见 `first-plot-point.md`。 + +## 原文摘录 + +> "The shooting happens at 19:30, too soon to be a functioning First Plot Point. But very right-on-the-mark as an inciting incident. An inciting incident, yes, because it does incite what happens next. It's huge, a total game-changer. But only when something else happens, something that does meet the criteria by imparting meaning to it—by defining the journey and challenge that lies ahead for the heroes—does it become a legitimate Plot Point." +> +> — Larry Brooks, *Story Engineering* (2011), Part 5 + +## 方法骨架 + +"开篇惊天大事"和"第一情节点"是两个不同概念, 在结构上不同位置、不同功能。混淆是新手最常见的错误。 + +**Inciting Incident(煽动事件)**: +- **位置**: Setup 段任何位置, 通常早于 25% +- **戏剧强度**: 极高(爆炸、死亡、发现、失踪) +- **功能**: 引起紧张, 暗示有事要发生 +- **不**赋予"意义/任务/赌注" +- 可以是开篇 1-5 页内 + +**First Plot Point(第一情节点)**: +- **位置**: 25%(硬约束) +- **戏剧强度**: 可高可低(Thelma 是对话, Shutter Island 是耳语) +- **功能**: 赋予意义——主角接任务/对抗力量亮相/赌注明确 +- **不**必是惊天大事 + +**两者的关系**: +- Inciting 可以早于 FPP 出现, 也可以重合 +- Inciting 是"火", FPP 是"开始扑火" +- 没有 inciting = 故事开局无聊 +- 没有 FPP = 故事没启动 + +**常见错误**: 写作者写了"开篇大事件", 以为这就是 FPP, 结果 25% 位置空了, 故事后半部分动力不足。 + +**操作法**: +- 写一个开篇大事件(inciting)——在 1-15% +- 留出"读者不知道这意味着什么"的时间(10-15%) +- 在 25% 给主角"接任务"瞬间(FPP) + +## 书中案例 + +### 案例 1: Thelma & Louise(《末路狂花》)——完美分离 +- **Inciting (19:30)**: 酒吧杀人事件——戏剧强度极高 +- **FPP (31:00)**: 决定跑——戏剧强度中等(只是对话) +- **两件事相距 11 分钟** = 演示分离 +- **关键**: 杀人是"煽动", 决定是"赋予意义" + +### 案例 2: Collateral(《借刀杀人》)——早 inciting + 延迟 FPP +- **Inciting (开场)**: 出租车顶掉下一具尸体——极高强度 +- **FPP (~25%)**: 坏人坐到后座, 告诉司机今晚的"任务" +- **两件事相距近 25%** = 极致延迟 +- **关键**: 尸体是"煽动", 任务是"赋予意义" + +### 案例 3: 反例——inciting 当 FPP +- **问题**: 写作者写了"开篇 1 页主角父亲被谋杀", 之后花 30% 找凶手 +- **方法论的使用**: 诊断 = FPP 提前到 1%, 故事启动过早 +- **结论**: 主角立即接任务 = Setup 段(建立赌注/共情/伏笔)没了 +- **结果**: 改稿: 把"父亲被谋杀"移到 5%, 让主角在 25% 才"接任务" + +## 可执行步骤 + +1. **找出开篇大事件** + - 完成标准: 用户能指认 1 个开篇"大事件" + - 提示: 通常在 1-15% +2. **判断它是 inciting 还是 FPP** + - 完成标准: 用 3 问 + - 它赋予"任务/意义"吗?(yes = FPP, no = inciting) + - 它在 25% 位置吗?(yes = 可能是 FPP, no = inciting) + - 戏剧强度极高?(yes = 倾向 inciting) +3. **如果只有 inciting 没有 FPP** + - 完成标准: 在 25% 处设计 FPP + - FPP = 主角的"决策/任务/意义"瞬间 + - 可以弱强度, 必须明确意义 +4. **如果只有 FPP 没有 inciting** + - 完成标准: 故事开头会无聊 + - 增补开篇钩子(Hook)或小事件 + +## 边界 + +### 不要在以下情况使用 + +- 写非叙事内容 +- 中短篇/flash fiction——经常 inciting=FPP(短篇体制见 `length-system.md`) +- 多 POV 故事——每个 POV 独立诊断 + +### 作者警告的失败模式 + +- 把"开篇大事件"和 FPP 必然当成"1 个事"——可以是 2 个事 +- 把 inciting 拖到 25% 之后——故事无聊 +- 跳过 inciting 直接到 FPP——读者"不知道为什么" + +### 作者盲点 + +- 假设 inciting 必是"动作"——也可以是"发现"(一封信/一张照片/一个电话) +- 假设 FPP 必是"决策"——也可以是"信息"(知道某真相) +- 假设 inciting=FPP 是错的——实际上常常是错的 + +### 易混方法论与术语冲突(规则冲突,都保留) + +- **"Inciting Incident"(Field/Syd Field)**——用法不同, Field 当 FPP 用。**注意冲突**:同一个词,Field 指的是 Brooks 所说的第一情节点;Clark/McKee 所说的 inciting incident 才是 Brooks 所说的煽动事件。用哪家的词,就要看哪家的定义,先确认对方用哪把尺子。 +- **"Catalyst"(Story Grid)**——接近 FPP +- **"Call to Adventure"(Campbell)**——是原型术语, 位置更灵活 + +## 中文落地(中文适配) + +- 中文类型小说(悬疑、刑侦、仙侠)习惯"开篇命案/开篇灭门",这正是 inciting 前置的写法;诊断时照样问三问——命案发生在 1-5% 是合格的煽动事件,但要确认 25% 处另有一场"赋予意义"的戏(主角正式接下追查/复仇/入局的任务),否则后程动力不足。 +- 章回体里"楔子 + 正书"的结构天然支持分离:楔子常承担 inciting(大事件),正书前若干回完成 Setup,第一情节点落在正文约四分之一处。 +- 短篇里 inciting 常与 FPP 重合:中文微型小说、小小说不必强拆成两个事件。 diff --git a/framework/catalog/pi/skills/story-structure/references/length-system.md b/framework/catalog/pi/skills/story-structure/references/length-system.md new file mode 100644 index 0000000..08a41ad --- /dev/null +++ b/framework/catalog/pi/skills/story-structure/references/length-system.md @@ -0,0 +1,130 @@ +# 短中长篇是三种体制——动笔前先选对尺子 + +> 这是结构工作的第一步:体裁定错了,后面所有结构工具都用错尺子。 + +## 原文摘录 + +> 「短篇小说、中篇小说、长篇小说是三个完全不同的体制,而不是小说的长短问题。」 +> ——《小说课》 + +毕飞宇在《故乡》分析中说: + +> “短篇小说由于篇幅的缘故,它是不允许[人物性格发育]的。” +> ——《小说课》 + +**关键洞察**:短篇/中篇/长篇不是"长度不同",是**体制不同**——它们有完全不同的运行规则。 + +## 三种体制的核心差异 + +| 维度 | 短篇 | 中篇 | 长篇 | +|-----|------|------|------| +| 人物数量 | 1-3 | 3-10 | 10+ | +| 性格发育 | 不允许 | 部分允许 | 必须 | +| 时间跨度 | 单一场景/瞬间 | 几天-几年 | 跨代 | +| 核心技法 | 冰山/反常/铺垫 | 性格转折 | 命运+复调 | +| 容忍度 | 极精微 | 中等 | 容忍粗线条 | +| 读者注意力 | 1-2 小时 | 半天 | 几天 | + +一句话判据: + +> **短篇看"瞬间",中篇看"转折",长篇看"命运"。** +> ——《小说课》 + +## 书中案例 + +### 案例 1:海明威《杀手》——短篇典范 + +- 五个人物,**全部用瞬间切片**呈现 +- 没有人物"前史"——只有当下 +- 短篇的"刀光剑影"在长篇里是**灾难**(会拖垮节奏) + +### 案例 2:蒲松龄《促织》——1700 字的"微小说" + +- 一家人、几件事、一个小孩变蛐蛐 +- **不允许性格发育**——成名就是"迂讷",没有"为什么迂讷" +- 用"两次寻死"代替了"人物心理转变" + +### 案例 3:曹雪芹《红楼梦》——长篇的反面教材 + +> 「读《红楼梦》如果你只读过一遍,和没读也没什么两别。」 + +毕飞宇承认《红楼梦》作为长篇"太精微了"——**短篇的精微用在长篇上是负担**。 + +### 案例 4:莫泊桑《项链》——短篇的标准结构 + +> 「凤头、猪肚、豹尾」 + +开头漂亮(借项链)、中间丰满(十年艰辛)、结尾有力(项链是假的)——**典型短篇结构**。 + +## 什么时候想到这条方法(触发场景) + +1. 你开始写一个文本前——先确认体裁 +2. 你被"卡住"了——可能用错了体裁的尺子 +3. 你想从短篇扩成长篇——这是**改写**,不是扩写 +4. 你评价别人的小说——先看体裁 +5. 你读不懂一部小说——可能你用错体裁的阅读方式 + +## 可执行步骤 + +### 步骤 1:写之前先定体裁 + +```yaml +我要写的: + 体裁:[短篇 / 中篇 / 长篇] + 核心人物数:[N] + 时间跨度:[N] + 核心技法:[冰山/铺垫/反常/性格发育/复调/命运] + 读者注意力预算:[X 小时] +``` + +### 步骤 2:短篇的硬规则 + +- **人物 ≤ 3**(含次要) +- **场景 ≤ 5**(含过渡) +- **时间 ≤ 24 小时** 或 单一回溯 +- **必须有 1 个反常事件**(短篇不靠性格发育,靠"反常"推动) +- **结尾必须有冲击**(豹尾) + +### 步骤 3:中篇的硬规则 + +- 人物 3-10 +- **必须有一个明确的"性格转折"** +- 时间跨度可以放宽 +- 可以分章节,但节奏要紧凑 +- 短篇技法(冰山、铺垫)依然适用,但要"摊薄" + +### 步骤 4:长篇的硬规则 + +- **必须有人物"命运"**(性格的累积变化) +- 短篇技法**不可照搬**——精微处要少用 +- 允许"粗线条" +- **复调**(多线并进)是长篇的特权 +- "延宕"是长篇的核心能力 + +### 步骤 5:跨体裁转换的红线 + +- 短 → 长:**加人物、加时间、加命运**——不是把句子写长 +- 长 → 短:**做减法**——只保留最核心的 1-2 个场景 +- 任何 → 短:**检查反常点**——短篇必须有它 + +## 边界与常见错误 + +### 适用边界 + +- **适用于**虚构叙事(小说为主) +- **部分适用**剧本(电影是"长篇"逻辑,单集剧是"短篇"逻辑) +- **不适用**纯散文、纯抒情诗 + +### 常见错误 + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 用短篇的精微写长篇 | 读者累、节奏拖 | 长篇允许"粗" | +| 用长篇的篇幅写短篇 | 拖沓、肿瘤 | 短篇必删到 5000-15000 字 | +| 中篇用短篇的人物密度 | 平面、单薄 | 中篇必须有"性格转折" | +| 长篇用中篇的命运刻度 | 不够深 | 长篇命运要"沉" | + +## 与其他结构方法的关系 + +- 本条是**框架性方法**:本 skill 其余方法(四箱、六里程碑、Setup 五使命等)都是长篇(及电影剧本)工具;中短篇不可整套照搬,短篇里触发事件常与第一情节点重合。短篇只取"触发事件 + 反常 + 豹尾"。 +- 跨域指针:长篇才有人物"命运"可言 → 见 character-presentation(人物命运);短篇铺垫极简、长篇铺垫可以是一整章 → 见 foreshadow-payoff;短篇的冰山在长篇要"摊薄" → 见 show-and-omission。 diff --git a/framework/catalog/pi/skills/story-structure/references/midpoint.md b/framework/catalog/pi/skills/story-structure/references/midpoint.md new file mode 100644 index 0000000..ee1c0e6 --- /dev/null +++ b/framework/catalog/pi/skills/story-structure/references/midpoint.md @@ -0,0 +1,104 @@ +# 中点(Midpoint):主角从被动转主动的那堵墙 + +> 中点之前主角必须是漫游者(见 `part2-wanderer.md`);中点在四箱与六里程碑中的位置见 `four-boxes.md`、`six-milestones.md`。 + +## 原文摘录 + +> "In Part 3, though, the hero begins to try to fix things. That's the context of this quartile—to become proactive and downright courageous and ingenious in the quest to attain the goal. The hero starts to conquer inner demons and begin doing things a little differently than before, or at least come to understand how they have been standing in his own way. That the hero needs to change if he is to succeed. In Part 3 the hero summons courage and applies creative thinking." +> +> — Larry Brooks, *Story Engineering* (2011), Part 5 + +## 方法骨架 + +Midpoint(50%)是故事的"墙"——Part 2 结束, Part 3 开始。Midpoint 之前, 主角是 wanderer(反应/摸索); Midpoint 之后, 主角是 attacker(主动进攻)。 + +**Midpoint 的 2 个核心功能**: +1. **主角心态转向**: 从"反应"变"主动"——主角开始"做"而不是"被做" +2. **新信息/觉醒/承诺**: 通常伴随一个"新认识"或"决心" + +**Midpoint 的常见 4 种形式**: +- **觉醒**: 主角明白自己一直错了(例如知道真相) +- **承诺**: 主角做出不可逆的承诺(例如"我要回故乡") +- **新盟友**: 主角获得新力量/新信息/新朋友 +- **新赌注**: 主角面对更大的威胁, 决心升级 + +**Midpoint 不是"故事过半的某个点"**, 是"主角本质的转变"。 + +**位置约束**: +- 50% ± 3%(硬约束) +- 偏早(45% 之前)= Response 段太短 +- 偏晚(55% 之后)= Attack 段太短 + +**没有 Midpoint = 故事平铺直叙 = 4 箱变 2 箱。** + +## 书中案例 + +### 案例 1: The Da Vinci Code(《达·芬奇密码》) +- **Midpoint (~50%)**: Langdon 和 Sophie 在某个关键发现后, 决定不再跑, 主动反击 +- **形式**: 承诺 + 新信息 +- **效果**: 之后 Langdon 开始主动破译密码、对抗神秘组织, 不再"被追" + +### 案例 2: Thelma & Louise(《末路狂花》) +- **Midpoint (~50%)**: 两位主角的对话"我们不回头了" +- **形式**: 承诺 +- **效果**: 之后她们开始主动决策(抢劫、对抗警察), 不再只跑 + +### 案例 3: Cold Mountain(《冷山》) +- **Midpoint (~50%)**: Inman 决定回家, 面对漫长旅程 +- **形式**: 承诺 +- **效果**: 旅程从"被动求生"变"主动回家" + +### 案例 4: 反例——Midpoint 缺失 +- **问题**: 写作者写完, 故事中段平 +- **方法论的使用**: 6 里程碑扫描发现: Midpoint 缺失 +- **结论**: 主角没有"从被动转主动"瞬间, 整部平 +- **结果**: 增补一个"主角觉醒/承诺"场景, 故事张力立现 + +## 可执行步骤 + +1. **找 Midpoint 候选** + - 完成标准: 用户能指认 1 个"主角变主动"的瞬间 + - 提示: 找"主角开始做决定"或"主角觉醒"瞬间 +2. **验证 2 个功能** + - 完成标准: + - 主角心态/行为转向了吗?(是 = 通过) + - 有新信息/觉醒/承诺吗?(是 = 通过) +3. **验证位置** + - 完成标准: 在 50% ± 3% 范围 + - 偏早(45% 之前)= Response 太短 + - 偏晚(55% 之后)= Attack 太短 +4. **如果缺失或偏离** + - 完成标准: 列出 1-2 个改写方案 + - 增补 Midpoint: 找 Part 2 结尾 + Part 3 开头的"主角觉醒"瞬间 + +## 边界 + +### 不要在以下情况使用 + +- 整体 6 里程碑诊断(用 `six-milestones.md`) +- 检查 Part 2 角色状态(用 `part2-wanderer.md`) +- 多 POV 故事——每个 POV 独立诊断 + +### 作者警告的失败模式(三种假中点) + +- 把"反派大动作"当 Midpoint——反派动 = 主角被动, 不是主角主动 +- 把"主角小胜利"当 Midpoint——胜利不是心态转向 +- 把"信息揭示"当 Midpoint——没有主角"用这个信息做事" = 不是 Midpoint + +### 作者盲点 + +- 假设 Midpoint 是"觉醒"——承诺/新赌注/新盟友也有效 +- 假设 Midpoint 后立即"开打"——Attack 段还可能再 wander 几次, 再开打 +- 假设 Midpoint = 1 个场景——可能是跨 2-3 个场景的"段" + +### 易混方法论 + +- "Midpoint"(Save the Cat)——略不同, Snyder 给的是"假胜利/真失败" +- "Midpoint Reversal"(不同书)——接近, 但强调"反转" +- "Hero's Journey: The Abyss"——类似, 但更神秘化 + +## 中文落地(中文适配) + +- 位置按字数换算:30 万字长篇的中点在 14.1 万-15.9 万字之间;章回体按回数折算(120 回的第 57-63 回)。 +- 中文叙事传统里的中点常以"誓言/明志"场面呈现——歃血为盟、当众立誓、决意下山、撕毁休书——对应四种形式中的"承诺";检查时仍看两功能:心态是否从被动转主动、是否有新信息或不可逆决心。 +- Setup 段暗示过的"内在恶魔"在此处开始被克服(原文摘录引文:"conquer inner demons"):中文长篇里对应主角的心结、旧伤、执念在中点前后被正面处理,这条因果链要在 Setup 就埋好(见 `setup.md` 使命 4)。 diff --git a/framework/catalog/pi/skills/story-structure/references/opening.md b/framework/catalog/pi/skills/story-structure/references/opening.md new file mode 100644 index 0000000..72355e0 --- /dev/null +++ b/framework/catalog/pi/skills/story-structure/references/opening.md @@ -0,0 +1,188 @@ +# 落笔写开头:不等完美第一句,用首尾两句当路标 + +> 讲"怎么写下第一句"的写作姿态与技术。Setup 段该完成哪些功能使命见 `setup.md`,开篇该放什么事件见 `inciting-incident.md` 与 `inciting-vs-fpp.md`。 + +## 原文摘录 + +> “现在, 立即开始写作。就像你自己进行第六章里的时间练习一样, +> 不要找任何借口, 拒绝任何居场的感觉, 只是开始写作。 +> 如果想不到一个好的开头, 就把它放在一边, 稍后再写。 +> 尽可能快地写, 对你自己的写作过程留意的越少越好, +> 尽量轻松而快速地工作, 开始和结束一个句子都要清晰有力。 +> 要减少重读的次数, 只时不时地读一两个句子, 以确保你在正确的轨道上。 +> 你开始写作之前, 把故事的第一句话和最后一句确定下来, +> 你会发现这非常有好处。这样你就可以用第一句作为跳板, 延伸你的故事, +> 用最后一句作为降落点。” +> +> —— 多萝西娅·布兰德,《成为作家》第十四章 + +## 方法骨架:3 条铁律 + 2 个锚定技术 + 5 种开头方法 + +### 3 条铁律(开头的反直觉规则) + +**铁律 1: 不要"等完美开头"** +- 想 30 分钟没想出好开头? **先跳过, 稍后再写** +- 你想出来的"好开头"通常是"陈词滥调"(因为它在脑内已经想得太久, 已经俗了) +- 真正的好开头, 是在**写中**涌现的, 不是在**想中**涌现的 + +**铁律 2: 立即开始** +- 就像固定写作时间纪律的"4 点必须写"一样 +- 不要"等准备好了" +- 拒绝"居场的感觉"(那种想拖延的感觉) + +**铁律 3: 减少重读** +- 写的时候, 只时不时读 1-2 个句子, 确认方向 +- **不要每写一句就回看**——那是无意识的杀手 +- 流畅 > 完美, 一气呵成 > 字字打磨 + +### 2 个锚定技术(开头不迷路的方法) + +**锚定 1: 确定"第一句"** +- 第一句 = 跳板, 让你"有地方开始" +- 不需要是"完美的第一句", 只需要是"够用的第一句" +- 标准: 这一句**已经**把读者带进故事——不是介绍背景, 是**进入画面** + +**锚定 2: 确定"最后一句"** +- 最后一句 = 降落点, 让你"知道要去哪" +- 写之前**先想好**这一句, 整个故事会"奔向"它 +- 关键: 最后一句**不是结尾的转折**(那是常见误区), 是**最后一个画面/声音/动作** +- 标准: 这一句**已经**让读者感到"完结"——不是问题被解决, 是**故事在这个时刻停住** + +**两个锚点的协同** +- 第一句 + 最后一句 = 一条路 +- 中间无论怎么写, 都不跑题 +- 这就是布兰德的"路标"技术 + +### 5 种开头方法(布兰德散落各章) + +**方法 1: "画面/动作"开头**(推荐, 最常用) +- 第一句就是一个**具体的画面**: “她在雨里跑了三十分钟。” +- 不是介绍, 是"你看到了什么" +- 适用于: 几乎所有小说 +- 优点: 立即把读者拉进故事 + +**方法 2: "对话"开头**(第 8 章强调) +- 第一句就是角色在说话 +- “'你来了,' 她说。” +- 适用于: 人物关系重要的故事 +- 优点: 立即建立声音, 暗示冲突 +- 风险: 读者不知道谁在说话, 可能困惑——配合"是谁"的指示 + +**方法 3: "声音/感官"开头**(第 14 章暗示) +- 第一句是一个声音/气味/触感 +- “走廊里有什么东西在动。” +- 适用于: 悬疑/惊悚/感官小说 +- 优点: 立即建立"在场"感 + +**方法 4: "反常/惊讶"开头**(第 12 章反例, 慎用) +- 第一句是一个反常/惊讶的事 +- “我母亲昨天死了。但我不哭。” +- 适用于: 想立刻建立张力 +- 风险: **容易落入"令人吃惊的结尾"陷阱**(第 12 章警告)——为"原创"而原创, 反而失真 + +**方法 5: "日常"开头**(第 11 章暗示) +- 第一句就是日常, 但日常中有"不寻常" +- “那个星期三的早餐和往常一样, 除了她在咖啡里加了盐。” +- 适用于: 慢热/心理小说 +- 优点: 反衬张力 + +### 5 种开头方法的选用 + +- 不确定用什么? **默认用方法 1(画面/动作)** +- 故事以人物关系为主? 用方法 2(对话) +- 想立刻建立紧张? 用方法 3(声音/感官)或方法 4(反常) +- 慢热/心理小说? 用方法 5(日常) + +### 与"开头"相关的"结尾"反例(第 12 章) + +布兰德的反例: 不要为"原创"而写"令人吃惊的结尾"——那是**为原创而原创**, 人物行为失真。 +- 正确: 结尾是**人物会做的事**, 不是作者强加 +- 错误: 结尾是"出乎意料", 但人物**不会**那样做 + +## 书中案例 + +### 案例 1: 布兰德的"路标"技术 +- **问题**: 写到一半不知道自己在写什么 +- **方法论的使用**: 动笔前确定"第一句 + 最后一句" +- **结论**: 这两个锚点让中间不跑题 +- **结果**: 故事能写完, 且不散 + +### 案例 2: 福特的"前期准备" +- **问题**: 不知道人物会做什么 +- **方法论的使用**: 前期准备"知道"一切(即使不写到) +- **结论**: 写起来, 第一句/最后一句自然涌现 +- **结果**: 开头不会"卡", 因为素材充足 +- 前期准备的完整流程见规划工作流 skill(story-planning)。 + +### 案例 3: 海明威的"日常+反常"开头 +- **问题**: 想写"一个人很痛苦" +- **方法论的使用**: 海明威的《永别了, 武器》开头: “那年晚秋, 我们住在乡村一所木屋里...” +- **结论**: 日常中藏反常, 不直说痛苦 +- **结果**: 比直接说"他很痛苦"有力 10 倍 + +## 可执行步骤 + +1. **诊断: 用户卡在哪里** + - 完成标准: 用户能说出"我卡在 5 种开头方法的哪个 / 不知道用哪种 / 写出来不满意" + - 提问: "你现在的问题是——(a) 想不到第一句? (b) 想出来但不满意? (c) 写出来但抓不住读者?" + - 判停条件: 若用户说"我不知道写什么故事" → 先解决写什么的问题(规划工作流 story-planning 的起点阶段) +2. **拒绝"等完美开头"** + - 完成标准: 用户承诺"先写一个'够用'的开头, 之后再改" + - 关键: 布兰德的反例: 等完美开头 = 永远写不完 +3. **帮用户选 5 种开头方法之一** + - 完成标准: 用户能说"我用方法 X 开头" + - 默认推荐: 方法 1(画面/动作)——最通用 + - 提问: "你希望读者第一眼看到什么? 听到什么? 知道什么?" +4. **确定"第一句 + 最后一句"两个锚点** + - 完成标准: 用户能写出第一句和最后一句 + - 关键: 不需要完美, 需要"够用" + - 第一句标准: 让读者**进入画面**, 不是介绍背景 + - 最后一句标准: 让读者感到**完结**, 不是"问题解决" +5. **立即动笔, 不要回看** + - 完成标准: 用户承诺"写完一段不回看, 只时不时看 1-2 句" + - 关键: 流畅 > 完美 +6. **写完后, 不要立即重读** + - 完成标准: 写完后立刻放一边, 至少隔一夜再看 + +## 边界 + +### 不要在以下情况使用 + +- **用户不知道写什么**——先解决写什么(规划工作流 story-planning 的起点阶段) +- **写非虚构开头**(新闻导语/学术摘要)——那是 lead/abstract 技术, 不同领域 +- **写诗/散文**——开头逻辑不同, 不必"路标" +- **写剧本**——剧本开头是场景/角色, 不是叙事 +- **用户已经能流畅写开头**——这是基础技术, 不是优化 + +### 作者在书中警告的失败模式 + +- **等完美开头**: 等"完美" / 等"最后智慧" → 永远等不到 +- **模仿风格**: 模仿别人的"开头风格"——永远追不上 +- **写完就删**: 写完开头立刻重读, 觉得"开头不行" → 删 +- **模仿别人的题材**: 因为别人用过某开头很成功, 你就跟着用 +- **公开宣告**: 写之前跟朋友讲"我想到一个超棒的开头" → 招来评判 + +### 作者的盲点 / 时代局限 + +- **1934 年的"小说"偏严肃文学**——类型小说(悬疑/科幻/言情)的开头逻辑有差异 +- **不区分"章节开头" vs "故事开头"**——短篇只有 1 个开头, 长篇每章都有, 方法不同 +- **没考虑"网文"形态**——网络连载的"开篇三章"(黄金三章)有其商业规律 +- **"反常开头"的"反常陷阱"**——布兰德警告过, 但没给出"怎么判断反常是否合理"的方法 +- **不区分"第一人称" / "第三人称"**——视角影响开头 + +### 容易混淆的邻近方法论 + +- **"钩子"(Hook, 新闻业)**——类似机制, 但"钩子"是为快速消费设计, 小说更复杂 +- **"黄金三章"(网文)**——是商业规律, 不是文学规律 +- **"冷开场" vs "暖开场"**——是技术分类, 不是布兰德的分类 + +### 组合使用(跨域指针) + +- **与对话写作 skill(dialogue-craft)组合**: 方法 2(对话开头)的延伸——本条管"用对话写第一句",贯穿全文的对话整体技术归 dialogue-craft。 +- **与场景执行 skill(scene-craft)组合**: 方法 1(画面/动作开头)的延伸——第一句进画面之后,场景如何展开执行归 scene-craft。 + +## 中文落地(中文适配) + +- 布兰德的五种开头方法对中文小说同样适用,例句本身已是中文语境;中文开篇另有"闲笔起兴"的传统(先写环境再入人事),落到方法上等同于方法 5(日常开头)的变体,判断标准不变:第一句要把读者带进画面,不是交代设定。 +- 网络连载小说的"黄金三章"是商业规律而非文学规律:它要求把本条的"第一句进画面"与 Setup 段的钩子使命(见 `setup.md`)、触发事件(见 `inciting-incident.md`)一起压缩到前三章。方法本身不变,变的是完成时限。 +- 长篇每章都有开头:本条的"路标"技术用于全书的第一句和最后一句;章节开头另算,可复用五种方法,但每章第一句优先服务"进入画面",不重复交代背景。 diff --git a/framework/catalog/pi/skills/story-structure/references/part2-wanderer.md b/framework/catalog/pi/skills/story-structure/references/part2-wanderer.md new file mode 100644 index 0000000..80dbc89 --- /dev/null +++ b/framework/catalog/pi/skills/story-structure/references/part2-wanderer.md @@ -0,0 +1,110 @@ +# 第二段(25-50%):主角必须是漫游者(wanderer) + +> 这一段结束于中点,中点见 `midpoint.md`;四箱全局见 `four-boxes.md`。 + +## 原文摘录 + +> "In Part 2 the hero is running, hiding, analyzing, observing, recalculating, planning, recruiting, or anything else required before moving forward. If you have your hero being too heroic here, being brilliant, already knocking heads with the bad guys (or some other dark force), it's too early. You're in violation of structural principles if that's the case." +> +> — Larry Brooks, *Story Engineering* (2011), Part 5 + +## 方法骨架 + +Part 2(25-50%)主角必须是 **wanderer**——反应/摸索/分析/学习/试错, 不是主动进攻。这是 Response 段的功能, 也是为 Midpoint 的转向蓄力。 + +**Part 2 主角的 6 个允许动作**: +1. **Running**: 跑 +2. **Hiding**: 躲 +3. **Analyzing**: 分析局势 +4. **Observing**: 观察敌人 +5. **Recalculating**: 重新计算计划 +6. **Planning/Recruiting**: 计划/招募盟友 + +**Part 2 主角的 3 个禁忌动作**: +1. **Knocking heads with the bad guys**: 主动对抗 +2. **Solving the problem**: 解决问题 +3. **Being brilliant**: 突然变聪明 + +**为什么**: +- Midpoint 的转向才有戏剧张力——需要 Part 2 累积"做不到" +- Part 2 主角主动 = Midpoint 无事可转 = 故事平 +- 主动过早 = Attack 段没戏 + +**何时破坏(合法的例外)**: +- 极小主动(例: 主角试 1 次, 失败) +- 主动只是"局部"(例: 解决小障碍, 不解决大冲突) +- 主动为 Midpoint 服务(例: 失败后觉醒) + +## 书中案例 + +### 案例 1: The Da Vinci Code(《达·芬奇密码》)——完美 Part 2 +- **位置**: 25-50% +- **主角动作**: 跑、躲、分析、不知所以 +- **关键**: 整段 Langdon 不知道谁在追、为什么被追 +- **效果**: 累积"做不到" = Midpoint 转向有戏 + +### 案例 2: Thelma & Louise(《末路狂花》)——Part 2 +- **位置**: 25-50% +- **主角动作**: 跑、躲、被警长追 +- **关键**: 整段她们只是跑, 没有主动决策 +- **效果**: 累积"逃不掉" = Midpoint 决定"不回头"有戏 + +### 案例 3: 反例——Part 2 主角太英雄 +- **问题**: 写作者在 30% 位置, 主角已经打败 1 个反派、破解 1 个谜题 +- **方法论的使用**: 诊断 = Part 2 越界, 主动过早 +- **结论**: Attack 段(50-75%)没戏, 故事结构错 +- **结果**: 把"主角打败反派"移到 55%+, 让 Part 2 真正 wanderer + +## 可执行步骤 + +1. **找 Part 2 关键场景** + - 完成标准: 用户能列出 3-5 个 25-50% 段的关键场景 +2. **检查每个场景的主角动作** + - 完成标准: 每个场景主角动作属于 6 个允许动作之一 + - 不在 6 个允许动作 = 越界 +3. **检查主角是否"主动"** + - 完成标准: 主角是否在做"主动进攻"类动作?(打怪/破案/解决冲突) + - 主动 = 越界, 需移到 Part 3 +4. **检查"局部主动"的合法性** + - 完成标准: 如果有主动, 是否满足: + - 极小主动? 或 + - 主动只是"局部"(小障碍)? 或 + - 主动为 Midpoint 服务(失败后觉醒)? +5. **改稿建议** + - 完成标准: 把越界场景移到 Part 3, 或改成"局部主动" + +空白巡查表见 `../references/structure-checklists.md` 的"漫游者巡查表"。 + +## 边界 + +### 不要在以下情况使用 + +- 整体 4 箱诊断(用 `four-boxes.md`) +- 检查 Midpoint(用 `midpoint.md`) +- 群像/POV 切换——每个 POV 独立 + +### 作者警告的失败模式 + +- 把"主角思考"当"主动"——思考是分析, 属于允许 +- 把"主角反击"当"wanderer"——反击 = 主动, 越界 +- 把"主角解决小障碍"当"小主动"——解决 = 主动, 即使"小"也算 + +注意上面两处的关系:合法例外允许的是**不碰核心冲突的局部主动**(解决小障碍、试一次就失败、为中点觉醒服务的失败);失败模式警告的是把"解决了障碍"误标成不算主动——局部主动本身仍是主动,只有满足三条之一才合法。 + +### 作者盲点 + +- 假设 Part 2 全是"反应"——实际上主角可以"招募盟友/收集信息"等主动准备 +- 假设 Part 2 不能有任何进展——可以有"小进展", 但不能"主问题进展" +- 假设 1 个 POV——多 POV 故事, 每个 POV 在自己 Part 2 是 wanderer + +### 易混方法论 + +- "Rising Action"(Freytag)——是 Part 2 的一部分, 但更强调"上升" +- "Complications"(Field)——类似, 但 Field 不分 2 段 +- "Hero's Journey: Tests"(Campbell)——是原型, 不是结构 + +## 中文落地(中文适配) + +- 武侠/仙侠的"逃亡学艺段"是天然的 Part 2:主角被追杀、隐姓埋名、观察仇家、拜师练功(招募盟友/收集信息属于允许动作);若在这一段就让主角手刃仇家,等于把 Attack 提前,中点后无戏可写。 +- 悬疑刑侦的"排查走访段"对应 wanderer:分析线索、观察嫌疑人、重新计算推理都属允许;"提前锁定并制服真凶"是禁忌动作,要移过中点。 +- 网文连载要注意:读者追更压力常逼作者让主角在第二段就"打脸反杀",这正是本条诊断的"30% 打败反派"越界;若确需爽点,用合法例外——小障碍可以解决,核心对手必须留到中点之后。 diff --git a/framework/catalog/pi/skills/story-structure/references/setup.md b/framework/catalog/pi/skills/story-structure/references/setup.md new file mode 100644 index 0000000..2c994a9 --- /dev/null +++ b/framework/catalog/pi/skills/story-structure/references/setup.md @@ -0,0 +1,112 @@ +# Setup 段(0-25%)的五件事 + +> 开篇的写作姿态(怎么写第一句)见 `opening.md`;开篇该放的大事件见 `inciting-incident.md`;Setup 段结束处的情节点见 `first-plot-point.md`。 + +## 原文摘录 + +> "Five Missions for the Set Up of Your Story: Establish the stakes before the antagonistic force arrives. Establish character empathy. Define your hero's backstory enough for the reader to understand who he is now. Hint at the inner demons. Deliver a hook and foreshadow the forthcoming conflict." +> +> — Larry Brooks, *Story Engineering* (2011), Part 5 + +## 方法骨架 + +Setup 段(0-25%)不是"开始讲故事", 是"完成 5 件事"。任何 1 件缺失, Setup 段都不完整, 后面 75% 都受影响。 + +**5 大使命**: + +1. **建立赌注(Establish Stakes)**: 在对抗力量到来之前, 让读者知道"主角会失去什么/获得什么" + - 为什么: 没有赌注 = 读者不关心 +2. **建立角色共情(Establish Character Empathy)**: 让读者同情/理解/认同主角 + - 为什么: 没有共情 = 读者不在乎主角死活 +3. **给出够用的背景故事(Define Backstory Enough)**: 解释"主角为什么是现在这样", 不必全背景 + - 为什么: 读者需要 1-2 个"原来如此"的点 +4. **暗示内在恶魔(Hint at Inner Demons)**: 不全说, 但暗示"主角有更深的问题" + - 为什么: 内在恶魔是 Midpoint 转向的引擎, 早暗示才有意义(中点见 `midpoint.md`) +5. **钩子 + 伏笔(Hook + Foreshadow)**: 开篇悬念 + 暗示未来的冲突 + - 为什么: 没钩子 = 读者放下书; 没伏笔 = 高潮是"突然" + +**5 件事的顺序不一定**, 但都在 Setup 段内完成。 + +**常见错误**: +- 5 件事都做了, 但 Setup 段超过 25%(塞太多故事) +- 5 件事没做完, 但已经到 25%(Setup 段太薄) +- 5 件事做完, 但顺序乱(建议顺序: stakes → empathy → backstory → inner demons → hook/foreshadow) + +## 书中案例 + +### 案例 1: The Da Vinci Code(《达·芬奇密码》) +- **Stakes (10%)**: Langdon 著名的符号学家身份, 失去 = 学界地位 +- **Empathy (5-10%)**: Langdon 温文尔雅, 关心人 +- **Backstory (5-15%)**: Langdon 离婚后孤僻, 不擅长面对情感 +- **Inner Demons (10-20%)**: Langdon 害怕神秘/超自然事物(与天主事工对应) +- **Hook (1%)**: 开篇就是 Saunière 死后场景 +- **Foreshadow (10-25%)**: 警察紧逼 + 神秘人盯梢 +- **5 件事都到位** + +### 案例 2: Thelma & Louise(《末路狂花》) +- **Stakes (5-15%)**: Louise 的男友问题, Thelma 的丈夫问题 +- **Empathy (5-15%)**: 两位主角都是"被困住"的女人 +- **Backstory (5-15%)**: Thelma 长期被控制, Louise 早年创伤 +- **Inner Demons (10-20%)**: 各自的不安全感 +- **Hook (1%)**: 开篇对话"我们出去玩吧" +- **Foreshadow (15-25%)**: 酒吧里男人的危险暗示 +- **5 件事都到位** + +### 案例 3: 反例——缺 Stakes +- **问题**: 写作者写完 Setup 段, 读者反馈"不知道这本书讲什么" +- **方法论的使用**: 5 使命检查, 发现 Stakes 缺失 +- **结论**: 读者不知道"主角会失去什么" = 不关心 +- **结果**: 增补 Stakes 场景, 读者开始投入 + +## 可执行步骤 + +1. **把 Setup 段标出来** + - 完成标准: 用户能说出 0-25% 段 +2. **逐项检查 5 件事** + - 完成标准: 5 件事都有 yes/no 答案 + - Stakes: 读者知道主角会失去什么吗? + - Empathy: 读者同情主角吗? + - Backstory: 读者知道主角为什么是现在这样吗? + - Inner Demons: 读者感觉到主角有更深的问题吗? + - Hook/Foreshadow: 读者被吸引 + 感觉到未来冲突吗? +3. **统计 + 诊断** + - 完成标准: 5 全 yes = 通过 + - 4 yes = 还行, 但弱项要补 + - ≤ 3 yes = Setup 段没完成, 需改稿 +4. **改稿建议** + - 完成标准: 列出"缺哪件 + 怎么补" + - 补法: 在合适位置加 1-3 段 + +空白打勾表见 `../references/structure-checklists.md` 的"Setup 五使命打勾表"。 + +## 边界 + +### 不要在以下情况使用 + +- 整体 4 箱诊断(用 `four-boxes.md`) +- 检查 FPP 单点(用 `first-plot-point.md`) +- 中短篇(5 件事压缩, 不全适用, 体裁判断见 `length-system.md`) + +### 作者警告的失败模式 + +- 5 件事都做完, 但 Setup 段超过 30%——Setup 段功能完整, 但越界 +- 5 件事全 yes, 但读者反馈不行——可能其他 4 箱问题 +- 顺序乱, 但顺序不影响功能——顺序不是硬约束, 但建议 stakes/empathy 先做 + +### 作者盲点 + +- 5 件事假设"先 Setup 后剧情"——部分文学/实验小说可在 Setup 段就开打 +- 5 件事假设"主角 1 个"——群像/POV 切换需对每个主角各做 1 次 +- 5 件事假设"读者关心"——实际读者可能不关心, 需 1-2 个"反讽/惊喜"钩 + +### 易混方法论 + +- "Opening Hook"(不同作家)——只是 5 件事中的 1 件 +- "First Scene"(Save the Cat)——接近, 但 Snyder 只强调 1 个 hook +- "Inciting Incident"——是 5 件事完成后的"启动", 不是 Setup 段本身 + +## 中文落地(中文适配) + +- 网络连载的"黄金三章"相当于把五件事压缩进前三章:赌注和共情必须最先完成(读者决定去留就在前两章),背景故事拆成碎屑随事件带出,不能集中交代——中文读者对"介绍式背景"的耐受比英文商业小说更低。 +- 中文传统小说习惯先交代身世家门(如章回体的"话说某人,祖居某地"),这是把 backstory 前置的写法;用本条检查时,要确认它没有挤掉赌注和共情的位置,且内在恶魔的暗示仍在 Setup 段内完成。 +- 群像长篇(家族小说、多主角):对每个主角各做一遍五使命检查,与本书"群像各做一次"的盲点提醒同理。 diff --git a/framework/catalog/pi/skills/story-structure/references/six-milestones.md b/framework/catalog/pi/skills/story-structure/references/six-milestones.md new file mode 100644 index 0000000..8663890 --- /dev/null +++ b/framework/catalog/pi/skills/story-structure/references/six-milestones.md @@ -0,0 +1,126 @@ +# 六大里程碑:在四箱之内定点 + +> 四箱是"段",里程碑是段内的固定"点"。宏观分段见 `four-boxes.md`,单点深入见 `first-plot-point.md`、`midpoint.md`。 + +## 原文摘录 + +> "In a 110-page screenplay, they show up at roughly pp. 1, 25, 37, 55, 75, 85, and 110. The same proportions apply to longer works, scaled accordingly. These are the dramatic milestones that anchor the structure: Hook, First Plot Point, First Pinch Point, Midpoint, Second Pinch Point, Second Plot Point, Resolution." +> +> — Larry Brooks, *Story Engineering* (2011), Part 5 + +## 方法骨架 + +在 4 箱之内, 故事有 6-7 个**固定位置**的关键节点。每个节点有特定功能, 位置偏离 = 结构错。 + +**6 大里程碑 + 1 终点**: + +| # | 名称 | 位置 | 功能 | +|---|---|---|---| +| 1 | Hook | 0-5% | 开篇钩子, 引起悬念 | +| 2 | First Plot Point (FPP) | ~25% | 对抗力量亮相, 主角接到任务 | +| 3 | First Pinch Point | ~37% | 提醒对抗力量仍存在 | +| 4 | Midpoint | ~50% | 主角从被动转主动 | +| 5 | Second Pinch Point | ~62% | 再次提醒对抗力量 | +| 6 | Second Plot Point (SPP) | ~75% | 重大反转/最后信息, 高潮充能 | +| 7 | Resolution | 95-100% | 故事收束 | + +**6 大里程碑的 3 组功能**: +- **激励组(Hook, FPP)**: 启动故事, 给任务 +- **推进组(Pinch, Midpoint, Pinch)**: 持续施压, 维持张力 +- **兑现组(SPP, Resolution)**: 收束故事, 主题兑现 + +**关键洞察**: +- 6 个里程碑是**位置**约束(硬约束), 不是内容约束 +- 每个里程碑的**功能**比**戏剧强度**重要——First Pinch 可以是"对话", 强度低但功能必须 +- 缺任何一个 = 故事功能缺失——没 Hook = 读者不读; 没 FPP = 故事没启动; 没 Midpoint = 主角没成长; 没 SPP = 高潮是"开挂" +- 多 1 个都不行——6 个里程碑各做 1 件事, 多 1 个 = 抢戏 + +**应用**: +- 诊断任何小说/剧本: 找这 6 个位置 +- 改稿: 移动里程碑到正确位置 +- 写新稿: 先定 6 个里程碑, 再展开 + +## 书中案例 + +### 案例 1: Thelma & Louise(《末路狂花》)的 6 里程碑 +- **Hook (0-5%)**: 两位主角无聊日常, 决定出去玩 +- **First Plot Point (25%, 31 分钟)**: 决定跑 +- **First Pinch Point (37%)**: 警察找到他们 +- **Midpoint (50%)**: 决定不停下来 +- **Second Pinch Point (62%)**: FBI 介入, 升级追捕 +- **Second Plot Point (75%)**: 警长给最后通牒 +- **Resolution**: 飞车冲下悬崖 +- **完美对齐 6 里程碑** + +### 案例 2: The Da Vinci Code(《达·芬奇密码》)的 6 里程碑 +- **Hook**: Langdon 被叫到卢浮宫(5 页) +- **FPP (25%)**: Saunière 留下神秘信息, Langdon 跑 +- **First Pinch**: 警察开始怀疑 Langdon +- **Midpoint**: Sophie 找到关键密码, Langdon 决定反击 +- **Second Pinch**: 神秘组织开始追 Langdon +- **SPP (75%)**: 找到"圣杯真相" + 知道 Silas 是谁 +- **Resolution**: 揭露阴谋 +- **每个里程碑都对位** + +### 案例 3: 反例——缺 Midpoint +- **问题**: 写作者写完, 故事"平"无转折 +- **方法论的使用**: 6 里程碑扫描, 发现 Midpoint 缺失 +- **结论**: 主角没有"从被动转主动", 整部平铺直叙 +- **结果**: 增补 Midpoint 场景后, 故事张力剧增 + +## 可执行步骤 + +1. **准备文本** + - 完成标准: 用户指定 1 个故事(自己的或现有的) + - 用页数或场景数标记位置 +2. **逐个找 6 里程碑** + - 完成标准: 6 个节点都有位置标注 + - 找不到 = 节点缺失 + - 位置偏离 25%±3% 太多 = 位置错位 +3. **验证每个节点的功能** + - 完成标准: 6 个节点都过功能检查 + - Hook: 1 句话吸引人? + - FPP: 主角接任务了? + - First Pinch: 对抗力量再次被想起? + - Midpoint: 主角从被动转主动? + - Second Pinch: 升级威胁? + - SPP: 给高潮充能? +4. **生成诊断报告** + - 完成标准: 1 张表, 列出"应有 vs 实际" + - 任何"无"或"错位"都是修改点 +5. **改稿** + - 完成标准: 列出至少 3 个具体修改动作 + +空白诊断表见 `../references/structure-checklists.md` 第 4 节"应有 vs 实际"诊断报告。 + +## 边界 + +### 不要在以下情况使用 + +- 写非叙事内容(本方法是叙事结构) +- 中短篇/单场景(6 里程碑不适用, 体裁判断见 `length-system.md`) +- 实验性叙事(非线性/多线并行)——需调整 + +### 作者警告的失败模式 + +- 把"事件密度高"当"里程碑多"——6 个, 不多不少 +- 把"主角做事"当"First Plot Point"——FPP 是"接任务", 不是"做任务" +- 把"高潮前紧张"当"Second Plot Point"——SPP 是"充能", 不是"紧张" + +### 作者盲点 + +- 6 里程碑假设单一 POV——多 POV 需对每个 POV 独立 +- 6 里程碑假设线性时间——非线性/倒叙需调整 +- 6 里程碑假设商业叙事——文学/实验小说可有意缺/移 + +### 易混方法论 + +- "Save the Cat 15 Beats"(Snyder)——是 6 里程碑的细化(15 个), 不替代 +- "Hero's Journey"(Campbell)——是原型, 不是 6 个固定位置 +- "7-Point Story Structure"(不同作家)——类似但有 1-2 节点差异 + +## 中文落地(中文适配) + +- 位置按字数比例换算:110 页剧本的比例(1、25、37、55、75、85、110 页)折成百分比后,对任何体量的中文长篇都适用;40 万字的小说,FPP ≈ 10 万字、Midpoint ≈ 20 万字、SPP ≈ 30 万字。 +- 网文连载的章末钩子密度高,容易把"事件密度"误当"里程碑多":章末小钩子不是里程碑,六个节点各做一件事的判据不变。 +- 章回体小说诊断时可按"回"标注位置(如 120 回制的第 30 回 ≈ 25%),与按字数换算结果互校。 diff --git a/framework/catalog/pi/skills/story-structure/references/structure-checklists.md b/framework/catalog/pi/skills/story-structure/references/structure-checklists.md new file mode 100644 index 0000000..453466a --- /dev/null +++ b/framework/catalog/pi/skills/story-structure/references/structure-checklists.md @@ -0,0 +1,162 @@ +# 结构诊断清单(可执行工作表) + +> 把 references/ 里的判断标准汇成一套可逐项打勾的工作表。新稿搭骨架按"新稿顺序"走;改稿直接从第 4 项"应有 vs 实际"诊断报告开始。 +> 方法细节与案例以 references/ 对应文件为准;来源追溯见 references/_coverage.md。 + +## 0. 新稿搭骨架顺序 + +1. **定体制**:填第 1 节体制确认表;长篇才走完全套,短篇只取"触发事件 + 反常 + 豹尾"。 +2. **定两个锚点再动笔**:写出够用的第一句(进画面)和最后一句(降落画面);想不到第一句就跳过先写正文。→ `opening.md` +3. **切四箱**:用页数/字数/场景数标出 0-25%、25-50%、50-75%、75-100% 四段,一句话说出每段功能。→ `four-boxes.md` +4. **定点**:先定六个里程碑的位置,再往里填场景;写新稿的顺序是"先节点后展开"。→ `six-milestones.md` +5. **Setup 五件事逐项打勾**:见第 5 节;5 个 yes = 通过,4 个 = 补弱项,≤3 个 = 返工。→ `setup.md` +6. **FPP 验证**:见第 7 节;不要因为它"不够大"就重写一个更大的,强度不是标准。→ `first-plot-point.md` +7. **漫游者巡查**:见第 8 节。→ `part2-wanderer.md` +8. **中点确认**:见第 9 节。→ `midpoint.md` +9. **画加码楼梯**:见第 10 节;相邻两级"一样重"就是没升级,重新设计赌注维度。→ `inciting-incident.md` +10. **出诊断表(改稿用)**:见第 4 节"应有 vs 实际"表,任何"无"或"错位"转成至少 3 个具体修改动作。→ `six-milestones.md` + +## 1. 体制确认表 + +```yaml +我要写的: + 体裁:[短篇 / 中篇 / 长篇] + 核心人物数:[N] + 时间跨度:[N] + 核心技法:[冰山/铺垫/反常/性格发育/复调/命运] + 读者注意力预算:[X 小时] +``` + +对照硬规则: +- [ ] 短篇:人物 ≤3;场景 ≤5;时间 ≤24 小时或单一回溯;有 1 个反常事件;结尾有冲击(豹尾) +- [ ] 中篇:人物 3-10;有 1 个明确的性格转折;可分章节但节奏紧凑 +- [ ] 长篇:有人物命运的累积变化;短篇式精微已减少;复调/延宕有安排 +- [ ] 跨体裁转换:短→长已加人物/时间/命运(不是加长句子);长→短已做减法只留 1-2 核心场景;任何→短已检查反常点 + +## 2. 四箱切段表 + +| 段 | 应有位置 | 实际位置 | 功能检查 | 结果 | +|---|---|---|---|---| +| Setup | 0-25% | | 主角接任务了吗?(没 = 正确) | | +| Response | 25-50% | | 主角主动攻击了吗?(没 = 正确) | | +| Attack | 50-75% | | 主角主动进攻了吗?(是 = 正确) | | +| Resolution | 75-100% | | 故事收束了吗?(是 = 正确) | | + +错位记录(任何"过早/过晚"都列出,例:"主角在 20% 就接了任务"太早;"主角在 60% 还在 wanderer"太晚): + +- (空) + +## 3. 六里程碑定位表 + +| # | 里程碑 | 应有位置 | 实际位置 | 功能检查 | 结果(对位/缺失/错位) | +|---|---|---|---|---|---| +| 1 | Hook | 0-5% | | 1 句话吸引人? | | +| 2 | First Plot Point | ~25%(±3%) | | 主角接任务了? | | +| 3 | First Pinch Point | ~37% | | 对抗力量再次被想起? | | +| 4 | Midpoint | ~50%(±3%) | | 主角从被动转主动? | | +| 5 | Second Pinch Point | ~62% | | 升级威胁? | | +| 6 | Second Plot Point | ~75% | | 给高潮充能? | | +| 7 | Resolution | 95-100% | | 故事收束? | | + +规则提醒:六个不多不少;找不到 = 缺失;位置偏离太多 = 错位;功能比戏剧强度重要。 + +## 4. "应有 vs 实际"诊断报告 + +把第 3 节结果汇成一张表,任何"无"或"错位"都是修改点: + +| 里程碑 | 应有 | 实际 | 修改动作(至少 3 条) | +|---|---|---|---| +| | | | | + +## 5. Setup 五使命打勾表 + +Setup 段范围:0-25%(按页数/字数标出:____ 至 ____) + +| 使命 | 检查问句 | yes/no | +|---|---|---| +| Stakes 赌注 | 读者知道主角会失去什么吗? | | +| Empathy 共情 | 读者同情主角吗? | | +| Backstory 背景故事 | 读者知道主角为什么是现在这样吗? | | +| Inner Demons 内在恶魔 | 读者感觉到主角有更深的问题吗? | | +| Hook/Foreshadow 钩子+伏笔 | 读者被吸引 + 感觉到未来冲突吗? | | + +评分:5 全 yes = 通过;4 yes = 补弱项;≤3 yes = Setup 没完成,需改稿。 +补法:缺哪件 + 在合适位置加 1-3 段:____ + +篇幅检查:Setup 是否超过 30%(越界)?是/否 + +## 6. 开篇事件三问:inciting 还是 FPP + +开篇大事件:____(通常在 1-15%) + +| 三问 | 回答 | 判定 | +|---|---|---| +| 它赋予"任务/意义"吗? | yes / no | yes = FPP;no = inciting | +| 它在 25% 位置吗? | yes / no | yes = 可能是 FPP;no = inciting | +| 戏剧强度极高? | yes / no | yes = 倾向 inciting | + +后续处置: +- [ ] 只有 inciting 没有 FPP → 在 25% 处设计 FPP(主角的"决策/任务/意义"瞬间;可弱强度,必须明确意义) +- [ ] 只有 FPP 没有 inciting → 增补开篇钩子(Hook)或小事件 + +## 7. FPP 验证表 + +FPP 候选场景(主角接到新任务/新身份/新威胁的瞬间):____ + +| 检查 | 结果 | +|---|---| +| 对抗力量亮相了吗? | | +| 主角接任务了吗? | | +| 赌注明确了吗? | | +| 位置在 25%±3% 吗?(偏早 20% 前 = Setup 不足;偏晚 30% 后 = Response 被压缩) | | + +处置:3 问全 yes 且位置合格 = 通过;不要因"不够精彩"重写更大的——强度不是标准。改写方案(1-2 条):____ + +## 8. 漫游者巡查表 + +列出 25-50% 的 3-5 场关键戏,逐场检查: + +| 场景 | 主角动作 | 属于六类允许动作?(跑/躲/分析/观察/重算/计划招募) | 是否主动进攻(打怪/破案/解决冲突)? | 若主动,是否合法例外(极小主动/局部小障碍/为中点觉醒服务)? | 处置 | +|---|---|---|---|---|---| +| | | | | | | + +越界场景处置:移到 50% 之后,或改成局部小主动:____ + +## 9. 中点验证表 + +Midpoint 候选(主角变主动的瞬间):____ + +| 检查 | 结果 | +|---|---| +| 主角心态/行为转向了吗(从"被做"到"去做")? | | +| 有新信息/觉醒/承诺吗? | | +| 形式属于四种之一?(觉醒/承诺/新盟友/新赌注) | | +| 位置在 50%±3% 吗?(偏早 = Response 太短;偏晚 = Attack 太短) | | +| 排除三种假中点:反派大动作?主角小胜利?纯信息揭示(主角没拿它行动)? | | + +缺失处置:找 Part 2 结尾 + Part 3 开头的"主角觉醒"瞬间,增补 1 场戏。改写方案:____ + +## 10. 加码楼梯表与赌注自检 + +触发事件(一句话,具体到哪一天哪一秒哪个事件):____ +检验:它是否"radically upsets the balance of forces in the protagonist's life"(主角日常真的被打碎,前稳定/后被打破可对比)?是/否 +若写成了"主角渐渐觉醒"一类的状态变化 → 改写为具体动作(接到电话/推门发现/错过末班车):____ + +加码楼梯(按时间顺序,至少 5 级,每级一句"从 X 升级到 Y";可量化:影响范围/不可逆程度/时间压力/涉及角色数): + +| 级 | 从 X 升级到 Y | 赌注维度(个人→家庭→社群→公众→国家→文明) | +|---|---|---| +| 1 | | | +| 2 | | | +| 3 | | | +| 4 | | | +| 5 | | | +| 6(可加) | | | +| 7(可加) | | | + +检查:任何相邻两级"一样重"(第 3 级 = 第 2 级)= 赌注没升 → 重新设计赌注维度。 + +每 3-5 章自检(写完每 3-5 章做一次): +- [ ] 最近这段的赌注,比 3-5 章前更高吗? +- [ ] 如果删掉这段,故事会失去什么?(答"不影响"= 这段是中段塌陷的元凶,重写或删除) +- [ ] 全书是否只有"开篇 + 结尾"两次赌注?(是 = 中段塌陷典型结构,必须补 2-3 个中间加码点;可借助"be careful what you wish for"——新获得的东西变成新威胁) diff --git a/framework/catalog/pi/skills/theme-and-stance/SKILL.md b/framework/catalog/pi/skills/theme-and-stance/SKILL.md new file mode 100644 index 0000000..5468429 --- /dev/null +++ b/framework/catalog/pi/skills/theme-and-stance/SKILL.md @@ -0,0 +1,96 @@ +--- +name: theme-and-stance +description: | + 中文小说的主题表达与作家立场的执行层:主题不由作者说出来,由人物在关键时刻的选择演示出来; + 立场不靠主题先行去安排,藏进环境与性格的碰撞里自然浮现;沉重题材不写成控诉、苦情或谩骂, + 用幽默建立与现实的关系;人物该受的苦,作者不能因为心软而放过。 + 激活场景:主题写成说教、立场太直白;人物像作者传声筒、情节被安排去服务主题; + 沉重题材写得压抑、愤怒、读着难受;作者舍不得人物受苦、写到关键处手抖。 + 关键 trigger:"主题说教" "主题太直白" "主题先行" "席勒化" "莎士比亚化" "主题怎么表达" + "show don't tell 主题" "演示主题" "手软" "舍不得" "手抖" "心慈手狠" "狠瞬间" + "黑色幽默" "沉重题材" "太沉重了" "批判但不说教" "读着压抑" "布尔加科夫" "卡夫卡式幽默"。 + 不适用于:非虚构/纪实/学术写作(主题表达方式不同);寓言、童话、儿童文学 + (可以明说主题,也可以心慈不手狠);纯喜剧写作(幽默本身就是目的); + 大屠杀、重大灾难等纯悲剧庄重题材(慎用幽默,会显得轻佻); + 主题尚未建立(先用 concept-design 做概念设计)。 + 与 show-and-omission 交接:标签换场景、冰山留白、视角穿帮归 show-and-omission;主题演示、立场与手软/幽默结构归本 Skill。 + 与 narration-pov 交接:外来者切入的荒诞/幽默距离与结构(含撒旦访莫斯科全文案例)归本 Skill;narration-pov 只保留 POV 侧外来者机制指针。 +--- + +# 主题与立场 + +主题不是作者说出来的道理,是读者自己看出来的东西;立场不是作者的表态,是环境、人物逻辑和命运重量共同逼出来的结论。本 skill 管四件事:主题怎么不说教(演示)、立场怎么不先行(莎士比亚化)、人物该受的苦怎么不放过(心慈手狠)、沉重题材怎么不被仇恨淹没(幽默作为结构)。 + +## 方法索引 + +### 定主题与查主题 + +- 主题是故事对现实照亮什么,必须具体到"关于 X 中的 Y";"关于人性"是模糊哲学,无法演示 → references/theme-demonstration.md +- 陈述的主题是被动的,演示的主题是主动的;角色说出主题就变成作者传声筒,读者立刻感到"被教" → references/theme-demonstration.md + +### 植入主题:演示而非说出 + +- 三种演示法:决策演示(关键场景选 A 还是 B,选什么就是主题立场)、结构演示(开头与结尾、失败与成功对照)、反讽演示(说一套做一套,落差即主题) → references/theme-demonstration.md +- Tell 扫描三类位置(角色对话陈述主题、叙述者点题、章节开头寓言式开篇),把"说"改成场景中"做",再补 1-2 个小决策演示场景 → references/theme-demonstration.md;references/theme-stance-checklist.md + +### 防主题先行:把立场翻译成环境与人物 + +- 席勒化是思想先行安排情节(作家当指挥家),莎士比亚化是让人物按小说内部逻辑自己走(作家是看不见的手) → references/stance-by-logic.md +- 操作方向:不写"批判 X、主角揭发 X",写一个具体的 X 场景加一个性格鲜明的当事人,让场景和性格碰撞,主题自然浮现 → references/stance-by-logic.md +- 性格碰撞推力链:A 的性格撞 B 的性格必然产生事件,事件改变环境,环境反作用于人物,每一环都要可推导、不能跳跃 → references/stance-by-logic.md + +### 作家沉默:三项检验 + +- 发言权检验:"如果我什么都不说,人物会自己走到这一步吗?" → references/stance-by-logic.md +- 必然性检验:删掉任何一个事件,故事完全垮掉才是必然的,不影响就是多余的 → references/stance-by-logic.md +- 终极检验:删掉全部作家发言(解释、议论、心理分析),读者还能读懂才算莎士比亚化 → references/stance-by-logic.md;references/theme-stance-checklist.md + +### 对人物的立场:心慈手狠 + +- 心慈是前提:不爱的人物写不好;手狠是诚实:不能因为爱就放过他——"手狠"不是恶意,是诚实地写出人物命运的必然 → references/mercy-ruth.md +- 每个主要人物要有 1-3 个"狠瞬间"(作家对他最残酷的瞬间);全是甜的是心慈手不狠,全是狠的是手狠心不慈 → references/mercy-ruth.md +- 三个手软信号:"舍不得""算了他不该这么惨""突然让他走运"——出现任何一个就回到性格加逻辑,把该给的代价给足 → references/mercy-ruth.md;references/theme-stance-checklist.md + +### 沉重题材的立场:幽默作为结构 + +- 面对无法改变的痛苦现实,除了妥协和对抗还有第三条路:幽默不是插科打诨,是整体的叙述结构和态度,让作者不被仇恨淹没、想象力开始茁壮成长 → references/humor-as-stance.md +- 幽默距离三档:近距人物在苦难中自嘲(余华式)、中距叙述者冷幽默(卡夫卡式)、远距引入荒诞元素制造间离(布尔加科夫式,让魔鬼访问莫斯科) → references/humor-as-stance.md +- 让荒诞自行呈现:不直接批判,写荒诞细节(翻箱倒柜找文件、永远找不到的负责人),全文至少 3 处"让人发笑但笑后不安"的细节;笑的对象是环境和制度,不是人物 → references/humor-as-stance.md;references/theme-stance-checklist.md + +### 边界与误诊 + +- 寓言、童话、儿童文学可以明说主题、可以心慈不手狠;魔幻现实主义只部分适合莎士比亚化(用环境逻辑替代日常逻辑) → references/boundaries-and-pitfalls.md +- 大屠杀、重大灾难等纯悲剧庄重题材慎用幽默;个人真实创伤书写先做情感宣泄,幽默的距离为时尚早 → references/boundaries-and-pitfalls.md +- 常见错误表(席勒化四错、心软五错)与易混方法(Show Don't Tell、契诃夫之枪、讽刺、喜剧 relief)→ references/boundaries-and-pitfalls.md + +## 引用索引 + +| 文件 | 覆盖内容 | +|------|----------| +| references/theme-demonstration.md | 主题演示而非告诉:英文原段引文与白话转述;陈述主题 vs 演示主题;Show/Tell 在主题上的应用;Tell 失败三原因;三种演示法(决策/结构/反讽);案例三个(《苹果酒屋法则》Homer Wells 的选择与奥斯卡、《可爱的骨头》Susie 天上视角与 1000 万册、反例"主题演讲");四步执行流程(确认主题、扫描 Tell、改成 Show 含撤离船例子、补 1-2 个演示场景);触发场景与语言信号;中文落地与适配;《小说课》"主题自然浮现"跨书呼应 | +| references/stance-by-logic.md | 莎士比亚化 vs 席勒化:"思想性传递"原文引文;林冲"走"上梁山的错误写法与正确写法全链(白虎堂→野猪林→牢城营→草料场→雪→风→石头→听到阴谋→杀人→柴进指路→上山);五维对照表;案例四个(林冲风雪石头因果链、《促织》"为人迁讷"、《项链》改写版 vs 原文、王熙凤"毒设相思局");五步执行流程(主题翻译成环境、推力链、发言权检验、必然性检验、让作家沉默);触发场景五条;一句话总结 | +| references/mercy-ruth.md | 心慈手狠:"心慈手狠"与"手不能抖"原文引文;《项链》"发红的手"原文与毕飞宇解读;心慈与手狠的关系三种;案例五个(《项链》、《苔丝》、《促织》、鲁迅闰土与杨二嫂、王熙凤"哭向金陵");五步执行流程(检验心慈、检验手狠、找狠瞬间、避开心软诱惑、用心慈写手狠);触发场景五条;一句话总结 | +| references/humor-as-stance.md | 幽默作为结构:余华论布尔加科夫三段引文与"让魔鬼访问莫斯科"段;两种反应与第三条路;幽默作为结构四个核心;案例三个(布尔加科夫沃兰德访问 1930 年代莫斯科、卡夫卡《城堡》官僚细节、余华《许三观卖血记》卖血仪式);六步执行流程(识别沉重程度、选幽默距离、让荒诞自行呈现、保持人物尊严、控制叙述节奏、检查幽默是否成为结构,各含完成标准);触发场景与语言信号 | +| references/boundaries-and-pitfalls.md | 四家不适用场景汇总(非虚构、主题根本不存在、寓言童话儿童文学、纯悲剧庄重题材、纯喜剧、个人创伤、反派视角慎用);失败模式(主题模糊哲学、反讽用错、删 Tell 不补 Show、幽默变嘲笑、幽默消解批判);作者盲点(Brooks 三个、余华两个);常见错误表两张(席勒化四行、心软五行);易混方法(Show Don't Tell、契诃夫之枪、象征叙事、讽刺、喜剧 relief);相邻方法区分与跨域链接(concept/character/show-and-omission/foreshadow-payoff/narration-pov/narrative-momentum/prose-craft/character-presentation) | +| references/theme-stance-checklist.md | 修订与写作中检查清单:主题 Tell 扫描(搜"主题关键词+说出动词")、主题翻译成环境、推力链、发言权检验、必然性检验、作家沉默终极检验、心慈手狠五项检验、狠瞬间盘点、幽默距离与结构检验;快速排错表 | + +## 脚本 + +| 脚本 | 用途 | 来源 | +|------|------|------| +| references/theme-stance-checklist.md | 写前建碰撞、写中防手软、改稿五项检验的可执行清单,附症状→诊断→处方排错表 | 四个源单元 | + +## 输入 + +- 用户明确点名本 Skill 所服务的创作阶段任务包(作品、章节/场景范围、冻结上下文摘要)。 +- 只消费 本 Skill 的 `references/` 目录 中与当前阶段相关的合同段落,不加载其它 Skill 的完整正文。 + +## 输出 + +- 面向当前任务的可执行判断、检查清单或改写建议(Markdown 结构化段落)。 +- 不直接落库、不代替 `write-next-chapter` / `decide-candidate` 写 Canonical。 + +## 复利合同 + +- **消费**:本 Skill 的选型判断指导后续 `plan-story` / `assemble-context` 的范式绑定;不直接写库。 +- **回写**:可操作写法单元出卡走 `review-knowledge-cards` → 用户确认(批次 3);当前不自动登记 `example_lesson`,避免无效果信号的公共卡膨胀。 diff --git a/framework/catalog/pi/skills/theme-and-stance/references/_coverage.md b/framework/catalog/pi/skills/theme-and-stance/references/_coverage.md new file mode 100644 index 0000000..03e087b --- /dev/null +++ b/framework/catalog/pi/skills/theme-and-stance/references/_coverage.md @@ -0,0 +1,15 @@ +# theme-and-stance 覆盖对照表 + +唯一追溯文件:源单元 → references/ 落点(文件级)。SKILL.md 与 references 内容文件不带追溯标记。 + +| 源单元 | 落点 | +|---|---| +| bifeiyu-novel-skill/bifeiyu-mercy-ruth | references/mercy-ruth.md | +| bifeiyu-novel-skill/bifeiyu-mercy-ruth | references/boundaries-and-pitfalls.md | +| bifeiyu-novel-skill/bifeiyu-shakespeare | references/stance-by-logic.md | +| bifeiyu-novel-skill/bifeiyu-shakespeare | references/theme-demonstration.md | +| bifeiyu-novel-skill/bifeiyu-shakespeare | references/boundaries-and-pitfalls.md | +| story-engineering/theme-demonstrate-not-tell | references/theme-demonstration.md | +| story-engineering/theme-demonstrate-not-tell | references/boundaries-and-pitfalls.md | +| wo-neng-fou-xiang-xin-zi-ji/humor-as-structure | references/humor-as-stance.md | +| wo-neng-fou-xiang-xin-zi-ji/humor-as-structure | references/boundaries-and-pitfalls.md | diff --git a/framework/catalog/pi/skills/theme-and-stance/references/boundaries-and-pitfalls.md b/framework/catalog/pi/skills/theme-and-stance/references/boundaries-and-pitfalls.md new file mode 100644 index 0000000..d61323b --- /dev/null +++ b/framework/catalog/pi/skills/theme-and-stance/references/boundaries-and-pitfalls.md @@ -0,0 +1,110 @@ +# 边界、常见误区与易混方法 + +> 汇总四个源单元的适用边界、失败模式、作者盲点、常见错误表、易混方法与相邻方法区分。每条标注来源。 +> 方法正文见:[theme-demonstration.md](theme-demonstration.md)、[stance-by-logic.md](stance-by-logic.md)、[mercy-ruth.md](mercy-ruth.md)、[humor-as-stance.md](humor-as-stance.md)。 + +## 一、不适用场景汇总 + +| 场景 | 原因 | 来源 | +|------|------|------| +| 非虚构 / 纪实 / 学术 | 主题表达方式不同 | /theme-demonstrate-not-tell | +| 主题根本不存在 | 需要先建主题(先做概念设计) | /theme-demonstrate-not-tell | +| 寓言、童话 | 寓言可以"说"主题,不在演示范围 | /theme-demonstrate-not-tell | +| 寓言、童话(立场层) | 它们恰恰需要席勒化 | /bifeiyu-shakespeare | +| 儿童文学、纯治愈系 | 它们恰恰要"心慈不手狠"(慎用) | /bifeiyu-mercy-ruth | +| 反派视角叙事 | 容易"手狠心不慈"(慎用) | /bifeiyu-mercy-ruth | +| 纯粹的悲剧 / 庄重题材(大屠杀、严重灾难) | 需要保持庄重,幽默会显得轻佻 | /humor-as-structure | +| 喜剧写作(情景喜剧等) | 幽默本身就是目的,不需要"幽默作为结构"——它就是全部 | /humor-as-structure | +| 个人创伤书写 | 处理自己的真实创伤可能需要先情感宣泄,幽默的距离可能为时尚早 | /humor-as-structure | + +适用面(正面): + +- 莎士比亚化**适合**现实主义小说、所有长篇、所有"严肃"叙事;**部分适合**魔幻现实主义(用环境逻辑替代日常逻辑)。(/bifeiyu-shakespeare) +- 心慈手狠**适合**所有虚构叙事,**特别适合**现实主义、批判现实主义。(/bifeiyu-mercy-ruth) + +## 二、失败模式(作者在书中警告的) + +**主题演示**(/theme-demonstrate-not-tell): + +- 主题是"模糊哲学"(如"关于人性")——必须具体到"关于 X 中的 Y" +- 反讽用错——让反派"说"主题让主角"做"反讽主题——容易混乱 +- 删除 Tell 后完全没有主题——应增加 Show 演示,不是简单删除 + +**幽默作为结构**(/humor-as-structure): + +- **幽默变成嘲笑**:幽默不是嘲笑人物的苦难,而是与苦难保持距离。如果读者感到作者在嘲笑人物,就失败了 +- **幽默消解了批判**:如果幽默过度,会让读者觉得"这也没什么大不了",失去批判力量。需要"控制得恰如其分" + +## 三、作者盲点 + +**Brooks**(/theme-demonstrate-not-tell): + +- 假设所有题材都不能 Tell——童话/寓言/儿童文学可以 Tell +- 假设"反讽" = 主题成功——反讽必须清晰,否则读者看不出 +- 假设"复杂主题"必须复杂演示——简单主题用 1 个场景就够 + +**余华**(/humor-as-structure): + +- 余华主要讨论极权/压迫环境下的幽默,没有讨论日常/普通题材中如何使用幽默作为结构 +- "幽默作为结构"是比较高级的技巧,需要相当的写作经验,初学者可能难以掌握 + +## 四、常见错误表 + +### 席勒化四类错误(/bifeiyu-shakespeare) + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 让人物"觉醒" | 突兀 | 觉醒前必须有"压垮骆驼的最后一根稻草"——具体的、可推导的 | +| 用"巧合"推情节 | 廉价 | 巧合要少用,且要"埋"——让读者读后才恍然 | +| 人物"被作者安排" | 假 | 让人物按性格走,作家只设环境 | +| 思想性太重 | 主题先行 | 把思想藏进环境 | + +### 心软五类错误(/bifeiyu-mercy-ruth) + +| 错误 | 后果 | 修正 | +|-----|------|-----| +| 心慈不手狠 | 烂好人作品 | 让人物承担他应承担的 | +| 手狠不心慈 | 虐待狂 | 检验你"爱不爱他" | +| 突然让命运变好 | 假 | 命运不可逆 | +| 让主角"轻飘飘"就过去 | 假 | 主角的命运必须有重量 | +| 写到关键处手抖 | 假 | 你手软了——回到性格 + 逻辑 | + +## 五、易混方法 + +**与主题演示易混**(/theme-demonstrate-not-tell): + +- "Show Don't Tell"(写作通用)——本 skill 的主题演示是它的主题特化版;句子与情绪层的展示方法在 `show-and-omission`(展示与留白) +- "Chekhov's Gun"(契诃夫之枪)——是"伏笔演示",不是"主题演示";见 `foreshadow-payoff`(伏笔与回收) +- "Symbolic Storytelling"(象征叙事)——是"通过象征演示",比主题演示宽 + +**与幽默结构易混**(/humor-as-structure): + +- **"讽刺"(satire)**:讽刺是用幽默批判具体对象,有明确的靶子。本方法是用幽默作为整体叙述态度,不一定有具体靶子——更接近"黑色幽默"而非"讽刺"。 +- **"喜剧 relief"**:喜剧 relief 是在沉重场景中插入搞笑段落缓解紧张,是局部技巧。本方法是全局结构——幽默贯穿全文,不是偶尔的调剂。 + +## 六、相邻方法区分与跨域链接 + +**主题演示与相邻 skill 的区分**(/theme-demonstrate-not-tell): + +- `concept-design`(概念与前提)的 concept-* 系列:是"找种子"(主题独立,不是 concept) +- `character-design`(人物设计)的 character-* 系列:是"建角色"(主题通过角色演示;源单元标注与 character-seven-variables 为 composes-with 关系) +- 本 skill:是"主题如何呈现"(执行层面) + +**幽默结构与相邻方法的区分**(/humor-as-structure): + +- 与 `narration-pov`(叙述与视角)的 skeptical-narration 的区别:本方法是用幽默的态度处理现实,skeptical-narration 是用怀疑的立场处理看法。两者经常配合——幽默中包含怀疑,怀疑中带有幽默。 +- 与 `show-and-omission`(展示与留白)的 imagination-to-fact 的区别:本方法关注叙述态度,imagination-to-fact 关注虚构内容的可信度。幽默的态度往往需要超现实的想象(如撒旦访问莫斯科),两者配合使用。 + +**莎士比亚化的跨域链接**(/bifeiyu-shakespeare): + +- 与 `show-and-omission`(展示与留白)的 bifeiyu-anti-logic 互补:莎士比亚化用逻辑,反逻辑是它的"另一面" +- 与 `character-presentation`(人物呈现)的 bifeiyu-character-fate 同源:性格即命运 = 性格 + 现实的逻辑推演 +- 与 `narrative-momentum`(叙事动力)的 bifeiyu-momentum 关联:莎士比亚化是"势"能产生的方法 +- 与本 skill 的 bifeiyu-mercy-ruth(心慈手狠)配对:作家要"手狠"才能让逻辑自己走——不能因心软去救人物 + +**心慈手狠的跨域链接**(/bifeiyu-mercy-ruth): + +- 与 `character-presentation`(人物呈现)的 bifeiyu-character-fate 配套:性格碰撞出来的命运 = 作家"手狠"的依据 +- 与本 skill 的 bifeiyu-shakespeare 同源:莎士比亚化要求作家"沉默",心慈手狠是前提 +- 与 `narrative-momentum`(叙事动力)的 bifeiyu-momentum 关联:势的累加 = 手狠——不能因心软去"减弱"势 +- 与 `prose-craft`(语言与修辞)的 bifeiyu-base-temp 关联:大师的温度是"冷中的热"——心慈手狠 = 冷温度下的热关怀 diff --git a/framework/catalog/pi/skills/theme-and-stance/references/humor-as-stance.md b/framework/catalog/pi/skills/theme-and-stance/references/humor-as-stance.md new file mode 100644 index 0000000..86987e7 --- /dev/null +++ b/framework/catalog/pi/skills/theme-and-stance/references/humor-as-stance.md @@ -0,0 +1,125 @@ +# 幽默作为结构:沉重题材的第三条路 + +> 来源单元:《我能否相信自己》(余华)wo-neng-fou-xiang-xin-zi-ji/humor-as-structure,《布尔加科夫与〈大师和玛格丽特〉》(1996)。 +> 本文件管沉重题材的立场:既不向现实妥协,也不与现实对抗,用幽默建立第三种关系。主题为什么不能直接说出见 [theme-demonstration.md](theme-demonstration.md);"批判但不说教"的另一半(把批判藏进环境与性格碰撞)见 [stance-by-logic.md](stance-by-logic.md);边界与易混方法见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> "幽默成为了结构,成为了叙述中控制得恰如其分的态度,也就是说幽默使布尔加科夫找到了与世界打交道的最好方式。" + +> "他两者都放弃了,他做出的选择是一个优秀作家应有的选择,最后他与现实建立了幽默的关系。" + +> "正是这样的方式,使布尔加科夫在其最后的写作里,没有被自己的仇恨淹没,也没有被贫穷拖垮,更没有被现实欺骗。同时,他的想象力,他的洞察力,他写作的激情开始茁壮成长了。" + +——余华,《布尔加科夫与〈大师和玛格丽特〉》 + +(/humor-as-structure) + +## 方法核心 + +当作家面对无法改变的痛苦现实时,有两种常见反应: + +1. **与现实妥协**:失去力量,作品变成歌功颂德 +2. **与现实对抗**:变成谩骂和哭叫,作品被愤怒淹没 + +布尔加科夫选择了**第三种方式:幽默**。但这里的幽默不是修辞技巧(机智的讽刺、俏皮的对话),而是**整体的叙述结构和态度**——是作家与世界打交道的方式。 + +幽默作为结构的核心: + +- **不被仇恨淹没**:幽默让作家与痛苦保持距离,可以审视它而非被它吞噬 +- **解放想象力**:幽默的态度让荒诞的想象成为可能(撒旦访问莫斯科) +- **控制叙述**:幽默是"控制得恰如其分的态度",让叙述在沉重和轻松之间保持平衡 +- **与现实的关系**:既不妥协也不对抗,而是用幽默"与现实建立关系" + +布尔加科夫在斯大林时代作品被禁,他让魔鬼沃兰德访问莫斯科,用幽默的方式处理自己的仇恨和痛苦。"他让魔鬼访问莫斯科,作品一开始他就表明了自己的态度,那就是他要讲述的不是一个斤斤计较的故事,他要告诉我们的不是个人的恩怨,而是真正意义上的现实。" + +(/humor-as-structure) + +## 书中案例 + +### 案例 1:布尔加科夫《大师和玛格丽特》——撒旦访问莫斯科 + +- **问题**:布尔加科夫在斯大林时代作品被禁,生活贫困,朋友疏远,如何写这个时代而不变成谩骂? +- **方法论的使用**:他让撒旦(沃兰德)带着随从访问 1930 年代的莫斯科,用魔鬼的视角审视苏联社会的虚伪和荒诞。撒旦的游戏(让莫斯科人惊慌失措)既是对现实的批判,又充满幽默和想象力。布尔加科夫"没有被自己的仇恨淹没,也没有被贫穷拖垮,更没有被现实欺骗"。 +- **结论**:幽默成为结构,让沉重的题材变得可写且有力。 +- **结果**:《大师和玛格丽特》成为 20 世纪最伟大的小说之一,死后出版,影响深远。 + +### 案例 2:卡夫卡《城堡》——官僚制度的黑色幽默 + +- **问题**:如何描写一个荒诞而压迫的官僚制度而不变成控诉? +- **方法论的使用**:卡夫卡用幽默的细节呈现官僚制度的荒谬——村长家翻箱倒柜找文件,电话接通后听到无数声音(因为所有电话同时接通),克拉姆先生仿佛生活在传说中。这些细节让人发笑,但笑完后感到深深的不安。 +- **结论**:幽默不是为了搞笑,而是让荒诞自行呈现——制度的不合理性通过外来者 K 的不适应自然暴露。 +- **结果**:《城堡》成为表现主义文学的经典,官僚批判的巅峰之作。 + +### 案例 3:余华《许三观卖血记》——苦难中的幽默 + +- **问题**:写一个人靠卖血维持生活的苦难故事,如何不变成苦情戏? +- **方法论的使用**:余华用通篇对话和冷幽默处理许三观的苦难——许三观卖血前要多喝水,卖血后要吃炒猪肝喝黄酒,这些仪式化的细节既真实又带着黑色幽默。人物在苦难中仍然有尊严和笑声。 +- **结论**:幽默让苦难有了温度,读者不是同情而是共情。 +- **结果**:《许三观卖血记》成为余华最受欢迎的作品之一。 + +(以上案例均出自/humor-as-structure) + +## 执行步骤 + +1. **识别题材的沉重程度** + - 这个题材涉及哪些痛苦/压迫/荒诞? + - 如果直接写,会变成什么?(控诉?苦情?谩骂?) + - 完成标准:明确题材的沉重点和直接写法的风险 + +2. **选择幽默的距离** + - 决定幽默与痛苦的距离: + - 近距幽默:人物在苦难中自嘲(余华式) + - 中距幽默:叙述者用冷幽默评论(卡夫卡式) + - 远距幽默:引入荒诞元素制造间离(布尔加科夫式,撒旦访问莫斯科) + - 完成标准:明确幽默的距离和方式 + +3. **让荒诞自行呈现** + - 不直接批判,而是让荒诞的细节自己说话 + - 官僚制度:写翻箱倒柜找文件、电话接通后无数声音、永远找不到的负责人 + - 社会虚伪:让人物在荒诞场景中一本正经地行事 + - 完成标准:至少有 3 处"让人发笑但笑后不安"的细节 + +4. **保持人物的尊严** + - 幽默不是嘲笑人物,而是嘲笑环境/制度 + - 人物在苦难中仍然有尊严、有逻辑、有笑声 + - 完成标准:读者对人物是共情而非俯视 + +5. **控制叙述节奏** + - 幽默段落和沉重段落交替,不要全程搞笑也不要全程压抑 + - 幽默的"度":控制得恰如其分,不过度也不不足 + - 完成标准:叙述在沉重和轻松之间有平衡 + +6. **检查幽默是否成为结构** + - 幽默是贯穿全文的态度,还是偶尔的俏皮话? + - 如果只是偶尔的俏皮话,需要回到步骤 2,让幽默成为整体结构 + - 完成标准:幽默是全文的叙述态度,不只是修辞装饰 + +(/humor-as-structure) + +## 触发场景与语言信号 + +用户会在什么情境下需要这个方法(/humor-as-structure): + +1. 写沉重/痛苦/批判题材,作品变得压抑、愤怒,自己写着都难受 +2. 想写黑色幽默但不知道怎么操作 +3. 批判社会/人性时忍不住变成说教或谩骂 +4. 作品被反馈"太沉重了""读着压抑" +5. 想学习布尔加科夫/卡夫卡式的幽默 +6. 写荒诞题材但缺乏幽默感 + +语言信号: + +- "写得太压抑" "太沉重了" +- "黑色幽默怎么写" "dark humor" +- "批判但不说教" "不想变成谩骂" +- "荒诞题材" "幽默结构" +- "作品读着难受" "需要轻松一点" +- "布尔加科夫" "卡夫卡式幽默" + +## 与其他方法的关系 + +- 与 `narration-pov`(叙述与视角)的 skeptical-narration 配合:本方法是用幽默的态度处理现实,怀疑叙述是用怀疑的立场处理看法。两者经常配合——幽默中包含怀疑,怀疑中带有幽默。(完整区分见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)) +- 与 `show-and-omission`(展示与留白)的 imagination-to-fact 配合:本方法关注叙述态度,想象锚定关注虚构内容的可信度。幽默的态度往往需要超现实的想象(如撒旦访问莫斯科),两者配合使用——用想象-事实转化让荒诞可信。(完整区分见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)) + +(/humor-as-structure) diff --git a/framework/catalog/pi/skills/theme-and-stance/references/mercy-ruth.md b/framework/catalog/pi/skills/theme-and-stance/references/mercy-ruth.md new file mode 100644 index 0000000..097573b --- /dev/null +++ b/framework/catalog/pi/skills/theme-and-stance/references/mercy-ruth.md @@ -0,0 +1,183 @@ +# 心慈手狠(Merciful Heart, Ruthless Hand):爱你的角色,但不要放过他 + +> 来源单元:《小说课》(毕飞宇)bifeiyu-novel-skill/bifeiyu-mercy-ruth,第 5 章(风格·态度)。 +> 本文件管作家对人物受苦的态度:心慈是前提,手狠是诚实。莎士比亚化要求作家"沉默",心慈手狠是它的前提,见 [stance-by-logic.md](stance-by-logic.md);边界与常见错误见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> 「我喜欢'心慈''手狠'的作家。鲁迅就是这样。'心慈'加'手狠'大概可以算作大师级作家的共同特征了。用李敬泽的说法,写到关键的地方,'作家的手不能抖'。」 + +(/bifeiyu-mercy-ruth) + +莫泊桑《项链》写马蒂尔德还了 10 年债之后: + +> "她已经变成一个粗壮耐劳的妇女了……她说话粗声大气……她提着脏衣服篮子……**她的手是发红的**。" + +**毕飞宇解读**: + +> "莫泊桑就'手狠'。'发红的手'就证明了莫泊桑的'手'有多'狠'。" + +- "心慈":莫泊桑同情马蒂尔德的虚荣 +- "手狠":莫泊桑没有放过她——给了她最残酷的结局 + +**"手狠"不是恶意——是诚实**。作家必须诚实地写出人物命运的必然。 + +(/bifeiyu-mercy-ruth) + +## 方法核心 + +**心慈 = 作家要爱自己的人物**。 + +**手狠 = 作家不能因为爱而放过人物**。 + +**两者的关系**: + +- 只心慈不手狠 = 烂好人作品(人物没真实命运) +- 只手狠不心慈 = 虐待狂作品(人物没灵魂) +- **心慈+手狠 = 大师作品(人物有真实命运)** + +(/bifeiyu-mercy-ruth) + +## 书中案例 + +### 案例 1:莫泊桑《项链》"发红的手" + +- 莫泊桑爱马蒂尔德吗?→ **爱**(她是人,有人的虚荣) +- 莫泊桑放过她吗?→ **没有**(她必须为虚荣付出代价) +- "发红的手"是莫泊桑的"狠"——**但这狠背后是爱** + +(同一作品《项链》在"莎士比亚化"单元里从逻辑自洽角度出现——人物性格 + 时代背景 → 自然借项链,见 [stance-by-logic.md](stance-by-logic.md) 案例 3。) + +### 案例 2:哈代《苔丝》 + +- 哈代爱苔丝吗?→ **深爱**(给她最纯粹的忠诚和痛苦) +- 哈代放过她吗?→ **没有**(杀了她) +- 哈代同情苔丝,但没放过她——**心慈手狠** + +### 案例 3:蒲松龄《促织》 + +- 蒲松龄爱成名一家吗?→ **爱**(同情他们的痛苦) +- 蒲松龄放过他们吗?→ **没有**(儿子变成蛐蛐、死亡、复活) +- 这是"心慈手狠"——**写了最残酷的故事** + +(同一作品《促织》在"莎士比亚化"单元里从性格碰撞角度出现——"为人迁讷"四个字然后小说自己跑,见 [stance-by-logic.md](stance-by-logic.md) 案例 2。) + +### 案例 4:鲁迅 + +- 鲁迅爱闰土吗?→ **爱**(年轻时是"自然关系") +- 鲁迅放过闰土吗?→ **没有**(让他叫"老爷"——揭示奴性) +- 鲁迅爱杨二嫂吗?→ **复杂**(批判但不蔑视) +- 鲁迅放过杨二嫂吗?→ **没有**(让她变成"圆规") + +### 案例 5:曹雪芹 + +- 曹雪芹爱王熙凤吗?→ **爱**(她是曹雪芹心中最精彩的人物) +- 曹雪芹放过王熙凤吗?→ **没有**(让她"哭向金陵事更哀") + +(同一人物王熙凤在"莎士比亚化"单元里从性格逻辑角度出现——管的性格 + 贾府复杂关系 → 必然"毒设相思局",见 [stance-by-logic.md](stance-by-logic.md) 案例 4。) + +(以上案例均出自/bifeiyu-mercy-ruth) + +## 执行步骤 + +### 步骤 1:检验"心慈" + +> "我爱我的主角吗?" + +- 爱 → 写下去 +- 不爱 / 蔑视 → 删掉或改写(你不爱的人物写不好) + +**心慈是基础**——你必须先爱人物,才能写他。 + +### 步骤 2:检验"手狠" + +> "我有没有因为我爱他就放过他?" + +- 放过他 → 你手软了——再狠一点 +- 没放过 → 你手狠 + +**检验问题**: + +- 你的主角有没有受够他应受的苦? +- 你的反派有没有得到他应得的报应? +- 你的悲剧够不够"悲"? + +### 步骤 3:找到"狠的瞬间" + +每个主要人物都应该有**1-3 个"狠"瞬间**——作家对他最残酷的瞬间: + +``` +成名:儿子自杀 +林冲:风雪山神庙,杀人 +马蒂尔德:发红的手 +苔丝:被处死 +闰土:叫"老爷" +王熙凤:哭向金陵 +``` + +**检验**:你的主要人物有"狠瞬间"吗? + +- 全是甜的 → 你心慈手不狠 +- 全是狠的 → 你手狠心不慈 +- **有甜有狠** → 心慈手狠 + +### 步骤 4:避免"心软的诱惑" + +**最常见的诱惑**:作家太爱人物,写到关键处"手抖"了: + +> "我舍不得她死……算了,让她活下去吧" + +**毕飞宇的解药**: + +> "作家是小说的上帝,但上帝不能滥用慈悲。" + +**检验**: + +- 你有没有"舍不得"过?→ 警惕 +- 你有没有"算了他不该这么惨"?→ 警惕 +- 你有没有"突然让他走运"?→ 警惕 + +### 步骤 5:用"心慈"写"手狠" + +**最难的技巧**——让读者感受到"作家爱他,但作家不能放过他": + +``` +莫泊桑的"发红的手": + 莫泊桑爱马蒂尔德(她美丽、虚荣、是人) + 莫泊桑写下"发红的手"(她必须付出代价) + 读者感受到的不是残忍——是诚实 + → 诚实 = 心慈 + 手狠 +``` + +**检验**:你的"狠"是不是带着"爱"? + +- 狠但带着爱 → 心慈手狠 +- 狠只是狠 → 虐待狂 +- 狠带着蔑视 → 失败 + +(/bifeiyu-mercy-ruth) + +## 触发场景 + +1. 你的人物"该受苦但你舍不得" → 你的手软了 +2. 你的悲剧"不够悲" → 你心慈但手不狠 +3. 你的人物"突然命运变好" → 你的手软了(不一定对,要看逻辑) +4. 你在写"坏人"但笔下留情 → 你可能太"心慈" +5. 你在写"主角"但不敢让他失败 → 你心慈手不狠 + +(/bifeiyu-mercy-ruth) + +## 一句话总结 + +> **"作家是小说的上帝,但上帝不能滥用慈悲"——爱你的角色,但不要放过他。** + +(/bifeiyu-mercy-ruth) + +## 与其他方法的关系 + +- 与 `character-presentation`(人物呈现)的 bifeiyu-character-fate 配套:性格碰撞出来的命运 = 作家"手狠"的依据 +- 与本 skill 的 bifeiyu-shakespeare 同源:莎士比亚化要求作家"沉默",心慈手狠是前提,见 [stance-by-logic.md](stance-by-logic.md) +- 与 `narrative-momentum`(叙事动力)的 bifeiyu-momentum 关联:势的累加 = 手狠——不能因心软去"减弱"势 +- 与 `prose-craft`(语言与修辞)的 bifeiyu-base-temp 关联:大师的温度是"冷中的热"——心慈手狠 = 冷温度下的热关怀 + +(/bifeiyu-mercy-ruth) diff --git a/framework/catalog/pi/skills/theme-and-stance/references/stance-by-logic.md b/framework/catalog/pi/skills/theme-and-stance/references/stance-by-logic.md new file mode 100644 index 0000000..81c4fea --- /dev/null +++ b/framework/catalog/pi/skills/theme-and-stance/references/stance-by-logic.md @@ -0,0 +1,161 @@ +# 莎士比亚化(Shakespeare-ization):把主题翻译成环境,让人物自己走 + +> 来源单元:《小说课》(毕飞宇)bifeiyu-novel-skill/bifeiyu-shakespeare,第 6 章(结构·逻辑)。 +> 本文件管立场的植入方式:不做思想先行的"席勒化",把主题藏进环境与性格的碰撞里,让小说内部逻辑推着人物走。主题为什么必须演示见 [theme-demonstration.md](theme-demonstration.md);作家"手狠"才能让逻辑自己走,见 [mercy-ruth.md](mercy-ruth.md);边界与常见错误见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> 「思想性的传递需要作家的思想,其实更需要作家的艺术才能。在美学上,说空话有一个专业的名词,叫'席勒化',把思想性落实到艺术性上,也有一个专业名词,叫'莎士比亚化'。」 + +(/bifeiyu-shakespeare) + +林冲怎么"走"上梁山的? + +**错误的写法**(席勒化): + +- 作家想:林冲应该造反 +- 作家安排:林冲拍案而起、振臂高呼、被逼上梁山 + +**正确的写法**(莎士比亚化): + +- 白虎堂 → 野猪林 → 牢城营 → 草料场 → 雪 → 风 → 石头 → 听到阴谋 → 杀人 → 柴进指路 → 上山 + +**林冲的每一次"走"都是他自己不想"走"的**。但小说内部逻辑推动着他不得不走。 + +(/bifeiyu-shakespeare) + +## 方法核心 + +**莎士比亚化 = 让人物按小说内部逻辑自己"走"**。作家是"看不见的手",不是"指挥家"。 + +**席勒化** = 思想先行 → 安排情节。作家是"传声筒"。 + +| 维度 | 莎士比亚化 | 席勒化 | +|-----|----------|------| +| 起点 | 人物性格 + 现实环境 | 思想/主题 | +| 推力 | 小说内部逻辑 | 作家意图 | +| 人物 | 自主行动 | 被动执行 | +| 主题 | 自然浮现 | 强行表达 | +| 阅读感受 | "不得不这样" | "作家让我知道" | + +(/bifeiyu-shakespeare) + +## 书中案例 + +### 案例 1:施耐庵《水浒》林冲 + +- **雪**铺垫林冲烤火(性格是"好犯人")→ 林冲处理火(积极改造)→ 雪压塌房(被动改变) +- **风**阻止林冲关门 → 推动石头靠门 → 隔开陆谦等人 → 泄露阴谋 +- **每一步都是必然**——但林冲没想"我要造反" +- **结果**:林冲自己"走"上梁山,作家都"说不上话" + +### 案例 2:蒲松龄《促织》成名 + +- 不是"作者让成名倒霉" +- 是"迁讷的性格 + 猾黠的里胥" → 性格碰撞 → 必然命运 +- 蒲松龄只给了 4 个字"为人迁讷"——然后小说自己跑 + +### 案例 3:莫泊桑 改写版 + +- 改写版("王宝强张小芳")漏洞百出——因为它**席勒化**:想批判虚荣,安排了人物去借项链 +- 原文(路瓦赛夫妇)逻辑自洽——因为**莎士比亚化**:人物性格 + 时代背景 → 自然借项链 + +(同一作品《项链》在"心慈手狠"单元里从另一个角度出现——"发红的手"是作家的狠。角度不同,两个都保留,见 [mercy-ruth.md](mercy-ruth.md) 案例 1。) + +### 案例 4:曹雪芹《红楼梦》王熙凤 + +- 王熙凤的性格 → 决定了她会"管事" +- 管的性格 + 贾府复杂关系 → 必然形成"毒设相思局" +- 作家没有"派"她杀人——是她自己"走"到那一步 + +(同一人物王熙凤在"心慈手狠"单元里从命运重量角度出现——"哭向金陵事更哀",见 [mercy-ruth.md](mercy-ruth.md) 案例 5。) + +(以上案例均出自/bifeiyu-shakespeare) + +## 执行步骤 + +### 步骤 1:把"主题"翻译成"环境" + +错误: + +```yaml +主题:批判官僚主义 +情节:主角觉醒,揭发腐败 +→ 席勒化 +``` + +正确: + +```yaml +环境:一个具体的官僚场景(办事、推诿、签字) +人物:性格鲜明的当事人 +→ 让"官僚场景"和"人物性格"碰撞,主题自然浮现 +→ 莎士比亚化 +``` + +### 步骤 2:设计"性格 + 现实"的推力链 + +``` +人物 A 的性格 = X +人物 B 的性格 = Y +X 与 Y 碰撞 → 必然产生事件 Z +Z 引发环境 E 的变化 +E 反过来作用于 A 和 B +``` + +**关键**:每个环节都要可推导,不能跳跃。 + +### 步骤 3:检验"作家发言权" + +写完后问自己: + +> "如果我(作家)什么都不说,人物会自己走到这一步吗?" + +- 会的 → 莎士比亚化 +- 不会 → 你还在席勒化 + +### 步骤 4:检验"必然性" + +把小说里**任何一个事件**删掉,看故事: + +- [ ] 完全垮掉?→ 这个事件是必然的,留 +- [ ] 不影响?→ 这个事件是多余的,删 +- [ ] 换个别的事件也能承接?→ 你可能没找到真正必然的事件 + +林冲的雪、风、石头——**删一个故事就垮**。这就是必然性。 + +### 步骤 5:让作家"沉默" + +**终极检验**: + +> 写完之后,把所有"作家发言"删掉(解释、议论、心理分析),看读者能不能读懂。 + +- 能 → 莎士比亚化 +- 不能 → 你在替人物说话——回到席勒化 + +(/bifeiyu-shakespeare) + +## 触发场景 + +1. 你的人物"按你安排"行动 → ❌ 席勒化预警 +2. 你的情节"为了主题服务" → ❌ 思想先行 +3. 你的角色"在小说里变了"但你不知道为什么 → ✅ 莎士比亚化成功 +4. 你想表达"批判 X"但不知道怎么办 → 把 X 变成**环境/对手**,让主角去碰撞 +5. 你的人物有"觉醒"或"转变" → 必须有**环境/事件**的推动链 + +(/bifeiyu-shakespeare) + +## 一句话总结 + +> **作家越小,权力越大;作家越大,权力越小。** + +(/bifeiyu-shakespeare) + +## 与其他方法的关系 + +- 与 `show-and-omission`(展示与留白)的 bifeiyu-anti-logic 互补:莎士比亚化用逻辑,反逻辑是它的"另一面" +- 与 `character-presentation`(人物呈现)的 bifeiyu-character-fate 同源:性格即命运 = 性格 + 现实的逻辑推演 +- 与 `narrative-momentum`(叙事动力)的 bifeiyu-momentum 关联:莎士比亚化是"势"能产生的方法 +- 与本 skill 的 bifeiyu-mercy-ruth(心慈手狠)配对:作家要"手狠"才能让逻辑自己走——不能因心软去救人物,见 [mercy-ruth.md](mercy-ruth.md) + +(/bifeiyu-shakespeare) diff --git a/framework/catalog/pi/skills/theme-and-stance/references/theme-demonstration.md b/framework/catalog/pi/skills/theme-and-stance/references/theme-demonstration.md new file mode 100644 index 0000000..3f31c0d --- /dev/null +++ b/framework/catalog/pi/skills/theme-and-stance/references/theme-demonstration.md @@ -0,0 +1,130 @@ +# 主题只能演示,不能说出 + +> 来源单元:《Story Engineering》(Larry Brooks)story-engineering/theme-demonstrate-not-tell,Part 4 · Implementing Theme。 +> 本文件管主题的呈现层:主题是什么、为什么不能说出、怎么演示。立场如何藏进环境与人物、从碰撞中自然浮现(防主题先行)见 [stance-by-logic.md](stance-by-logic.md);作者对人物受苦的态度见 [mercy-ruth.md](mercy-ruth.md);沉重题材用幽默立立场见 [humor-as-stance.md](humor-as-stance.md);边界与易混方法见 [boundaries-and-pitfalls.md](boundaries-and-pitfalls.md)。 + +## 原文引文 + +> "Theme is best implemented in your story when it is demonstrated by the story itself, and the characters in it, rather than when it is told by them... the difference between active voice and passive voice, almost. A demonstrated theme is active. A stated theme is passive." +> +> — Larry Brooks, *Story Engineering* (2011), Part 4 + +主题落地在你的故事里,最好的方式是故事本身和其中的人物把它**演示**出来,而不是由他们把它**说**出来……这差别几乎就像主动语态和被动语态的差别。被演示的主题是主动的。被陈述的主题是被动的。(/theme-demonstrate-not-tell,白话转述) + +## 方法核心 + +"主题"是故事对现实照亮什么。但主题不能被**说出**,只能被**演示**。读者必须自己"看出"主题,角色/作者替读者"说" = 失败。(/theme-demonstrate-not-tell) + +**核心规则**: + +- **陈述主题(Told Theme)**:角色说"我爱我的祖国" / 叙述者说"这是一个关于失去的故事" / 章节开头"寓言"——**失败** +- **演示主题(Demonstrated Theme)**:角色在关键时刻做选择,选择本身演示主题——**成功** + +**Show vs Tell 在主题上的应用**: + +- Show = 角色的**行为**演示主题(在关键决策中"做"什么) +- Tell = 角色的**台词**说主题(在对话中"讲"什么) +- 主题必须 Show,不要 Tell + +**为什么 Tell 失败**: + +- 角色一旦"说出"主题,角色就变成作者传声筒,失去主体性 +- 读者立刻出戏,因为感觉"被教" +- 主题的"由读者自己发现"乐趣消失 + +**演示主题的 3 种方法**: + +1. **决策演示**:关键场景里,角色在 A/B 中选,选什么 = 主题立场 +2. **结构演示**:故事整体结构(开头 vs 结尾,失败 vs 成功)演示主题 +3. **反讽演示**:角色"说"一套,"做"另一套,反讽 = 主题 + +(/theme-demonstrate-not-tell) + +## 跨书呼应:同一条原理的另外两种说法 + +"主题只能演示、不能说出"不止一本书这么说。毕飞宇把"说出主题"叫席勒化,把"演示主题"叫莎士比亚化(/bifeiyu-shakespeare): + +> 「思想性的传递需要作家的思想,其实更需要作家的艺术才能。在美学上,说空话有一个专业的名词,叫'席勒化',把思想性落实到艺术性上,也有一个专业名词,叫'莎士比亚化'。」 + +在他的对照表里,"主题"一栏正是两种写法的分水岭:莎士比亚化的主题**自然浮现**,席勒化的主题**强行表达**。完整对照表与操作方法(把主题翻译成环境、性格碰撞推力链、作家沉默)见 [stance-by-logic.md](stance-by-logic.md)。 + +余华讨论沉重题材时同样要求批判不沦为说教与谩骂——他给出的解法是幽默作为结构:用幽默的态度与现实建立关系,既不妥协也不对抗。见 [humor-as-stance.md](humor-as-stance.md)。 + +(/bifeiyu-shakespeare;/humor-as-structure) + +## 书中案例 + +### 案例 1:The Cider House Rules(《苹果酒屋法则》) + +- **问题**:John Irving 想"写一个关于堕胎的故事" +- **方法论的使用**:不让任何角色"谈论堕胎对不对"——通过 Homer Wells(主角)在"成为医生"和"留在孤儿院"之间的反复选择演示主题 +- **结论**:主题 = "选择 vs 强加"——通过 Homer 的选择,从不通过说教 +- **结果**:获奥斯卡最佳改编剧本 + +(/theme-demonstrate-not-tell) + +### 案例 2:The Lovely Bones(《可爱的骨头》) + +- **问题**:Alice Sebold 想"写一个关于失去与宽恕的故事" +- **方法论的使用**:不让 Susie's 天上独白"讲"宽恕——通过她看着家人如何处理悲痛、凶手如何生活来演示 +- **结论**:主题被"看"出来,不被"说"出来 +- **结果**:1000 万册 + +(/theme-demonstrate-not-tell) + +### 案例 3:反例——常见的"主题演讲" + +- **问题**:写作者写完一章,让角色在对话中说"我们这个社会..." +- **方法论的使用**:诊断 = 主题 Tell 化 +- **结论**:删掉这段对话,改成角色在关键场景做"那个社会议题"的选择 +- **结果**:改稿后不再"说教" + +(/theme-demonstrate-not-tell) + +## 执行步骤 + +1. **确认主题** + - 完成标准:1 句话说清"我的故事想照亮什么" + +2. **扫描全文:有没有 Tell?** + - 完成标准:列出 3 类"Tell"出现位置 + - 角色对话中的主题陈述 + - 叙述者/旁白的主题点明 + - 章节开头的"寓言式"开篇 + - 提示:搜"主题关键词 + 说出动词"(说/讲/道/谓/示) + +3. **改成 Show** + - 完成标准:每个 Tell 都有对应的 Show 改写 + - 方法:把"角色说"改成"角色在场景中做" + - 例:把"他说'我爱我的祖国'"改成"他在撤退时为救一个同胞兵,错过了撤离船" + +4. **增加 1-2 个"主题演示"场景** + - 完成标准:至少 1 个新场景,角色的"做"演示主题 + - 不必是大幅动作,小决策即可 + +(/theme-demonstrate-not-tell) + +## 触发场景与语言信号 + +用户会在什么情境下需要这个方法(/theme-demonstrate-not-tell): + +1. **主题植入**:"我故事主题是 X,怎么表达?" +2. **说教修复**:"我被反馈'说教味重',怎么改?" +3. **写作完成前自检**:"我主题被说出来过吗?" +4. **教学/讨论**:"主题怎么写才有艺术感?" + +语言信号: + +- "主题说教 / 主题直白 / 主题表达" +- "show don't tell / 演示 vs 告诉" +- "我的故事像在讲道理" +- "怎么表达主题" + +## 中文落地(中文适配) + +Brooks 的方法从英文小说中总结,落地中文时 Tell 信号与检索法如下(/theme-demonstrate-not-tell 源内已有中文检索法 + 中文适配补充): + +- Tell 扫描用中文动词检索:搜"主题关键词 + 说出动词"(说/讲/道/谓/示)。这是源单元自带的中文检索法。 +- 书中反例案例本就是中文语境:角色在对话中说"我们这个社会..."——这类"主题演讲"在中文小说里同样扎眼。 +- 三种演示法(决策/结构/反讽)不依赖语言特性,中文同样适用;书中的 Show 改写例子("他在撤退时为救一个同胞兵,错过了撤离船")已是中文表达。 +- 中文适配补充:中文古典小说的"陈述主题"形态特别多——说书人旁白、章首开篇词、章末总结诗、直接议论评点,改稿时都属于 Tell,按同一标准扫描(读者自己看出 vs 作者替读者说出)。判断标准不变,只是中文 Tell 的常见载体清单更长。 diff --git a/framework/catalog/pi/skills/theme-and-stance/references/theme-stance-checklist.md b/framework/catalog/pi/skills/theme-and-stance/references/theme-stance-checklist.md new file mode 100644 index 0000000..5163b74 --- /dev/null +++ b/framework/catalog/pi/skills/theme-and-stance/references/theme-stance-checklist.md @@ -0,0 +1,114 @@ +# 主题与立场检查清单 + +> 汇总四个源单元的可执行检查项,按写作进程排列:写前(定主题、建碰撞)→ 写中(演示、防手软、幽默距离)→ 改稿(五项检验)。 +> 方法细节与案例见 references/ 各文件。 + +## 一、写前:定主题与建碰撞 + +**1. 主题确认**(/theme-demonstrate-not-tell): + +- [ ] 能用 1 句话说清"我的故事想照亮什么" +- [ ] 这句话具体到"关于 X 中的 Y",不是"关于人性""关于爱"这类模糊哲学 + +**2. 把主题翻译成环境**(/bifeiyu-shakespeare): + +- [ ] 没有写成"主题:批判 X → 情节:主角觉醒揭发 X"(这是席勒化) +- [ ] 写成了:环境 = 一个具体的 X 场景(如官僚场景:办事、推诿、签字);人物 = 性格鲜明的当事人 +- [ ] 想批判 X,就把 X 变成环境/对手,让主角去碰撞,主题自然浮现 + +**3. 设计推力链**(/bifeiyu-shakespeare): + +- [ ] 人物 A 的性格 = X,人物 B 的性格 = Y +- [ ] X 与 Y 碰撞 → 必然产生事件 Z +- [ ] Z 引发环境 E 的变化,E 反过来作用于 A 和 B +- [ ] 每个环节都可推导,没有跳跃 + +## 二、写中:演示主题、防手软、选幽默距离 + +**4. 主题用"做"演示,不用"说"**(/theme-demonstrate-not-tell): + +- [ ] 关键场景里让人物在 A/B 之间选,选什么 = 主题立场(决策演示) +- [ ] 整体结构(开头 vs 结尾,失败 vs 成功)能对照出主题(结构演示) +- [ ] 若用人物说一套做一套,反讽必须清晰,读者看得出来(反讽演示) +- [ ] 至少 1-2 个小决策场景,角色的"做"演示主题(不必大幅动作) + +**5. 防手软自查**(/bifeiyu-mercy-ruth): + +- [ ] 我写这个人物之前确认过"我爱他"(不爱/蔑视的人物删掉或改写) +- [ ] 写到关键处没有出现"我舍不得她死……算了,让她活下去吧" +- [ ] 没有"算了他不该这么惨" +- [ ] 没有"突然让他走运" +- [ ] 出现以上任何一个 → 回到性格 + 逻辑,把该给的代价给足("作家是小说的上帝,但上帝不能滥用慈悲") + +**6. 沉重题材选幽默距离**(/humor-as-structure): + +- [ ] 已明确题材的沉重点:涉及哪些痛苦/压迫/荒诞 +- [ ] 已判断直接写会变成什么:控诉?苦情?谩骂? +- [ ] 已选定幽默距离:近距(人物在苦难中自嘲,余华式)/ 中距(叙述者冷幽默,卡夫卡式)/ 远距(引入荒诞元素制造间离,布尔加科夫式,撒旦访问莫斯科) +- [ ] 让荒诞自行呈现:不直接批判,写荒诞细节(翻箱倒柜找文件、电话接通后无数声音、永远找不到的负责人;让人物在荒诞场景中一本正经地行事) +- [ ] 全文至少 3 处"让人发笑但笑后不安"的细节 +- [ ] 笑的对象是环境/制度,不是人物;人物在苦难中仍然有尊严、有逻辑、有笑声 +- [ ] 读者对人物是共情而非俯视 + +## 三、改稿:五项检验 + +**7. Tell 扫描**(/theme-demonstrate-not-tell): + +- [ ] 搜"主题关键词 + 说出动词"(说/讲/道/谓/示) +- [ ] 标出三类 Tell 位置:角色对话中的主题陈述;叙述者/旁白的主题点明;章节开头的"寓言式"开篇 +- [ ] 每个 Tell 都有对应的 Show 改写:把"角色说"改成"角色在场景中做"(例:把"他说'我爱我的祖国'"改成"他在撤退时为救一个同胞兵,错过了撤离船") +- [ ] 删掉 Tell 后补上了 Show(只删不补 = 没有主题) + +**8. 作家发言权检验**(/bifeiyu-shakespeare): + +- [ ] 问自己:"如果我(作家)什么都不说,人物会自己走到这一步吗?" +- [ ] 会的 → 莎士比亚化;不会 → 还在席勒化 + +**9. 必然性检验**(/bifeiyu-shakespeare): + +把小说里任何一个事件删掉,看故事: + +- [ ] 完全垮掉?→ 这个事件是必然的,留 +- [ ] 不影响?→ 这个事件是多余的,删 +- [ ] 换个别的事件也能承接?→ 可能没找到真正必然的事件(参照:林冲的雪、风、石头——删一个故事就垮) + +**10. 作家沉默终极检验**(/bifeiyu-shakespeare): + +- [ ] 把所有"作家发言"删掉(解释、议论、心理分析),读者还能读懂 +- [ ] 能 → 莎士比亚化;不能 → 在替人物说话,回到席勒化 + +**11. 手狠检验**(/bifeiyu-mercy-ruth): + +- [ ] 主角受够他应受的苦了吗? +- [ ] 反派得到他应得的报应了吗? +- [ ] 悲剧够不够"悲"? +- [ ] 每个主要人物有 1-3 个"狠瞬间"(参照:成名儿子自杀;林冲风雪山神庙杀人;马蒂尔德发红的手;苔丝被处死;闰土叫"老爷";王熙凤哭向金陵) +- [ ] 狠的成分检验:狠但带着爱 → 心慈手狠;狠只是狠 → 虐待狂;狠带着蔑视 → 失败 +- [ ] 有甜有狠(全是甜 = 心慈手不狠;全是狠 = 手狠心不慈) + +**12. 幽默结构检验**(/humor-as-structure): + +- [ ] 幽默是贯穿全文的态度,还是偶尔的俏皮话?是俏皮话就回到第 6 步重选距离,让幽默成为整体结构 +- [ ] 幽默段落和沉重段落交替:没有全程搞笑,也没有全程压抑 +- [ ] 幽默的"度"控制得恰如其分:不过度也不不足 +- [ ] 没有让读者感到作者在嘲笑人物(幽默变嘲笑 = 失败) +- [ ] 幽默没有消解批判力量(读者不会觉得"这也没什么大不了") + +## 四、快速排错表 + +| 症状 | 诊断 | 处方 | 来源 | +|------|------|------|------| +| 被反馈"说教味重" | 主题 Tell 化 | Tell 扫描,改成关键场景里的选择与行动 | /theme-demonstrate-not-tell | +| 人物"按你安排"行动 | 席勒化预警 | 把主题翻译成环境,让性格碰撞 | /bifeiyu-shakespeare | +| 情节"为了主题服务" | 思想先行 | 把思想藏进环境 | /bifeiyu-shakespeare | +| 想"批判 X"但不知怎么办 | 主题没有环境化 | 把 X 变成环境/对手,让主角去碰撞 | /bifeiyu-shakespeare | +| 人物"觉醒"很突兀 | 缺推动链 | 觉醒前补"压垮骆驼的最后一根稻草"——具体的、可推导的 | /bifeiyu-shakespeare | +| 该受苦但你舍不得 | 手软了 | 手狠检验;让人物承担他应承担的 | /bifeiyu-mercy-ruth | +| 悲剧"不够悲" | 心慈但手不狠 | 找到并写下"狠瞬间" | /bifeiyu-mercy-ruth | +| 人物命运突然变好 | 手软的痕迹(先看逻辑) | 命运不可逆 | /bifeiyu-mercy-ruth | +| 写"坏人"笔下留情 | 太心慈 | 检验"爱不爱他",爱就给足报应 | /bifeiyu-mercy-ruth | +| 主角不敢让他失败 | 心慈手不狠 | 主角的命运必须有重量 | /bifeiyu-mercy-ruth | +| 沉重题材写得压抑、愤怒 | 在与现实对抗(或妥协) | 选幽默距离,让荒诞自行呈现 | /humor-as-structure | +| 批判变成说教或谩骂 | 没有距离 | 远距幽默(引入荒诞元素制造间离) | /humor-as-structure | +| 被反馈"太沉重了""读着压抑" | 全程无轻松 | 幽默段落与沉重段落交替 | /humor-as-structure | +| 读者感到作者在嘲笑人物 | 幽默变嘲笑 | 笑的对象换成环境/制度,保住人物尊严 | /humor-as-structure | diff --git a/framework/primitives/__init__.py b/framework/primitives/__init__.py new file mode 100644 index 0000000..df87faf --- /dev/null +++ b/framework/primitives/__init__.py @@ -0,0 +1,5 @@ +"""与具体 Agent 宿主无关的框架原语。""" + +from .execution import FrameworkEvent, FrameworkExecutionRequest, FrameworkExecutionResult + +__all__ = ["FrameworkEvent", "FrameworkExecutionRequest", "FrameworkExecutionResult"] diff --git a/framework/primitives/artifacts.py b/framework/primitives/artifacts.py new file mode 100644 index 0000000..5220554 --- /dev/null +++ b/framework/primitives/artifacts.py @@ -0,0 +1,108 @@ +"""框架运行工件的确定性写入、校验与重放工具。""" + +from __future__ import annotations + +import hashlib +import json +import os +import tempfile +from pathlib import Path +from typing import Any, Iterable, Mapping + + +class ArtifactError(ValueError): + """运行工件不完整、格式非法或序列不连续。""" + + +def payload_sha256(value: Any) -> str: + """按稳定 JSON 计算 payload 摘要。""" + + raw = json.dumps(value, ensure_ascii=False, sort_keys=True, separators=(",", ":")) + return "sha256:" + hashlib.sha256(raw.encode("utf-8")).hexdigest() + + +def _validate_event(event: Mapping[str, Any], expected_seq: int) -> dict[str, Any]: + if not isinstance(event, Mapping): + raise ArtifactError("事件必须是对象") + source_seq = event.get("sourceSeq") + if source_seq != expected_seq: + raise ArtifactError( + f"事件序列不连续:期望 sourceSeq={expected_seq},实际 {source_seq!r}" + ) + if not event.get("framework") or not event.get("kind") or not event.get("phase"): + raise ArtifactError("事件缺少 framework/kind/phase") + return dict(event) + + +def write_jsonl_atomic(path: str | Path, events: Iterable[Mapping[str, Any]]) -> str: + """原子发布完整 JSONL 工件,返回文件摘要;发布前校验序列连续。""" + + target = Path(path) + target.parent.mkdir(parents=True, exist_ok=True) + lines: list[str] = [] + for expected_seq, event in enumerate(events, start=1): + validated = _validate_event(event, expected_seq) + lines.append(json.dumps(validated, ensure_ascii=False, sort_keys=True) + "\n") + if not lines: + raise ArtifactError("不能发布空运行工件") + content = "".join(lines).encode("utf-8") + descriptor, temporary_name = tempfile.mkstemp( + prefix=f".{target.name}.", dir=str(target.parent) + ) + temporary = Path(temporary_name) + try: + with os.fdopen(descriptor, "wb") as stream: + stream.write(content) + stream.flush() + os.fsync(stream.fileno()) + os.replace(temporary, target) + finally: + temporary.unlink(missing_ok=True) + return "sha256:" + hashlib.sha256(content).hexdigest() + + +def read_jsonl(path: str | Path, *, allow_seq_gap: bool = False) -> list[dict[str, Any]]: + """读取并校验 JSONL;默认拒绝缺失或重复 sourceSeq。""" + + source = Path(path) + try: + lines = source.read_text(encoding="utf-8").splitlines() + except (OSError, UnicodeError) as exc: + raise ArtifactError(f"运行工件不可读: {source}") from exc + events: list[dict[str, Any]] = [] + expected = 1 + for line_number, line in enumerate(lines, start=1): + if not line.strip(): + continue + try: + raw = json.loads(line) + except json.JSONDecodeError as exc: + raise ArtifactError(f"第 {line_number} 行不是合法 JSON") from exc + if not isinstance(raw, Mapping): + raise ArtifactError(f"第 {line_number} 行不是事件对象") + if allow_seq_gap: + source_seq = raw.get("sourceSeq") + if not isinstance(source_seq, int) or source_seq < expected: + raise ArtifactError(f"第 {line_number} 行 sourceSeq 非法或重复") + expected = source_seq + 1 + events.append(dict(raw)) + else: + events.append(_validate_event(raw, expected)) + expected += 1 + if not events: + raise ArtifactError("运行工件为空") + return events + + +def detect_seq_gaps(events: Iterable[Mapping[str, Any]]) -> list[tuple[int, int]]: + """返回排序后发现的 sourceSeq 缺口,不修改输入。""" + + values = sorted(int(event["sourceSeq"]) for event in events) + gaps: list[tuple[int, int]] = [] + for left, right in zip(values, values[1:]): + if right > left + 1: + gaps.append((left + 1, right - 1)) + return gaps + + +__all__ = ["ArtifactError", "detect_seq_gaps", "payload_sha256", "read_jsonl", "write_jsonl_atomic"] diff --git a/framework/primitives/execution.py b/framework/primitives/execution.py new file mode 100644 index 0000000..2cf2d8f --- /dev/null +++ b/framework/primitives/execution.py @@ -0,0 +1,124 @@ +"""框架端口对象。 + +这些对象只描述一次 Agent 执行所需的通用材料,不加载 Muse 角色合同、数据库或业务状态。 +""" + +from __future__ import annotations + +from dataclasses import dataclass, field +from typing import Any, Mapping + + +@dataclass(frozen=True) +class FrameworkExecutionRequest: + """已由业务侧解析完成的框架执行请求。""" + + system_prompt: str + user_content: str + tool_allowlist: tuple[str, ...] = () + timeout_seconds: float = 600.0 + request_id: str | None = None + session_mode: str = "fresh" + + def __post_init__(self) -> None: + if not isinstance(self.system_prompt, str) or not self.system_prompt.strip(): + raise ValueError("system_prompt 必须是非空字符串") + if not isinstance(self.user_content, str) or not self.user_content.strip(): + raise ValueError("user_content 必须是非空字符串") + if self.session_mode not in {"fresh", "continue"}: + raise ValueError("session_mode 必须是 fresh 或 continue") + if self.timeout_seconds <= 0: + raise ValueError("timeout_seconds 必须大于 0") + if any(not isinstance(name, str) or not name.strip() for name in self.tool_allowlist): + raise ValueError("tool_allowlist 必须是非空工具名数组") + + def as_dict(self) -> dict[str, Any]: + return { + "systemPrompt": self.system_prompt, + "userContent": self.user_content, + "toolAllowlist": list(self.tool_allowlist), + "timeoutSeconds": self.timeout_seconds, + "requestId": self.request_id, + "sessionMode": self.session_mode, + } + + +@dataclass(frozen=True) +class FrameworkEvent: + """框架原生事件的通用观察材料。""" + + framework: str + framework_version: str + session_id: str | None + source_seq: int + kind: str + phase: str + safe_details: Mapping[str, Any] = field(default_factory=dict) + payload_sha256: str | None = None + source_event_id: str | None = None + run_id: str | None = None + observed_at: str = "" + + def __post_init__(self) -> None: + if not self.framework or not self.framework_version: + raise ValueError("FrameworkEvent 缺少 framework/framework_version") + if self.source_seq < 1: + raise ValueError("FrameworkEvent source_seq 必须从 1 开始") + if self.kind not in {"session", "turn", "step", "model", "tool", "agent", "transport", "unknown"}: + raise ValueError(f"未知 FrameworkEvent kind: {self.kind}") + if self.phase not in {"started", "progress", "completed", "failed"}: + raise ValueError(f"未知 FrameworkEvent phase: {self.phase}") + if not self.observed_at: + raise ValueError("FrameworkEvent observed_at 不能为空") + + def as_dict(self) -> dict[str, Any]: + return { + "framework": self.framework, + "frameworkVersion": self.framework_version, + "sessionId": self.session_id, + "sourceSeq": self.source_seq, + "sourceEventId": self.source_event_id, + "runId": self.run_id, + "kind": self.kind, + "phase": self.phase, + "safeDetails": dict(self.safe_details), + "payloadSha256": self.payload_sha256, + "observedAt": self.observed_at, + } + + +@dataclass(frozen=True) +class FrameworkExecutionResult: + """框架执行结果;业务层仍需运行自己的 Schema 与主权门。""" + + status: str + final_text: str | None + requested_model: str + actual_models: tuple[str, ...] = () + session_id: str | None = None + artifact_locator: str | None = None + trace_digest: str | None = None + + def __post_init__(self) -> None: + if self.status not in {"completed", "failed", "cancelled", "timed_out", "invalid_output"}: + raise ValueError(f"未知框架结果状态: {self.status}") + if not self.requested_model: + raise ValueError("FrameworkExecutionResult requested_model 不能为空") + + def as_dict(self) -> dict[str, Any]: + return { + "status": self.status, + "finalText": self.final_text, + "requestedModel": self.requested_model, + "actualModels": list(self.actual_models), + "sessionId": self.session_id, + "artifactLocator": self.artifact_locator, + "traceDigest": self.trace_digest, + } + + +__all__ = [ + "FrameworkEvent", + "FrameworkExecutionRequest", + "FrameworkExecutionResult", +] diff --git a/framework/primitives/schemas/framework_event.schema.json b/framework/primitives/schemas/framework_event.schema.json new file mode 100644 index 0000000..9668bf5 --- /dev/null +++ b/framework/primitives/schemas/framework_event.schema.json @@ -0,0 +1,21 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://muse.local/framework/framework-event-v1.schema.json", + "title": "FrameworkEvent", + "type": "object", + "additionalProperties": false, + "required": ["framework", "frameworkVersion", "sessionId", "sourceSeq", "kind", "phase", "safeDetails", "observedAt"], + "properties": { + "framework": {"type": "string", "minLength": 1, "maxLength": 64}, + "frameworkVersion": {"type": "string", "minLength": 1, "maxLength": 64}, + "sessionId": {"type": ["string", "null"], "maxLength": 128}, + "sourceSeq": {"type": "integer", "minimum": 1}, + "sourceEventId": {"type": ["string", "null"], "maxLength": 256}, + "runId": {"type": ["string", "null"], "maxLength": 128}, + "kind": {"enum": ["session", "turn", "step", "model", "tool", "agent", "transport", "unknown"]}, + "phase": {"enum": ["started", "progress", "completed", "failed"]}, + "safeDetails": {"type": "object"}, + "payloadSha256": {"type": ["string", "null"], "pattern": "^sha256:[0-9a-f]{64}$"}, + "observedAt": {"type": "string", "minLength": 1} + } +} diff --git a/framework/primitives/schemas/framework_execution_request.schema.json b/framework/primitives/schemas/framework_execution_request.schema.json new file mode 100644 index 0000000..b290c61 --- /dev/null +++ b/framework/primitives/schemas/framework_execution_request.schema.json @@ -0,0 +1,20 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://muse.local/framework/framework-execution-request-v1.schema.json", + "title": "FrameworkExecutionRequest", + "type": "object", + "additionalProperties": false, + "required": ["systemPrompt", "userContent", "toolAllowlist", "timeoutSeconds", "sessionMode"], + "properties": { + "systemPrompt": {"type": "string", "minLength": 1}, + "userContent": {"type": "string", "minLength": 1}, + "toolAllowlist": { + "type": "array", + "items": {"type": "string", "pattern": "^[A-Za-z0-9_-]{1,64}$"}, + "uniqueItems": true + }, + "timeoutSeconds": {"type": "number", "exclusiveMinimum": 0}, + "requestId": {"type": ["string", "null"], "maxLength": 128}, + "sessionMode": {"enum": ["fresh", "continue"]} + } +} diff --git a/framework/primitives/schemas/framework_execution_result.schema.json b/framework/primitives/schemas/framework_execution_result.schema.json new file mode 100644 index 0000000..496851c --- /dev/null +++ b/framework/primitives/schemas/framework_execution_result.schema.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://muse.local/framework/framework-execution-result-v1.schema.json", + "title": "FrameworkExecutionResult", + "type": "object", + "additionalProperties": false, + "required": ["status", "finalText", "requestedModel", "actualModels", "sessionId", "artifactLocator", "traceDigest"], + "properties": { + "status": {"enum": ["completed", "failed", "cancelled", "timed_out", "invalid_output"]}, + "finalText": {"type": ["string", "null"]}, + "requestedModel": {"type": "string", "minLength": 1}, + "actualModels": {"type": "array", "items": {"type": "string"}}, + "sessionId": {"type": ["string", "null"]}, + "artifactLocator": {"type": ["string", "null"]}, + "traceDigest": {"type": ["string", "null"], "pattern": "^sha256:[0-9a-f]{64}$"} + } +} diff --git a/harness/skills_index.py b/harness/skills_index.py deleted file mode 100644 index 1fceef2..0000000 --- a/harness/skills_index.py +++ /dev/null @@ -1,200 +0,0 @@ -#!/usr/bin/env python3 -"""生成与机械校验 Skill 发现总索引 `.agent/skills/_index.md`。 - -发现合同(见 AGENTS.md §3):任何 agent(不限宿主)读 AGENTS.md 后必须读总索引, -按 `skill_file` 读取所需能力的 `SKILL.md`;不依赖任何 coding agent 的 skill 自动发现, -物理目录位置只是索引里的数据。 - -索引只登记三字段: -- `skill_name`:目录名,即调用名; -- `skill_file`:合同文件路径(来自 `harness/manifests/skills.json` 的 `skill_path`); -- `skill_description`:适用与边界描述,与 SKILL.md frontmatter 的 `description` 逐字一致 - (frontmatter 是 SoT,索引是生成物)。 - -生命周期分组取自 `harness/manifests/skills.json` 的 `lifecycle` 字段;取值定义见 -`harness/specs/skill-quality-rubric.md`。 - -用法: - .venv/bin/python harness/skills_index.py --check # 校验索引与磁盘、manifest 一致(默认) - .venv/bin/python harness/skills_index.py --write # 按磁盘与 manifest 重新生成索引 -""" -from __future__ import annotations - -import argparse -import difflib -from pathlib import Path -from typing import Optional, Sequence - -import yaml - -# 生命周期域 → 索引分节标题;顺序即索引分节顺序,标题沿用既有中文域名。 -LIFECYCLE_SECTIONS: tuple[tuple[str, str], ...] = ( - ("platform", "0 平台底座"), - ("ingest", "1 素材导入与拆解"), - ("knowledge", "2 知识与上下文供给"), - ("concept", "3 概念与前期设计"), - ("planning", "4 结构与规划"), - ("writing", "5 正文写作与呈现"), - ("review", "6 检测、评分与诊断"), - ("humanization", "7 去 AI 味与人感"), - ("sovereignty", "8 候选主权与落库"), -) - -INDEX_RELPATH = Path(".agent") / "skills" / "_index.md" -MANIFEST_RELPATH = Path("harness") / "manifests" / "skills.json" - -HEADER = """# Skill 发现总索引 - -> **发现合同**:任何 agent(不限宿主)读 [`AGENTS.md`](../../AGENTS.md) 后必须读本索引,\ -需要某项能力时按 `skill_file` 读对应 `SKILL.md`。发现只靠 AGENTS.md → 本索引 → SKILL.md \ -的渐进披露,不依赖任何 coding agent 的 skill 自动发现;物理目录位置只是索引里的数据。 - -本索引只登记三字段:`skill_name`(目录名,即调用名)、`skill_file`(合同文件路径)、\ -`skill_description`(适用与边界描述,与 SKILL.md frontmatter 逐字一致,frontmatter 是 SoT)。\ -分类字段(`lifecycle` / `invocation` / `side_effects` / `compounding`)逐个登记在 \ -[`harness/manifests/skills.json`](../../harness/manifests/skills.json),由 \ -`harness/skill_harness.py` 机械校验,不在本索引重复。 - -本文件由 `harness/skills_index.py --write` 生成,手改会被覆盖;一致性由 `--check` 与 \ -`tests/architecture/test_skills_index.py` 机械把关。按生命周期分域,共 {count} 个 skill。 -""" - - -def _load_manifest(root: Path) -> dict[str, dict[str, str]]: - """读取 skills.json,返回 name → 条目;仅接受与磁盘一致的规范路径。""" - import json - - manifest_path = root / MANIFEST_RELPATH - data = json.loads(manifest_path.read_text(encoding="utf-8")) - entries = data["skills"] if isinstance(data, dict) and "skills" in data else data - result: dict[str, dict[str, str]] = {} - for entry in entries: - result[entry["name"]] = entry - return result - - -def _read_description(skill_md: Path) -> str: - """取 SKILL.md frontmatter 的 description 并折叠换行为单行。""" - text = skill_md.read_text(encoding="utf-8") - if not text.startswith("---\n"): - raise ValueError(f"{skill_md}: 缺少 frontmatter") - end = text.index("\n---\n", 4) - fields = yaml.safe_load(text[4:end]) - description = (fields or {}).get("description") - if not isinstance(description, str) or not description.strip(): - raise ValueError(f"{skill_md}: frontmatter 缺少非空 description") - # YAML 多行块按行折叠;中文行间接缝不需要空格。 - return "".join(line.strip() for line in description.strip().splitlines()) - - -def build_index_text(root: Path) -> tuple[str, int]: - """按磁盘 + skills.json 组装索引全文,返回 (文本, skill 数)。""" - skills_root = root / ".agent" / "skills" - manifest = _load_manifest(root) - - # 磁盘事实:目录名 → description;与 manifest 双向对账。 - disk: dict[str, str] = {} - for skill_dir in sorted(skills_root.iterdir(), key=lambda item: item.name): - skill_md = skill_dir / "SKILL.md" - if not skill_md.exists(): - continue - disk[skill_dir.name] = _read_description(skill_md) - - only_disk = sorted(set(disk) - set(manifest)) - only_manifest = sorted(set(manifest) - set(disk)) - if only_disk or only_manifest: - parts = [] - if only_disk: - parts.append(f"磁盘有而 skills.json 缺: {', '.join(only_disk)}") - if only_manifest: - parts.append(f"skills.json 有而磁盘缺: {', '.join(only_manifest)}") - raise ValueError("磁盘与 skills.json 不一致:" + ";".join(parts)) - - for name, entry in manifest.items(): - expected = f".agent/skills/{name}/SKILL.md" - if entry.get("skill_path") != expected: - raise ValueError( - f"{name}: skills.json skill_path={entry.get('skill_path')!r}," - f"期望 {expected!r}" - ) - lifecycle = entry.get("lifecycle") - if lifecycle not in dict(LIFECYCLE_SECTIONS): - raise ValueError(f"{name}: 未知 lifecycle={lifecycle!r}") - - lines: list[str] = [HEADER.format(count=len(disk)).rstrip()] - for lifecycle, title in LIFECYCLE_SECTIONS: - names = sorted( - name for name, entry in manifest.items() if entry["lifecycle"] == lifecycle - ) - if not names: - continue - lines.append("") - lines.append(f"## {title}") - lines.append("") - lines.append("| skill_name | skill_file | skill_description |") - lines.append("|---|---|---|") - for name in names: - lines.append( - f"| {name} | `.agent/skills/{name}/SKILL.md` | {disk[name]} |" - ) - lines.append("") - return "\n".join(lines), len(disk) - - -def check(root: Path) -> Optional[str]: - """校验现有索引与重建结果一致;一致返回 None,否则返回差异文本。""" - expected, _ = build_index_text(root) - index_path = root / INDEX_RELPATH - actual = ( - index_path.read_text(encoding="utf-8") if index_path.exists() else "" - ) - if actual == expected: - return None - diff = difflib.unified_diff( - actual.splitlines(keepends=True), - expected.splitlines(keepends=True), - fromfile=str(INDEX_RELPATH) + "(现状)", - tofile=str(INDEX_RELPATH) + "(按磁盘与 skills.json 重建)", - n=2, - ) - return "".join(diff) - - -def main(argv: Optional[Sequence[str]] = None) -> int: - parser = argparse.ArgumentParser( - description="生成与机械校验 .agent/skills/_index.md(三字段发现总索引)。" - ) - parser.add_argument("--root", default=".", help="项目根目录,默认为当前目录") - group = parser.add_mutually_exclusive_group() - group.add_argument( - "--check", - action="store_true", - help="校验索引与磁盘、skills.json 一致(默认模式)", - ) - group.add_argument( - "--write", action="store_true", help="按磁盘与 skills.json 重新生成索引" - ) - args = parser.parse_args(argv) - root = Path(args.root).resolve() - - try: - if args.write: - text, count = build_index_text(root) - (root / INDEX_RELPATH).write_text(text, encoding="utf-8") - print(f"已重新生成 {INDEX_RELPATH}({count} 个 skill)") - return 0 - diff = check(root) - except (ValueError, KeyError, FileNotFoundError) as error: - print(f"skills_index 失败:{error}") - return 2 - - if diff is None: - print("skills_index 一致:索引与磁盘、skills.json 相符") - return 0 - print("skills_index 漂移:请用 harness/skills_index.py --write 重新生成") - print(diff) - return 1 - - -if __name__ == "__main__": - raise SystemExit(main()) diff --git a/muse/_skills_index.md b/muse/_skills_index.md new file mode 100644 index 0000000..51f43f4 --- /dev/null +++ b/muse/_skills_index.md @@ -0,0 +1,95 @@ +# Muse 编排 Skill 索引 + +> **业务发现合同**:主代理与业务编排按本索引的 `skill_file` 读取对应 `SKILL.md`。编排 Skill 不进入 Agent 框架的运行期 catalog;物理位置完全取自 manifest 的 `skill_path`。 + +本索引只登记三字段:`skill_name`、`skill_file`、`skill_description`。分类字段与责任方仍以 [`lifecycle/quality/harness/manifests/skills.json`](lifecycle/quality/harness/manifests/skills.json) 为准,由 `muse/lifecycle/quality/harness` 机械校验。 + +本文件由 `muse/lifecycle/quality/harness/skills_index.py --write` 生成,手改会被覆盖;按生命周期分域,共 43 个编排 skill。 + +## 0 平台底座 + +| skill_name | skill_file | skill_description | +|---|---|---| +| access-database | `muse/authority/evidence/skills/access-database/SKILL.md` | 通过唯一受控入口查询或修改 muse-example PostgreSQL,并应用可审计 DDL。主会话或 Skill 需要通用数据库访问时使用;专用导入、嵌入和检索仍走各自 Skill,禁止裸连和一次性脚本。 | +| call-content-model | `muse/platform/llm/skills/call-content-model/SKILL.md` | 通过 New-API 的统一治理入口调用内容模型,执行额度窗口、模型降级、重试和 JSON 提取。清洗、拆书或知识审核需要 MiniMax 等内容模型时使用;不得裸调外部服务。 | +| dispatch-agent-task | `muse/lifecycle/dispatch/skills/dispatch-agent-task/SKILL.md` | 把冻结角色任务包派发给 Agent 框架子代理执行并自动留痕:注入角色 prompt 与输出 Schema、按白名单开放工具、归一框架事件流写入代理事件账本,结构化输出经 Draft 2020-12 校验后返回回执。当前生产入口使用 Pi;DSH headless 仅有独立的无工具 fresh 对照适配器,尚未接入本 Skill 的生产派发。执行 writer/planner/detector/judge/extractor 角色任务时使用;不经框架的直接 HTTP 批处理走 execute-role-task;本 Skill 不做补证、重写等业务决策。 | +| execute-role-task | `muse/platform/llm/skills/execute-role-task/SKILL.md` | 以冻结 RoleExecutionProfile 运行一次不经框架的直接 HTTP 角色调用,校验模型策略、期限、预算、结构和输入输出哈希并返回 RoleExecutionReceipt。writer、planner、extractor、detector 或 judge 的无工具批处理需要直接模型调用时使用;需要框架原生 ReAct/工具循环的子代理执行走 dispatch-agent-task;能力探针刷新交给 refresh-runtime-probe,本 Skill 不负责保存 raw、登记运行或裁决业务结果。 | +| record-run-evidence | `muse/authority/evidence/skills/record-run-evidence/SKILL.md` | 记录模型调用、运行登记、不可变回执、CAS revision 和受控 raw 证据。执行器或业务 Skill 需要持久化一次运行、追加失败证据、补回执引用或管理 raw 备份时使用;不负责调用模型或裁决内容质量。 | +| refresh-runtime-probe | `muse/platform/llm/skills/refresh-runtime-probe/SKILL.md` | 通过 execute-role-task 用当前 writer 提示词、结构和档案实跑一次极小合成角色任务,刷新运行探针记录与自哈希并把完整配置写到新文件。角色合同或运行时、模型策略版本变化导致执行门失败时使用;不就地覆盖原配置,不把离线预览伪装成成功证明。 | + +## 1 素材导入与拆解 + +| skill_name | skill_file | skill_description | +|---|---|---| +| backup-work-extraction | `muse/content/entity/skills/ingest/backup-work-extraction/SKILL.md` | 对单本作品的 upgrade_book 派生状态做七域一致性备份、离线复验、回滚演练与精确恢复。需要在重置或高危维护前留下可复验快照、或需要把作品抽取状态恢复到某个备份点时使用;不负责重置、定向修复和正常按窗抽取。 | +| clean-book-text | `muse/content/entity/skills/ingest/clean-book-text/SKILL.md` | 识别并删除参考书或旧稿中的广告、水印、作者拉票和乱码噪声,同时保留逐段审计。静态导入后仍有语义垃圾时使用;模型只提候选,确定性守卫决定是否删除,绝不改写正文。首次 txt 分章落库归 import-book;本 Skill 只在已有 block 上做语义噪声清洗。 | +| deconstruct-book | `muse/content/entity/skills/ingest/deconstruct-book/SKILL.md` | 从完整存量作品逆向拆出章节细纲、阶段大纲、实体线索和脱敏写作范式。需要解析用户旧稿或参考书全书时使用;不负责把作品面知识按窗升格,也不确认产物。 | +| extract-work-knowledge | `muse/content/entity/skills/ingest/extract-work-knowledge/SKILL.md` | 将已完成拆解的作品正文按窗口抽取为 upgrade_book 实体、关系与演变草稿。作品完成拆书后需要建立本书知识面、续跑抽取窗口或查看抽取进度时使用;备份/恢复归 backup-work-extraction,全量重置归 reset-work-extraction,定向修复/迁移归 repair-work-extraction,本 Skill 不负责这三类维护。 | +| import-book | `muse/content/entity/skills/ingest/import-book/SKILL.md` | 将参考书或用户旧稿 txt 确定性分章并写入作品、章节、正文 block 和来源档案。首次导入完整书稿或明确重导时使用;不调用模型、不改写正文。导入后散落广告/乱码/拉票等语义噪声归 clean-book-text,本 Skill 不做 M3 探测删除。 | +| inspect-parse-health | `muse/content/entity/skills/ingest/inspect-parse-health/SKILL.md` | 只读体检拆书与升格两条管线的终态,并导出范式卡与升格实体卡样张。需要在一批跑完后机械核对章级细纲、窗级大纲、范式出卡和作品面升格四层健康度、或需要呈报样张时使用;不负责解析、抽取和任何修复动作。 | +| repair-work-extraction | `muse/content/entity/skills/ingest/repair-work-extraction/SKILL.md` | 对已有 upgrade_book 抽取结果做定向修复与存量迁移,包括 legacy failed 窗口恢复、单卡质量修复、presence 重复清理、存量窗口章号定位和存量回洗。需要修补个别窗口或行而不是重跑全书时使用;正常按窗抽取归 extract-work-knowledge,全量重置归 reset-work-extraction,备份恢复归 backup-work-extraction。 | +| reset-work-extraction | `muse/content/entity/skills/ingest/reset-work-extraction/SKILL.md` | 全量重抽前预览或清空单本作品的 upgrade_book 派生状态,把窗口退回 pending。需要对一本书重新跑一遍作品面抽取时使用;正常按窗抽取归 extract-work-knowledge,定向修复归 repair-work-extraction,备份恢复归 backup-work-extraction。 | + +## 2 知识与上下文供给 + +| skill_name | skill_file | skill_description | +|---|---|---| +| assemble-context | `muse/lifecycle/context/skills/assemble-context/SKILL.md` | 按冻结点从 PostgreSQL 读取可信来源,组装可审计上下文,并为 writer、detector、judge、planner 或 extractor 生成最小投影。创作或评测调用模型前需要受控上下文时使用。 | +| embed-knowledge | `muse/lifecycle/context/skills/embed-knowledge/SKILL.md` | 使用固定 Qwen3 嵌入模型将知识草稿或实体批量写入 pgvector,并按内容哈希幂等处理 owner 与版本。知识行需要建立或刷新检索向量时使用;不嵌入参考书全文。 | +| extract-chapter-knowledge | `muse/content/entity/skills/extract/extract-chapter-knowledge/SKILL.md` | 从已接受章节抽取实体、关系、事件和叙事状态草稿,并提出既有知识更新。正文进入 Canonical 后需要章后增量知识时使用;只产草稿,不自动确认知识。 | +| freeze-context | `muse/lifecycle/context/skills/freeze-context/SKILL.md` | 将截至指定章号的来源冻结为可重复清单,并校验授权、版本、未来信息泄漏和只读原文装载。上下文组装或回放评测需要稳定时间边界时使用;不调用模型、不写正式数据。 | +| review-knowledge-cards | `muse/content/entity/skills/review/review-knowledge-cards/SKILL.md` | 以三种编辑视角审核公共知识卡的成立性、创作可用性和跨书复用性,并写回 pass、revise 或 reject。拆书产出公共卡后使用;不负责生成卡或确认作品私有知识。 | +| search-knowledge | `muse/lifecycle/context/skills/search-knowledge/SKILL.md` | 将创作意图嵌入后从 pgvector 召回知识,并按绑定、状态和 aiContext 权限裁剪结果。管理审查或上下文组装需要知识候选时使用;不返回参考书全文,不绕过作品绑定。 | + +## 3 概念与前期设计 + +| skill_name | skill_file | skill_description | +|---|---|---| +| design-story-foundation | `muse/lifecycle/flow/skills/book/design-story-foundation/SKILL.md` | 在正式规划前固化作品根设定,按固定三级章节树生成可比较的前期设计候选。用户仍在单文档前期设计阶段时使用;不写正文、不落库、不替用户定稿。不适用于合并多案(归 merge-story-candidates)或正式规划落库(归 plan-story)。 | +| merge-story-candidates | `muse/lifecycle/flow/skills/book/merge-story-candidates/SKILL.md` | 把多份已完成的前期设计候选逐章串行统合成一份新候选,一级章节一个 fresh 代理,权威顺序固定为根设定优先。用户明确要求综合多案时使用;不生成候选、不做机械门校验、不改前期设计 SoT。 | + +## 4 结构与规划 + +| skill_name | skill_file | skill_description | +|---|---|---| +| plan-chapter | `muse/lifecycle/flow/skills/chapter/plan-chapter/SKILL.md` | 根据已确认规划、叙事状态和冻结事实生成下一章结构细纲草稿。正文生成前需要明确章目标、事件因果、出场实体、伏笔动作和章末钩子时使用;不写正文、不读取目标章答案。书级设定/大纲/装配归 plan-story;本 Skill 是 section_type=fine_outline 的唯一写入方(经 persist_planning.py --owner-skill plan-chapter)。 | +| plan-story | `muse/lifecycle/flow/skills/book/plan-story/SKILL.md` | 按正式 schema 生成或修订作品设定包、大纲、知识卡、状态和装配草稿。前期方向已由用户选定并进入正式规划,或续作需要调整规划时使用;不写正文,未确认产物不进入生成上下文。单章 fine_outline(含 writer 硬依赖字段)只归 plan-chapter;本 Skill 不得写入 section_type=fine_outline。 | + +## 5 正文写作与呈现 + +| skill_name | skill_file | skill_description | +|---|---|---| +| expand-scene | `muse/content/work/skills/generate/expand-scene/SKILL.md` | 在既有场景内补充动作链、对话潜台词、感官细节和环境互动。用户认为某个场景过薄并明确要求扩写时使用;不新开场景、不改落点、不夹带新设定。点名改情节/翻案归 rewrite-selection;只修语病/标点/节奏归 polish-prose;AI 味须先 diagnose-ai-flavor,本槽不得绕过。 | +| polish-prose | `muse/content/work/skills/generate/polish-prose/SKILL.md` | 修正候选或既有正文的错字、语病、标点、节奏和角色声音指纹(非规则级去 AI 味)。用户只要求改善表达层时使用;不得改变情节事实、场景结构或对白语义。场景加厚归 expand-scene;点名改范围/翻案归 rewrite-selection;AI 味检测与修订归 diagnose-ai-flavor → revise-ai-flavor,本 Skill 不得自称去 AI 味入口。 | +| rewrite-selection | `muse/content/work/skills/generate/rewrite-selection/SKILL.md` | 按用户意见重写指定段落或场景,并校验范围、事实锚和版本。用户明确点名修改范围时使用;范围外原文不动,不顺手改规划或知识卡。场景过薄只加厚归 expand-scene;只修表达层归 polish-prose;AI 味须先 diagnose-ai-flavor,本槽不得绕过。 | +| write-next-chapter | `muse/content/work/skills/generate/write-next-chapter/SKILL.md` | 按已确认细纲、冻结事实和动态篇幅合同生成下一整章候选。作品需要续写下一章且输入合同完整时使用;不自行检索、不改规划、不把候选直接写入 Canonical。 | + +## 6 检测、评分与诊断 + +| skill_name | skill_file | skill_description | +|---|---|---| +| adjudicate-quality-gate | `muse/lifecycle/quality/skills/mechanical/adjudicate-quality-gate/SKILL.md` | 从不可变逐层回执构建 Gate 输入,并按父仓专题-04 的固定顺序产出 Gate A/B 终态与可核验 receipt。回放评测收集完逐样本脱敏结果、需要一个不可协商的通过/不通过裁决时使用;不评分、不改样本、不放宽阈值。 | +| check-content-consistency | `muse/lifecycle/quality/skills/semantic/check-content-consistency/SKILL.md` | 检查正文或细纲候选的结构、事实、角色状态、能力代价、伏笔和证据缺口。候选进入用户决策或独立评分前使用;只产检测报告,不修改候选。 | +| evaluate-frozen-replay | `muse/lifecycle/quality/skills/replay/evaluate-frozen-replay/SKILL.md` | 编排细纲隔离回放:把参考作品冻结到 as_of 章号,跑三臂 planner、盲 detector 与双盲 judge,产出可审计的逐样本结果。需要验证知识或上下文方案对细纲质量是否有增益时使用;阻断未来信息、未授权来源和不可接受的候选流入生产。 | +| load-replay-reference-work | `muse/lifecycle/quality/skills/replay/load-replay-reference-work/SKILL.md` | 在单个只读事务内从实验库装配正文回放的真实临时配置:来源证明、授权快照、目标 scaffold 拆分、冻结历史与预注册卡,写到仓库外临时文件。回放要从仓内合成夹具切到真实作品时使用;只 SELECT,不查询目标章正文,不把原书写进 Git。 | +| optimize-content-quality | `muse/lifecycle/quality/skills/judge/optimize-content-quality/SKILL.md` | 根据 score-content-quality 的独立评分,锁定最低质量维度并归因到 prompt、上下文或设定层,只出单变量改进建议。候选稳定不达标且需要定位改进来源时使用;不执行重生成、不改 rubric、不自行提交代码。 | +| replay-writer-gate | `muse/lifecycle/quality/skills/replay/replay-writer-gate/SKILL.md` | 执行正文 A/B/C 三臂隔离回放:构造并校验三臂 WriterContext、跑写手与盲评、结算预算与 raw 租约,产出逐样本脱敏结果。需要用真实作品验证卡索引对正文质量是否有增益时使用;不产生 Gate 终态,不把原书正文写进仓库。 | +| score-content-quality | `muse/lifecycle/quality/skills/judge/score-content-quality/SKILL.md` | 按独立 rubric 评分在线正文、正文回放或细纲回放,产出逐维分数、引文证据与理由。候选交付用户前或回放实验需要独立质量判断时使用;只评分不裁决——集合级通过/不通过归 adjudicate-quality-gate;不改候选、不放宽阈值。 | + +## 7 去 AI 味与人感 + +| skill_name | skill_file | skill_description | +|---|---|---| +| capture-ai-flavor-cases | `muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/SKILL.md` | 从已有作品或创作反馈中抽取可复核的 AI 味案例卡,保留来源哈希与位置并做来源重验证。需要反向积累人感样例、记录一次写作事故或批量回填既有作品时使用;不做标注确认与规则升格,不直接修改正文、范式或生产规则。 | +| diagnose-ai-flavor | `muse/lifecycle/quality/humanization/skills/diagnose-ai-flavor/SKILL.md` | 技能 3 诊断:对目标正文跑 active 规则库,产出带精确片段与证据的发现清单,检测完成自动落库。只查不改;没有本产物,revise-ai-flavor 拒绝启动。 | +| establish-voice-baseline | `muse/lifecycle/quality/humanization/skills/establish-voice-baseline/SKILL.md` | 技能 1 定基线:作品建立或新角色登场时,把已确认正文与作者样张产出的声音账做结构校验、grounding 门后版本化落库。不产正文;是修订门禁与前置预防的对照物。 | +| prevent-ai-flavor | `muse/lifecycle/quality/humanization/skills/prevent-ai-flavor/SKILL.md` | 技能 2 前置预防:生成前组装写作上下文合同——active 规则的负约束(附反例)加声音账的正样例与保护项。不碰正文,只供上下文组装消费。 | +| promote-ai-flavor-rule | `muse/lifecycle/quality/humanization/skills/promote-ai-flavor-rule/SKILL.md` | 把已标注的 AI 味案例卡沿 canonical→样例→规则候选→评测→激活的升格链推进,并负责降级。需要确认案例卡、投影四类样例、归纳规则候选、跑合同回放或审批激活时使用;不做案例采集与扫描,也不改正文。 | +| revise-ai-flavor | `muse/lifecycle/quality/humanization/skills/revise-ai-flavor/SKILL.md` | 技能 4 修订:在诊断产物与作者同意之上执行最小 patch,过硬门、复扫与成对选择校验,产出候选稿与审计报告。没诊断不启动;人不点头永远是候选。 | + +## 8 候选主权与落库 + +| skill_name | skill_file | skill_description | +|---|---|---| +| confirm-knowledge-draft | `muse/content/entity/skills/sovereignty/confirm-knowledge-draft/SKILL.md` | 用户明确确认后把知识草稿翻成作品正式知识面,写入实体或关系、绑定知识库并迁移向量 owner。抽取或拆书产出的卡需要转正时使用;不处理正文候选、规划确认和冲突裁决。 | +| decide-candidate | `muse/content/work/skills/sovereignty/decide-candidate/SKILL.md` | 据用户明确指令接受、合并或丢弃 Shadow 正文候选并更新 Canonical。仅主会话在用户决定后调用;知识卡归 confirm-knowledge-draft,规划归 plan-story。 | diff --git a/db/ddl/100-example规划与冻结.sql b/muse/authority/db/ddl/100-example规划与冻结.sql similarity index 100% rename from db/ddl/100-example规划与冻结.sql rename to muse/authority/db/ddl/100-example规划与冻结.sql diff --git a/db/ddl/101-example-raw.sql b/muse/authority/db/ddl/101-example-raw.sql similarity index 100% rename from db/ddl/101-example-raw.sql rename to muse/authority/db/ddl/101-example-raw.sql diff --git a/db/ddl/102-example智能体技能登记.sql b/muse/authority/db/ddl/102-example智能体技能登记.sql similarity index 100% rename from db/ddl/102-example智能体技能登记.sql rename to muse/authority/db/ddl/102-example智能体技能登记.sql diff --git a/db/ddl/103-example评测隔离引擎强制.sql b/muse/authority/db/ddl/103-example评测隔离引擎强制.sql similarity index 100% rename from db/ddl/103-example评测隔离引擎强制.sql rename to muse/authority/db/ddl/103-example评测隔离引擎强制.sql diff --git a/db/ddl/104-example-ai-flavor-cases.sql b/muse/authority/db/ddl/104-example-ai-flavor-cases.sql similarity index 100% rename from db/ddl/104-example-ai-flavor-cases.sql rename to muse/authority/db/ddl/104-example-ai-flavor-cases.sql diff --git a/db/ddl/105-example候选语义审查.sql b/muse/authority/db/ddl/105-example候选语义审查.sql similarity index 100% rename from db/ddl/105-example候选语义审查.sql rename to muse/authority/db/ddl/105-example候选语义审查.sql diff --git a/db/ddl/106-example事实增量.sql b/muse/authority/db/ddl/106-example事实增量.sql similarity index 100% rename from db/ddl/106-example事实增量.sql rename to muse/authority/db/ddl/106-example事实增量.sql diff --git a/db/ddl/107-example投影登记.sql b/muse/authority/db/ddl/107-example投影登记.sql similarity index 100% rename from db/ddl/107-example投影登记.sql rename to muse/authority/db/ddl/107-example投影登记.sql diff --git a/db/ddl/108-example经验升格.sql b/muse/authority/db/ddl/108-example经验升格.sql similarity index 100% rename from db/ddl/108-example经验升格.sql rename to muse/authority/db/ddl/108-example经验升格.sql diff --git a/db/ddl/109-example候选状态CAS.sql b/muse/authority/db/ddl/109-example候选状态CAS.sql similarity index 100% rename from db/ddl/109-example候选状态CAS.sql rename to muse/authority/db/ddl/109-example候选状态CAS.sql diff --git a/db/ddl/110-example-voice-baseline.sql b/muse/authority/db/ddl/110-example-voice-baseline.sql similarity index 100% rename from db/ddl/110-example-voice-baseline.sql rename to muse/authority/db/ddl/110-example-voice-baseline.sql diff --git a/db/ddl/111-example-humanization规则与样例.sql b/muse/authority/db/ddl/111-example-humanization规则与样例.sql similarity index 100% rename from db/ddl/111-example-humanization规则与样例.sql rename to muse/authority/db/ddl/111-example-humanization规则与样例.sql diff --git a/db/ddl/112-example角色模型策略与登记路径.sql b/muse/authority/db/ddl/112-example角色模型策略与登记路径.sql similarity index 93% rename from db/ddl/112-example角色模型策略与登记路径.sql rename to muse/authority/db/ddl/112-example角色模型策略与登记路径.sql index ab8b04d..3ecebf7 100644 --- a/db/ddl/112-example角色模型策略与登记路径.sql +++ b/muse/authority/db/ddl/112-example角色模型策略与登记路径.sql @@ -19,7 +19,7 @@ COMMENT ON COLUMN example_llm_call.model_match IS '实际模型是否符合冻结 RoleExecutionProfile 的模型策略;由执行 profile/回执哈希链证明。'; COMMENT ON TABLE example_agent_role IS - '五个 prompt 管理角色的库内影子;稳定合同 Git 权威位于 .agent/docs/architecture/角色合同.md,身份提示位于 .agent/agents/*.md。'; + '五个 prompt 管理角色的库内影子;稳定合同 Git 权威位于 muse/sot/角色合同.md,身份提示位于 .agent/agents/*.md。'; COMMENT ON COLUMN example_agent_role.model IS '保留兼容列;角色模型由派发 profile 决定,本列保持 NULL。'; COMMENT ON TABLE example_skill IS diff --git a/db/ddl/113-example代理事件账本.sql b/muse/authority/db/ddl/113-example代理事件账本.sql similarity index 100% rename from db/ddl/113-example代理事件账本.sql rename to muse/authority/db/ddl/113-example代理事件账本.sql diff --git a/db/ddl/114-example冻结幂等键-清单加上下文对.sql b/muse/authority/db/ddl/114-example冻结幂等键-清单加上下文对.sql similarity index 100% rename from db/ddl/114-example冻结幂等键-清单加上下文对.sql rename to muse/authority/db/ddl/114-example冻结幂等键-清单加上下文对.sql diff --git a/db/ddl/90-主仓ALTER摘录-V9V10V14V30.sql b/muse/authority/db/ddl/90-主仓ALTER摘录-V9V10V14V30.sql similarity index 100% rename from db/ddl/90-主仓ALTER摘录-V9V10V14V30.sql rename to muse/authority/db/ddl/90-主仓ALTER摘录-V9V10V14V30.sql diff --git a/db/ddl/91-example实验私货.sql b/muse/authority/db/ddl/91-example实验私货.sql similarity index 100% rename from db/ddl/91-example实验私货.sql rename to muse/authority/db/ddl/91-example实验私货.sql diff --git a/db/ddl/92-example清洗日志.sql b/muse/authority/db/ddl/92-example清洗日志.sql similarity index 100% rename from db/ddl/92-example清洗日志.sql rename to muse/authority/db/ddl/92-example清洗日志.sql diff --git a/db/ddl/93-example大纲聚合.sql b/muse/authority/db/ddl/93-example大纲聚合.sql similarity index 100% rename from db/ddl/93-example大纲聚合.sql rename to muse/authority/db/ddl/93-example大纲聚合.sql diff --git a/db/ddl/94-example作品面升格.sql b/muse/authority/db/ddl/94-example作品面升格.sql similarity index 100% rename from db/ddl/94-example作品面升格.sql rename to muse/authority/db/ddl/94-example作品面升格.sql diff --git a/db/ddl/95-example额度账本.sql b/muse/authority/db/ddl/95-example额度账本.sql similarity index 100% rename from db/ddl/95-example额度账本.sql rename to muse/authority/db/ddl/95-example额度账本.sql diff --git a/db/ddl/96-example参考作品授权快照.sql b/muse/authority/db/ddl/96-example参考作品授权快照.sql similarity index 100% rename from db/ddl/96-example参考作品授权快照.sql rename to muse/authority/db/ddl/96-example参考作品授权快照.sql diff --git a/db/ddl/97-example模型调用明细.sql b/muse/authority/db/ddl/97-example模型调用明细.sql similarity index 100% rename from db/ddl/97-example模型调用明细.sql rename to muse/authority/db/ddl/97-example模型调用明细.sql diff --git a/db/ddl/98-example运行与回执与质量结果.sql b/muse/authority/db/ddl/98-example运行与回执与质量结果.sql similarity index 100% rename from db/ddl/98-example运行与回执与质量结果.sql rename to muse/authority/db/ddl/98-example运行与回执与质量结果.sql diff --git a/db/ddl/99-example候选与决策.sql b/muse/authority/db/ddl/99-example候选与决策.sql similarity index 100% rename from db/ddl/99-example候选与决策.sql rename to muse/authority/db/ddl/99-example候选与决策.sql diff --git a/db/ddl/V1__init_content_schema.sql b/muse/authority/db/ddl/V1__init_content_schema.sql similarity index 100% rename from db/ddl/V1__init_content_schema.sql rename to muse/authority/db/ddl/V1__init_content_schema.sql diff --git a/db/ddl/V26__fix_content_softdelete_order_uk_partial.sql b/muse/authority/db/ddl/V26__fix_content_softdelete_order_uk_partial.sql similarity index 100% rename from db/ddl/V26__fix_content_softdelete_order_uk_partial.sql rename to muse/authority/db/ddl/V26__fix_content_softdelete_order_uk_partial.sql diff --git a/db/ddl/V3__init_meta_schema.sql b/muse/authority/db/ddl/V3__init_meta_schema.sql similarity index 100% rename from db/ddl/V3__init_meta_schema.sql rename to muse/authority/db/ddl/V3__init_meta_schema.sql diff --git a/db/ddl/V5__init_knowledge_schema.sql b/muse/authority/db/ddl/V5__init_knowledge_schema.sql similarity index 100% rename from db/ddl/V5__init_knowledge_schema.sql rename to muse/authority/db/ddl/V5__init_knowledge_schema.sql diff --git a/db/表映射.md b/muse/authority/db/表映射.md similarity index 97% rename from db/表映射.md rename to muse/authority/db/表映射.md index 00015b2..85d73dd 100644 --- a/db/表映射.md +++ b/muse/authority/db/表映射.md @@ -1,7 +1,7 @@ # muse-example 表 ↔ 主仓迁移来源映射(A2 审查面) > 口径(创始人拍板③ 2026-07-10):主仓表**原样不改列**;实验私货全进 `example_*` 前缀。 -> 建表方式:`db/ddl/` 下文件经 `access-database` skill `apply`,主仓部分为 `muse-cloud/sql/muse/` 原文拷贝或逐字摘录。 +> 建表方式:`muse/authority/db/ddl/` 下文件经 `access-database` skill `apply`,主仓部分为 `muse-cloud/sql/muse/` 原文拷贝或逐字摘录。 > 已应用顺序:V1 → V3 → V5 → 90-ALTER摘录 → V26 → 91-example(2026-07-13)→ 97/98(2026-07-30)→ 104 AI 味案例(2026-08-14)→ 105/106/107/108/109 先审后入与复利闭环(2026-08-14)→ 110 声音账(2026-08-15)-> 112 角色模型策略(2026-08-21)-> 113 代理事件账本(2026-08-22)。库内表现状以 `access-database` skill `tables` 实时输出为准。 > 96 不启用:`96-example参考作品授权快照.sql` 已实现但**决定不 apply**(单用户本地不做多租户授权机制,2026-07-30 拍板,见领域索引 §9);库内无该表。 @@ -30,7 +30,7 @@ | muse_knowledge_draft | V5 | V14(两快照列→varchar(128)) | **草稿**知识行(B2 拆书产出落此) | | muse_knowledge_binding | V5 | V14(同上) | 作品↔库绑定(C3 起用) | -## 实验私货表(`db/ddl/91` + 92 + 93 + 97 + 98 + 104 + 110;94/95 见库内现状) +## 实验私货表(`muse/authority/db/ddl/91` + 92 + 93 + 97 + 98 + 104 + 110;94/95 见库内现状) | 表 | 用途 | |---|---| diff --git a/db/连接信息.md b/muse/authority/db/连接信息.md similarity index 100% rename from db/连接信息.md rename to muse/authority/db/连接信息.md diff --git a/.agent/skills/access-database/SKILL.md b/muse/authority/evidence/skills/access-database/SKILL.md similarity index 63% rename from .agent/skills/access-database/SKILL.md rename to muse/authority/evidence/skills/access-database/SKILL.md index 1fb6718..b33ea61 100644 --- a/.agent/skills/access-database/SKILL.md +++ b/muse/authority/evidence/skills/access-database/SKILL.md @@ -1,6 +1,7 @@ --- name: access-database description: 通过唯一受控入口查询或修改 muse-example PostgreSQL,并应用可审计 DDL。主会话或 Skill 需要通用数据库访问时使用;专用导入、嵌入和检索仍走各自 Skill,禁止裸连和一次性脚本。 +disable-model-invocation: true --- # 访问 muse-example 数据库 @@ -11,27 +12,27 @@ description: 通过唯一受控入口查询或修改 muse-example PostgreSQL, ```bash # 查询:卡片式打印(默认最多 50 行、长值截 160 字) -.venv/bin/python .agent/skills/access-database/scripts/db.py query "SELECT id,title FROM muse_content_work" -.venv/bin/python .agent/skills/access-database/scripts/db.py query "SELECT ..." --json # JSON 数组输出(给脚本消费) -.venv/bin/python .agent/skills/access-database/scripts/db.py query "SELECT ..." --full # 长值不截断 -.venv/bin/python .agent/skills/access-database/scripts/db.py query "SELECT ..." --max 200 # 放宽行数 +.venv/bin/python muse/authority/evidence/skills/access-database/scripts/db.py query "SELECT id,title FROM muse_content_work" +.venv/bin/python muse/authority/evidence/skills/access-database/scripts/db.py query "SELECT ..." --json # JSON 数组输出(给脚本消费) +.venv/bin/python muse/authority/evidence/skills/access-database/scripts/db.py query "SELECT ..." --full # 长值不截断 +.venv/bin/python muse/authority/evidence/skills/access-database/scripts/db.py query "SELECT ..." --max 200 # 放宽行数 # 单条写操作(INSERT/UPDATE/DELETE,DELETE 必须带 WHERE):报影响行数;机械拒绝 DDL/裸删 -.venv/bin/python .agent/skills/access-database/scripts/db.py exec "UPDATE ... WHERE ..." +.venv/bin/python muse/authority/evidence/skills/access-database/scripts/db.py exec "UPDATE ... WHERE ..." # 参数化写操作:SQL 用 %s 占位,参数走服务端绑定(防注入;大内容不拼命令行);同样禁止 DDL/裸 DELETE -.venv/bin/python .agent/skills/access-database/scripts/db.py execparams "INSERT INTO example_raw_content(kind,content_sha256,content) VALUES (%s,%s,%s)" --param response --param --param "短文本" +.venv/bin/python muse/authority/evidence/skills/access-database/scripts/db.py execparams "INSERT INTO example_raw_content(kind,content_sha256,content) VALUES (%s,%s,%s)" --param response --param --param "短文本" # 大对象(raw 全文)经 stdin 传 JSON 数组(避开 shell 转义 / ARG_MAX): -.venv/bin/python .agent/skills/access-database/scripts/db.py execparams "INSERT ... VALUES (%s,%s)" --stdin < params.json # params.json = ["", "<完整全文>"] +.venv/bin/python muse/authority/evidence/skills/access-database/scripts/db.py execparams "INSERT ... VALUES (%s,%s)" --stdin < params.json # params.json = ["", "<完整全文>"] -# SQL 文件应用(DDL 唯一入口):整文件一个事务,失败全回滚;先落 db/ddl/ 再 apply -.venv/bin/python .agent/skills/access-database/scripts/db.py apply db/ddl/91-example实验私货.sql +# SQL 文件应用(DDL 唯一入口):整文件一个事务,失败全回滚;先落 muse/authority/db/ddl/ 再 apply +.venv/bin/python muse/authority/evidence/skills/access-database/scripts/db.py apply muse/authority/db/ddl/91-example实验私货.sql # 表清单+活行数(deleted=FALSE 计数,无 deleted 列的表计全行) -.venv/bin/python .agent/skills/access-database/scripts/db.py tables +.venv/bin/python muse/authority/evidence/skills/access-database/scripts/db.py tables # A3 种子:23 型 YAML → meta 表行(幂等可重跑;字段改动=改 YAML 后重跑) -.venv/bin/python .agent/skills/access-database/scripts/seed_schemas.py +.venv/bin/python muse/authority/evidence/skills/access-database/scripts/seed_schemas.py ``` ## 红线 @@ -39,12 +40,12 @@ description: 通过唯一受控入口查询或修改 muse-example PostgreSQL, - **只连 `muse-example`**:DSN 锁死在 `muse_db` 内;严禁另拼连接串去碰共享 PG 上的 muse_local / muse_slice_live / *_test。 - 软删约定照主仓:删除=UPDATE `deleted=TRUE`,不物理删(example_* 表同样遵守)。 - 批量导入/嵌入等专用写路径由 `import-book`/`embed-knowledge` Skill 封装(内部同走 psycopg 直连),本 Skill 承担通用查改;DDL 只经 `apply` 文件入口。 -- 建表/改表先落 `db/ddl/` 文件再 `apply`,不敲一次性 DDL——文件即审计;`exec`/`execparams` 机械拒绝 DDL 与无 WHERE 的 DELETE。 +- 建表/改表先落 `muse/authority/db/ddl/` 文件再 `apply`,不敲一次性 DDL——文件即审计;`exec`/`execparams` 机械拒绝 DDL 与无 WHERE 的 DELETE。 - 大对象写入(raw 全文等)走 `execparams` 参数化通道(大内容经 stdin JSON),不得把大内容拼进 `exec` 的 SQL 字符串(shell 转义 + ARG_MAX);参数化绑定同时防 SQL 注入。 ## 元数据驱动 -库内 `muse_meta_schema` / `muse_meta_field` / `muse_meta_visibility_policy` 是 23 型结构本体的权威行(A3 起);拆书与抽取的字段合同一律 `query` 读库取,不再读 `meta/schemas/` YAML(YAML 退为设计稿与种子来源)。 +库内 `muse_meta_schema` / `muse_meta_field` / `muse_meta_visibility_policy` 是 23 型结构本体的权威行(A3 起);拆书与抽取的字段合同一律 `query` 读库取,不再读 `muse/content/meta/schemas/` YAML(YAML 退为设计稿与种子来源)。 ## 数据边界 diff --git a/.agent/skills/access-database/scripts/db.py b/muse/authority/evidence/skills/access-database/scripts/db.py similarity index 100% rename from .agent/skills/access-database/scripts/db.py rename to muse/authority/evidence/skills/access-database/scripts/db.py diff --git a/.agent/skills/access-database/scripts/seed_schemas.py b/muse/authority/evidence/skills/access-database/scripts/seed_schemas.py similarity index 100% rename from .agent/skills/access-database/scripts/seed_schemas.py rename to muse/authority/evidence/skills/access-database/scripts/seed_schemas.py diff --git a/.agent/skills/access-database/scripts/sync_agent_registry.py b/muse/authority/evidence/skills/access-database/scripts/sync_agent_registry.py similarity index 91% rename from .agent/skills/access-database/scripts/sync_agent_registry.py rename to muse/authority/evidence/skills/access-database/scripts/sync_agent_registry.py index 01d8cf0..d280831 100644 --- a/.agent/skills/access-database/scripts/sync_agent_registry.py +++ b/muse/authority/evidence/skills/access-database/scripts/sync_agent_registry.py @@ -8,9 +8,9 @@ - 看板只读登记表、不读 Git。幂等可重跑(upsert),配置变更后重跑即同步。 跑法(仓库根目录): - .venv/bin/python .agent/skills/access-database/scripts/sync_agent_registry.py --check - .venv/bin/python .agent/skills/access-database/scripts/sync_agent_registry.py --check-db - .venv/bin/python .agent/skills/access-database/scripts/sync_agent_registry.py + .venv/bin/python muse/authority/evidence/skills/access-database/scripts/sync_agent_registry.py --check + .venv/bin/python muse/authority/evidence/skills/access-database/scripts/sync_agent_registry.py --check-db + .venv/bin/python muse/authority/evidence/skills/access-database/scripts/sync_agent_registry.py """ import argparse import json @@ -20,9 +20,13 @@ from pathlib import Path from muse_db import connect from muse_role_contract import ROLE_CONTRACT_RELATIVE_PATH, load_role_contract_catalog -ROOT = Path(__file__).resolve().parents[4] # .agent/skills/access-database/scripts → 仓库根 +ROOT = next( + parent + for parent in (Path(__file__).resolve().parent, *Path(__file__).resolve().parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) AGENTS_DIR = ROOT / ".agent" / "agents" -SKILLS_DIR = ROOT / ".agent" / "skills" +SKILL_ROOTS = (ROOT / ".agent" / "skills", ROOT / "muse") TABLE_RE = re.compile(r"\b(muse_[a-z_]+|example_[a-z_]+)\b") SKILL_NAME_RE = re.compile(r"^[a-z][a-z0-9]*(?:-[a-z0-9]+)+$") SKILL_FRONTMATTER_KEYS = frozenset({"name", "description", "disable-model-invocation"}) @@ -86,12 +90,16 @@ def validate_role_catalog(agents_dir: Path = AGENTS_DIR) -> list[tuple[Path, dic return entries -def validate_skill_catalog(skills_dir: Path = SKILLS_DIR) -> list[tuple[Path, dict]]: - """校验 Skill 目录、frontmatter 与动作式名称,返回稳定排序的目录项。""" +def validate_skill_catalog(skills_dir: Path | None = None) -> list[tuple[Path, dict]]: + """校验挂载面与 Muse 业务树中的 Skill,返回稳定排序的目录项。""" entries = [] seen = set() - for sk in sorted(skills_dir.glob("*/SKILL.md")): + roots = (skills_dir,) if skills_dir is not None else SKILL_ROOTS + skill_files = sorted( + {path for root in roots for path in root.rglob("SKILL.md")} + ) + for sk in skill_files: fm = parse_frontmatter(sk.read_text(encoding="utf-8")) name = fm.get("name", "") directory = sk.parent.name diff --git a/.agent/skills/record-run-evidence/SKILL.md b/muse/authority/evidence/skills/record-run-evidence/SKILL.md similarity index 100% rename from .agent/skills/record-run-evidence/SKILL.md rename to muse/authority/evidence/skills/record-run-evidence/SKILL.md diff --git a/.agent/skills/record-run-evidence/scripts/agent_trace.py b/muse/authority/evidence/skills/record-run-evidence/scripts/agent_trace.py similarity index 100% rename from .agent/skills/record-run-evidence/scripts/agent_trace.py rename to muse/authority/evidence/skills/record-run-evidence/scripts/agent_trace.py diff --git a/.agent/skills/record-run-evidence/scripts/file_cas.py b/muse/authority/evidence/skills/record-run-evidence/scripts/file_cas.py similarity index 100% rename from .agent/skills/record-run-evidence/scripts/file_cas.py rename to muse/authority/evidence/skills/record-run-evidence/scripts/file_cas.py diff --git a/.agent/skills/record-run-evidence/scripts/invariant_checks.py b/muse/authority/evidence/skills/record-run-evidence/scripts/invariant_checks.py similarity index 97% rename from .agent/skills/record-run-evidence/scripts/invariant_checks.py rename to muse/authority/evidence/skills/record-run-evidence/scripts/invariant_checks.py index f7df783..e98a0e0 100644 --- a/.agent/skills/record-run-evidence/scripts/invariant_checks.py +++ b/muse/authority/evidence/skills/record-run-evidence/scripts/invariant_checks.py @@ -12,7 +12,7 @@ I3 评测候选的质量结果可被生产视图过滤(带评测标记,不 I4 oracle 读侧红线:oracle/标准答案以 kind='oracle' 标记,生产模型输入不得包含(read-context 生产路径保证;此处校验标记完整)。 I5 COMPLETED 轮次封存:一轮声明的 raw 集合 == 实际落库集合(lease 声明的 content_hashes 数 == 实际 raw_content 行数)。 -跑法:.venv/bin/python .agent/skills/record-run-evidence/scripts/invariant_checks.py [--run-id X] +跑法:.venv/bin/python muse/authority/evidence/skills/record-run-evidence/scripts/invariant_checks.py [--run-id X] """ import argparse import json diff --git a/.agent/skills/record-run-evidence/scripts/lesson_registry.py b/muse/authority/evidence/skills/record-run-evidence/scripts/lesson_registry.py similarity index 100% rename from .agent/skills/record-run-evidence/scripts/lesson_registry.py rename to muse/authority/evidence/skills/record-run-evidence/scripts/lesson_registry.py diff --git a/.agent/skills/record-run-evidence/scripts/persist_llm_call.py b/muse/authority/evidence/skills/record-run-evidence/scripts/persist_llm_call.py similarity index 100% rename from .agent/skills/record-run-evidence/scripts/persist_llm_call.py rename to muse/authority/evidence/skills/record-run-evidence/scripts/persist_llm_call.py diff --git a/.agent/skills/record-run-evidence/scripts/persist_raw.py b/muse/authority/evidence/skills/record-run-evidence/scripts/persist_raw.py similarity index 100% rename from .agent/skills/record-run-evidence/scripts/persist_raw.py rename to muse/authority/evidence/skills/record-run-evidence/scripts/persist_raw.py diff --git a/.agent/skills/record-run-evidence/scripts/raw_vault.py b/muse/authority/evidence/skills/record-run-evidence/scripts/raw_vault.py similarity index 100% rename from .agent/skills/record-run-evidence/scripts/raw_vault.py rename to muse/authority/evidence/skills/record-run-evidence/scripts/raw_vault.py diff --git a/.agent/skills/record-run-evidence/scripts/record_failed_run.py b/muse/authority/evidence/skills/record-run-evidence/scripts/record_failed_run.py similarity index 100% rename from .agent/skills/record-run-evidence/scripts/record_failed_run.py rename to muse/authority/evidence/skills/record-run-evidence/scripts/record_failed_run.py diff --git a/.agent/skills/record-run-evidence/scripts/repair_receipt_evidence.py b/muse/authority/evidence/skills/record-run-evidence/scripts/repair_receipt_evidence.py similarity index 100% rename from .agent/skills/record-run-evidence/scripts/repair_receipt_evidence.py rename to muse/authority/evidence/skills/record-run-evidence/scripts/repair_receipt_evidence.py diff --git a/.agent/skills/record-run-evidence/scripts/run_registry.py b/muse/authority/evidence/skills/record-run-evidence/scripts/run_registry.py similarity index 100% rename from .agent/skills/record-run-evidence/scripts/run_registry.py rename to muse/authority/evidence/skills/record-run-evidence/scripts/run_registry.py diff --git a/dashboard/fixtures/README.md b/muse/authority/studio/read/fixtures/README.md similarity index 100% rename from dashboard/fixtures/README.md rename to muse/authority/studio/read/fixtures/README.md diff --git a/dashboard/fixtures/backfill-inventory-2026-08-13.json b/muse/authority/studio/read/fixtures/backfill-inventory-2026-08-13.json similarity index 100% rename from dashboard/fixtures/backfill-inventory-2026-08-13.json rename to muse/authority/studio/read/fixtures/backfill-inventory-2026-08-13.json diff --git a/dashboard/fixtures/revalidation-2026-08-14.json b/muse/authority/studio/read/fixtures/revalidation-2026-08-14.json similarity index 100% rename from dashboard/fixtures/revalidation-2026-08-14.json rename to muse/authority/studio/read/fixtures/revalidation-2026-08-14.json diff --git a/dashboard/server.py b/muse/authority/studio/read/server.py similarity index 99% rename from dashboard/server.py rename to muse/authority/studio/read/server.py index 0d649a3..784b841 100644 --- a/dashboard/server.py +++ b/muse/authority/studio/read/server.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 """只读可视化看板(muse-example 库)—— 纯 Python 标准库 HTTP 服务。 -合同:.agent/docs/architecture/可视化模块合同.md(唯一 SoT)。 +合同:muse/sot/可视化模块合同.md(唯一 SoT)。 布局:对齐 muse 的领域布局(作品 / 知识库 / 智能体 三空间 + 总览), 与领域索引(domains/_index.md)的领域分区一致——看板按领域看库,不按功能切。 命根子(验收按机械门查): @@ -10,7 +10,7 @@ 3. 不接会写的通道:不调用 decide-candidate / access-database Skill,只自己只读查库。 4. 挂了不牵连:进程崩了不影响库内正式内容与创作链。 视觉系统:dataviz 方法(已验证默认调色板,light/dark 双模式,状态色固定不主题化)。 -跑法:.venv/bin/python dashboard/server.py (默认 http://127.0.0.1:8765) +跑法:.venv/bin/python muse/authority/studio/read/server.py (默认 http://127.0.0.1:8765) """ import html import json @@ -2497,7 +2497,7 @@ def _run_decision_menu_panel(run_id: str, candidates: list, terminal_state, pipe # 预填改指令:绕开不可证缺口(阶段 0.1 选 A 时用) avoid = ";".join(f"避开「{h}」" for h in gap_hints[:2]) if gap_hints else "按语义/诊断理由修改" rewrite_cmd = ( - f".venv/bin/python .agent/skills/write-next-chapter/scripts/produce_next_chapter.py 3 " + f".venv/bin/python muse/content/work/skills/generate/write-next-chapter/scripts/produce_next_chapter.py 3 " f"--provider

--model " f"--instruction \"改:{avoid}。禁止细纲原句抄进正文;门符号只在舰队医疗舱语境。\"" ) diff --git a/dashboard/test_server_display.py b/muse/authority/studio/read/test_server_display.py similarity index 100% rename from dashboard/test_server_display.py rename to muse/authority/studio/read/test_server_display.py diff --git a/dashboard/decision_channel.py b/muse/authority/studio/write/decision/decision_channel.py similarity index 100% rename from dashboard/decision_channel.py rename to muse/authority/studio/write/decision/decision_channel.py diff --git a/dashboard/lesson_confirm.py b/muse/authority/studio/write/lesson/lesson_confirm.py similarity index 99% rename from dashboard/lesson_confirm.py rename to muse/authority/studio/write/lesson/lesson_confirm.py index f8692f0..41620be 100644 --- a/dashboard/lesson_confirm.py +++ b/muse/authority/studio/write/lesson/lesson_confirm.py @@ -20,7 +20,7 @@ HOST, PORT = "127.0.0.1", 8766 READONLY_BASE = "http://127.0.0.1:8765" ROOT = Path(__file__).resolve().parents[1] -EVIDENCE = ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +EVIDENCE = ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" if str(EVIDENCE) not in sys.path: sys.path.insert(0, str(EVIDENCE)) diff --git a/.agent/skills/dispatch-agent-task/scripts/read_tools.py b/muse/authority/tools/read/read_tools.py similarity index 100% rename from .agent/skills/dispatch-agent-task/scripts/read_tools.py rename to muse/authority/tools/read/read_tools.py diff --git a/.agent/skills/extract-chapter-knowledge/SKILL.md b/muse/content/entity/skills/extract/extract-chapter-knowledge/SKILL.md similarity index 100% rename from .agent/skills/extract-chapter-knowledge/SKILL.md rename to muse/content/entity/skills/extract/extract-chapter-knowledge/SKILL.md diff --git a/.agent/skills/extract-chapter-knowledge/scripts/dispatch_extraction_bridge.py b/muse/content/entity/skills/extract/extract-chapter-knowledge/scripts/dispatch_extraction_bridge.py similarity index 95% rename from .agent/skills/extract-chapter-knowledge/scripts/dispatch_extraction_bridge.py rename to muse/content/entity/skills/extract/extract-chapter-knowledge/scripts/dispatch_extraction_bridge.py index 74279a5..62121ec 100644 --- a/.agent/skills/extract-chapter-knowledge/scripts/dispatch_extraction_bridge.py +++ b/muse/content/entity/skills/extract/extract-chapter-knowledge/scripts/dispatch_extraction_bridge.py @@ -21,9 +21,16 @@ from pathlib import Path from typing import Any, Callable, Mapping SCRIPT_DIR = Path(__file__).resolve().parent -DISPATCH_SCRIPTS = SCRIPT_DIR.parents[1] / "dispatch-agent-task" / "scripts" -if str(DISPATCH_SCRIPTS) not in sys.path: - sys.path.insert(0, str(DISPATCH_SCRIPTS)) +PROJECT_ROOT = next( + parent + for parent in (SCRIPT_DIR, *SCRIPT_DIR.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +DISPATCH_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "dispatch" / "skills" / "dispatch-agent-task" / "scripts" +READ_TOOLS_DIR = PROJECT_ROOT / "muse" / "authority" / "tools" / "read" +for _path in (PROJECT_ROOT, DISPATCH_SCRIPTS, READ_TOOLS_DIR): + if str(_path) not in sys.path: + sys.path.insert(0, str(_path)) from extract_knowledge import ( # noqa: E402 ACTOR, @@ -38,7 +45,7 @@ from muse_llm import extract_json # noqa: E402 from record_failed_run import record_failure # noqa: E402 from run_registry import finish_run, new_run_id, start_run # noqa: E402 from dispatch_agent_task import run_dispatch # noqa: E402 -from pi_runner import ExecutionPolicy # noqa: E402 +from framework.adapters.pi.runner import ExecutionPolicy # noqa: E402 from read_tools import TOOL_REGISTRY # noqa: E402 # 抽取探索白名单:查重与回读核验;正文本体注入任务输入,不依赖工具读取。 diff --git a/.agent/skills/extract-chapter-knowledge/scripts/extract_knowledge.py b/muse/content/entity/skills/extract/extract-chapter-knowledge/scripts/extract_knowledge.py similarity index 98% rename from .agent/skills/extract-chapter-knowledge/scripts/extract_knowledge.py rename to muse/content/entity/skills/extract/extract-chapter-knowledge/scripts/extract_knowledge.py index 7886a53..9fbc7f7 100644 --- a/.agent/skills/extract-chapter-knowledge/scripts/extract_knowledge.py +++ b/muse/content/entity/skills/extract/extract-chapter-knowledge/scripts/extract_knowledge.py @@ -16,12 +16,14 @@ from psycopg.types.json import Jsonb HERE = pathlib.Path(__file__).resolve().parent -SKILLS = HERE.parents[1] -for import_path in ( - SKILLS / "record-run-evidence" / "scripts", -): - if str(import_path) not in sys.path: - sys.path.insert(0, str(import_path)) +PROJECT_ROOT = next( + parent + for parent in (HERE, *HERE.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +EVIDENCE_SCRIPTS = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" +if str(EVIDENCE_SCRIPTS) not in sys.path: + sys.path.insert(0, str(EVIDENCE_SCRIPTS)) from muse_llm import chat_governed, cost_usd, extract_json from muse_db import connect # noqa: E402 diff --git a/.agent/skills/extract-chapter-knowledge/scripts/extract_via_dispatch.py b/muse/content/entity/skills/extract/extract-chapter-knowledge/scripts/extract_via_dispatch.py similarity index 93% rename from .agent/skills/extract-chapter-knowledge/scripts/extract_via_dispatch.py rename to muse/content/entity/skills/extract/extract-chapter-knowledge/scripts/extract_via_dispatch.py index 1a06f3d..2cbea49 100644 --- a/.agent/skills/extract-chapter-knowledge/scripts/extract_via_dispatch.py +++ b/muse/content/entity/skills/extract/extract-chapter-knowledge/scripts/extract_via_dispatch.py @@ -2,7 +2,7 @@ """抽取智能体派发入口(阶段 F 第二部分)。 真实模型调用必须显式授权并显式给出 provider/model: -.venv/bin/python .agent/skills/extract-chapter-knowledge/scripts/extract_via_dispatch.py 12 3 \ +.venv/bin/python muse/content/entity/skills/extract/extract-chapter-knowledge/scripts/extract_via_dispatch.py 12 3 \ --provider catproxy-anthropic --model claude-opus-5 --thinking medium """ from __future__ import annotations diff --git a/.agent/skills/backup-work-extraction/SKILL.md b/muse/content/entity/skills/ingest/backup-work-extraction/SKILL.md similarity index 91% rename from .agent/skills/backup-work-extraction/SKILL.md rename to muse/content/entity/skills/ingest/backup-work-extraction/SKILL.md index 08109c6..54f65b5 100644 --- a/.agent/skills/backup-work-extraction/SKILL.md +++ b/muse/content/entity/skills/ingest/backup-work-extraction/SKILL.md @@ -22,11 +22,11 @@ disable-model-invocation: true | `restore` | `--backup-dir`、`--backup-id`、`--confirmation-sha`、`--execute` | 精确匹配后逐域读回再提交。 | ```bash -.venv/bin/python .agent/skills/backup-work-extraction/scripts/backup_upgrade_work.py backup \ +.venv/bin/python muse/content/entity/skills/ingest/backup-work-extraction/scripts/backup_upgrade_work.py backup \ --work-id 8 --expected-chapters 594 --expected-windows 116 -.venv/bin/python .agent/skills/backup-work-extraction/scripts/backup_upgrade_work.py verify \ +.venv/bin/python muse/content/entity/skills/ingest/backup-work-extraction/scripts/backup_upgrade_work.py verify \ --backup-dir /private/tmp/muse-upgrade-work8-before-reset -.venv/bin/python .agent/skills/backup-work-extraction/scripts/backup_upgrade_work.py rehearse \ +.venv/bin/python muse/content/entity/skills/ingest/backup-work-extraction/scripts/backup_upgrade_work.py rehearse \ --work-id 8 --backup-dir /private/tmp/muse-upgrade-work8-before-reset \ --confirmation-sha ``` diff --git a/.agent/skills/backup-work-extraction/scripts/backup_upgrade_work.py b/muse/content/entity/skills/ingest/backup-work-extraction/scripts/backup_upgrade_work.py similarity index 97% rename from .agent/skills/backup-work-extraction/scripts/backup_upgrade_work.py rename to muse/content/entity/skills/ingest/backup-work-extraction/scripts/backup_upgrade_work.py index d0d7551..2054967 100644 --- a/.agent/skills/backup-work-extraction/scripts/backup_upgrade_work.py +++ b/muse/content/entity/skills/ingest/backup-work-extraction/scripts/backup_upgrade_work.py @@ -29,10 +29,17 @@ import click # 维护命令复用作品抽取 Skill 的同书锁和执行身份,不复制第二套互斥规则。 _HERE = pathlib.Path(__file__).resolve().parent -_EXTRACTION_SCRIPTS = _HERE.parents[1] / "extract-work-knowledge" / "scripts" -sys.path.insert(0, str(_HERE)) -sys.path.insert(0, str(_EXTRACTION_SCRIPTS)) -sys.path.insert(0, str(_HERE.parents[1] / "deconstruct-book" / "scripts")) +PROJECT_ROOT = next( + parent + for parent in (_HERE, *_HERE.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +_EXTRACTION_SCRIPTS = PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "ingest" / "extract-work-knowledge" / "scripts" +_RESET_SCRIPTS = PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "ingest" / "reset-work-extraction" / "scripts" +_DECONSTRUCT_SCRIPTS = PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "ingest" / "deconstruct-book" / "scripts" +for _path in (_HERE, _EXTRACTION_SCRIPTS, _DECONSTRUCT_SCRIPTS): + if str(_path) not in sys.path: + sys.path.insert(0, str(_path)) from upgrade_work_lock import UpgradeWorkLockUnavailable, upgrade_work_lock @@ -332,7 +339,7 @@ def _atomic_write(path: pathlib.Path, data: bytes) -> None: def _git_commit() -> str: """读取脚本所在仓库当前提交;不把工作区 diff 或远端信息写入备份。""" - repository = pathlib.Path(__file__).resolve().parents[4] + repository = PROJECT_ROOT result = subprocess.run( ["git", "rev-parse", "HEAD"], cwd=repository, @@ -373,28 +380,28 @@ def _file_sha(path: pathlib.Path) -> str: def _repository_root() -> pathlib.Path: """返回 agent-example Git 根目录。""" - return pathlib.Path(__file__).resolve().parents[4] + return PROJECT_ROOT def capture_code_identity(git_commit: str | None = None) -> dict[str, Any]: """绑定本次实际执行文件;未提交代码用 fileSha 表达,不借 HEAD 冒充。""" here = pathlib.Path(__file__).resolve().parent - extraction_scripts = here.parents[1] / "extract-work-knowledge" / "scripts" + extraction_scripts = _EXTRACTION_SCRIPTS root = _repository_root() # 契约 key 是稳定逻辑名(拆分前后字节不变,存量备份永久可离线复验);value 只是拆分后的真实定位路径。 files = { "backup_upgrade_work.py": pathlib.Path(__file__).resolve(), # reset 拆到独立 Skill 后路径改变;逻辑名 "reset_upgrade_work.py" 保持稳定。 - "reset_upgrade_work.py": here.parents[1] / "reset-work-extraction" / "scripts" / "reset_upgrade_work.py", + "reset_upgrade_work.py": _RESET_SCRIPTS / "reset_upgrade_work.py", # 升格执行器拆分后改名 upgrade.py;逻辑名 "parse_upgrade.py" 保持稳定。 "parse_upgrade.py": extraction_scripts / "upgrade.py", # parse_llm 留 parse-book(字节不动);路径单向跨 skill 定位,逻辑名 "parse_llm.py" 不变。 - "parse_llm.py": here.parents[1] / "deconstruct-book" / "scripts" / "parse_llm.py", + "parse_llm.py": _DECONSTRUCT_SCRIPTS / "parse_llm.py", # 嵌入与模型调用的实现已装成共享运行时包;逻辑名不变,指向包内实现而非 Skill 的薄 CLI。 - "embed_drafts.py": here.parents[3] / "muse-embed" / "src" / "muse_embed.py", + "embed_drafts.py": PROJECT_ROOT / "muse" / "platform" / "embed" / "src" / "muse_embed.py", "upgrade_work_lock.py": extraction_scripts / "upgrade_work_lock.py", - "llm.py": here.parents[3] / "muse-llm" / "src" / "muse_llm.py", + "llm.py": PROJECT_ROOT / "muse" / "platform" / "llm" / "src" / "muse_llm.py", # 逻辑名保留 "parse-book/SKILL.md"(稳定契约键);随 __file__ 实际指向 upgrade/SKILL.md。 "parse-book/SKILL.md": extraction_scripts.parent / "SKILL.md", } @@ -1263,7 +1270,7 @@ def backup_command( def _propose_backup_lesson(*, work_id: int, manifest: Mapping[str, Any]) -> dict: """备份并离线复验通过后登记 lesson。""" - evidence = _HERE.parents[1] / "record-run-evidence" / "scripts" + evidence = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" if str(evidence) not in sys.path: sys.path.insert(0, str(evidence)) from lesson_registry import propose_lesson_dedup # noqa: WPS433 diff --git a/.agent/skills/clean-book-text/SKILL.md b/muse/content/entity/skills/ingest/clean-book-text/SKILL.md similarity index 81% rename from .agent/skills/clean-book-text/SKILL.md rename to muse/content/entity/skills/ingest/clean-book-text/SKILL.md index 0c8e403..c912e42 100644 --- a/.agent/skills/clean-book-text/SKILL.md +++ b/muse/content/entity/skills/ingest/clean-book-text/SKILL.md @@ -1,6 +1,7 @@ --- name: clean-book-text description: 识别并删除参考书或旧稿中的广告、水印、作者拉票和乱码噪声,同时保留逐段审计。静态导入后仍有语义垃圾时使用;模型只提候选,确定性守卫决定是否删除,绝不改写正文。首次 txt 分章落库归 import-book;本 Skill 只在已有 block 上做语义噪声清洗。 +disable-model-invocation: true --- # 清洗书稿正文 @@ -11,19 +12,19 @@ description: 识别并删除参考书或旧稿中的广告、水印、作者拉 ```bash # 放量驱动(每书 prep→detect→apply 全链;断点续跑/幂等防重删;可多进程分书并行) -.venv/bin/python .agent/skills/clean-book-text/scripts/clean_batch.py --work-id 7 --work-id 10 --batch <批次号> +.venv/bin/python muse/content/entity/skills/ingest/clean-book-text/scripts/clean_batch.py --work-id 7 --work-id 10 --batch <批次号> # 单步(调试/演示用) -.venv/bin/python .agent/skills/clean-book-text/scripts/clean_prep.py --work-id 7 [--from 1 --to 50] # 切窗 -.venv/bin/python .agent/skills/clean-book-text/scripts/clean_detect.py --work-id 7 [--win 1] # M3 探测 -.venv/bin/python .agent/skills/clean-book-text/scripts/clean_apply.py --work-id 7 --batch X --file … [--dry-run] [--report-md docs/清洗-N-书名.md] +.venv/bin/python muse/content/entity/skills/ingest/clean-book-text/scripts/clean_prep.py --work-id 7 [--from 1 --to 50] # 切窗 +.venv/bin/python muse/content/entity/skills/ingest/clean-book-text/scripts/clean_detect.py --work-id 7 [--win 1] # M3 探测 +.venv/bin/python muse/content/entity/skills/ingest/clean-book-text/scripts/clean_apply.py --work-id 7 --batch X --file … [--dry-run] [--report-md docs/清洗-N-书名.md] # 收尾收割:高频水印全书规则扫净(LLM 每窗只报样例,重复水印靠种子收割) -.venv/bin/python .agent/skills/clean-book-text/scripts/clean_sweep.py --work-id 7 --batch X # 审计自动种子(重复≥3次且≥20字) -.venv/bin/python .agent/skills/clean-book-text/scripts/clean_sweep.py --work-id 4 --batch X --seed "http://m." # 人工确认的碎水印 +.venv/bin/python muse/content/entity/skills/ingest/clean-book-text/scripts/clean_sweep.py --work-id 7 --batch X # 审计自动种子(重复≥3次且≥20字) +.venv/bin/python muse/content/entity/skills/ingest/clean-book-text/scripts/clean_sweep.py --work-id 4 --batch X --seed "http://m." # 人工确认的碎水印 # 审查:审计对账 -.venv/bin/python .agent/skills/access-database/scripts/db.py query "SELECT batch, count(*), sum(length(removed_text)) FROM example_clean_log WHERE work_id=7 GROUP BY batch" +.venv/bin/python muse/authority/evidence/skills/access-database/scripts/db.py query "SELECT batch, count(*), sum(length(removed_text)) FROM example_clean_log WHERE work_id=7 GROUP BY batch" ``` ⚠️ prep 会覆盖 /tmp/muse-clean// 的窗与 manifest——换范围重切前先归档旧产物目录。 diff --git a/.agent/skills/clean-book-text/scripts/clean_apply.py b/muse/content/entity/skills/ingest/clean-book-text/scripts/clean_apply.py similarity index 100% rename from .agent/skills/clean-book-text/scripts/clean_apply.py rename to muse/content/entity/skills/ingest/clean-book-text/scripts/clean_apply.py diff --git a/.agent/skills/clean-book-text/scripts/clean_batch.py b/muse/content/entity/skills/ingest/clean-book-text/scripts/clean_batch.py similarity index 100% rename from .agent/skills/clean-book-text/scripts/clean_batch.py rename to muse/content/entity/skills/ingest/clean-book-text/scripts/clean_batch.py diff --git a/.agent/skills/clean-book-text/scripts/clean_detect.py b/muse/content/entity/skills/ingest/clean-book-text/scripts/clean_detect.py similarity index 100% rename from .agent/skills/clean-book-text/scripts/clean_detect.py rename to muse/content/entity/skills/ingest/clean-book-text/scripts/clean_detect.py diff --git a/.agent/skills/clean-book-text/scripts/clean_prep.py b/muse/content/entity/skills/ingest/clean-book-text/scripts/clean_prep.py similarity index 100% rename from .agent/skills/clean-book-text/scripts/clean_prep.py rename to muse/content/entity/skills/ingest/clean-book-text/scripts/clean_prep.py diff --git a/.agent/skills/clean-book-text/scripts/clean_sweep.py b/muse/content/entity/skills/ingest/clean-book-text/scripts/clean_sweep.py similarity index 100% rename from .agent/skills/clean-book-text/scripts/clean_sweep.py rename to muse/content/entity/skills/ingest/clean-book-text/scripts/clean_sweep.py diff --git a/.agent/skills/deconstruct-book/SKILL.md b/muse/content/entity/skills/ingest/deconstruct-book/SKILL.md similarity index 91% rename from .agent/skills/deconstruct-book/SKILL.md rename to muse/content/entity/skills/ingest/deconstruct-book/SKILL.md index 9c16e63..1449602 100644 --- a/.agent/skills/deconstruct-book/SKILL.md +++ b/muse/content/entity/skills/ingest/deconstruct-book/SKILL.md @@ -37,17 +37,17 @@ disable-model-invocation: true ```bash # ① 章级 pass(细纲+实体+范式候选线索;断点续跑,重跑自动补失败章) -.venv/bin/python .agent/skills/deconstruct-book/scripts/parse_llm.py chapters --work-id 4 --from 1 --to 50 +.venv/bin/python muse/content/entity/skills/ingest/deconstruct-book/scripts/parse_llm.py chapters --work-id 4 --from 1 --to 50 # ② 窗级大纲聚合(每 5–10 万字:多章细纲+正文→阶段大纲;书末残窗无论大小必成窗) -.venv/bin/python .agent/skills/deconstruct-book/scripts/parse_outline.py window --work-id 4 +.venv/bin/python muse/content/entity/skills/ingest/deconstruct-book/scripts/parse_outline.py window --work-id 4 # ③ 窗级聚类出卡(窗=②的窗行;线索+细纲+阶段大纲→母卡;守卫+判重在 parse_ingest cards) -.venv/bin/python .agent/skills/deconstruct-book/scripts/parse_llm.py cards --work-id 4 +.venv/bin/python muse/content/entity/skills/ingest/deconstruct-book/scripts/parse_llm.py cards --work-id 4 # ④ 全书拆完:终检(逐窗细纲对账大纲 + 跨段连贯性纵览) -.venv/bin/python .agent/skills/deconstruct-book/scripts/parse_outline.py check --work-id 4 +.venv/bin/python muse/content/entity/skills/ingest/deconstruct-book/scripts/parse_outline.py check --work-id 4 # ⑤ 公共卡三角色审核(番茄作家/起点作家/主编,M3 常设步骤;见 review-knowledge-cards Skill) -.venv/bin/python .agent/skills/review-knowledge-cards/scripts/review_cards.py review --batch <批次> --work-id 4 +.venv/bin/python muse/content/entity/skills/review/review-knowledge-cards/scripts/review_cards.py review --batch <批次> --work-id 4 # 进度 -.venv/bin/python .agent/skills/deconstruct-book/scripts/parse_ingest.py progress +.venv/bin/python muse/content/entity/skills/ingest/deconstruct-book/scripts/parse_ingest.py progress ``` 审核纪律:常设审核=M3(已用 opus 金标准校准,偏差 0.45 达标);fable/opus 只做起量前校准与起量后一次总审核(门禁与优化,不进流程循环)。 @@ -57,7 +57,7 @@ disable-model-invocation: true **窗行冲突(放量首日实测,现行机械门)**:`--window` 变化后若计划窗与存量窗同 `from_order`、不同 `to_order`,`window` 命令以 `WINDOW_PLAN_CONFLICT` 失败关闭——禁止「已有大纲跳过」吞掉新大窗。换窗重切必须显式 `--replace-windows`(单事务软删该书全部活窗行后再切)。出卡仍挂「窗起」,须随后重跑 `cards`。 ```bash -.venv/bin/python .agent/skills/deconstruct-book/scripts/parse_outline.py window \ +.venv/bin/python muse/content/entity/skills/ingest/deconstruct-book/scripts/parse_outline.py window \ --work-id 4 --window 80000 --replace-windows ``` diff --git a/.agent/skills/deconstruct-book/scripts/parse_ingest.py b/muse/content/entity/skills/ingest/deconstruct-book/scripts/parse_ingest.py similarity index 100% rename from .agent/skills/deconstruct-book/scripts/parse_ingest.py rename to muse/content/entity/skills/ingest/deconstruct-book/scripts/parse_ingest.py diff --git a/.agent/skills/deconstruct-book/scripts/parse_llm.py b/muse/content/entity/skills/ingest/deconstruct-book/scripts/parse_llm.py similarity index 100% rename from .agent/skills/deconstruct-book/scripts/parse_llm.py rename to muse/content/entity/skills/ingest/deconstruct-book/scripts/parse_llm.py diff --git a/.agent/skills/deconstruct-book/scripts/parse_outline.py b/muse/content/entity/skills/ingest/deconstruct-book/scripts/parse_outline.py similarity index 100% rename from .agent/skills/deconstruct-book/scripts/parse_outline.py rename to muse/content/entity/skills/ingest/deconstruct-book/scripts/parse_outline.py diff --git a/.agent/skills/deconstruct-book/scripts/parse_salvage.py b/muse/content/entity/skills/ingest/deconstruct-book/scripts/parse_salvage.py similarity index 100% rename from .agent/skills/deconstruct-book/scripts/parse_salvage.py rename to muse/content/entity/skills/ingest/deconstruct-book/scripts/parse_salvage.py diff --git a/.agent/skills/extract-work-knowledge/SKILL.md b/muse/content/entity/skills/ingest/extract-work-knowledge/SKILL.md similarity index 90% rename from .agent/skills/extract-work-knowledge/SKILL.md rename to muse/content/entity/skills/ingest/extract-work-knowledge/SKILL.md index cfae3e1..99b4552 100644 --- a/.agent/skills/extract-work-knowledge/SKILL.md +++ b/muse/content/entity/skills/ingest/extract-work-knowledge/SKILL.md @@ -27,14 +27,14 @@ disable-model-invocation: true ```bash # 幂等切窗 -.venv/bin/python .agent/skills/extract-work-knowledge/scripts/upgrade.py windows --work-id 8 +.venv/bin/python muse/content/entity/skills/ingest/extract-work-knowledge/scripts/upgrade.py windows --work-id 8 # 顺序抽取并断点续跑 -.venv/bin/python .agent/skills/extract-work-knowledge/scripts/upgrade.py run --work-id 8 \ +.venv/bin/python muse/content/entity/skills/ingest/extract-work-knowledge/scripts/upgrade.py run --work-id 8 \ [--max-windows K] [--max-calls M] [--semantic-dedup] # 只读进度 -.venv/bin/python .agent/skills/extract-work-knowledge/scripts/upgrade.py status --work-id 8 +.venv/bin/python muse/content/entity/skills/ingest/extract-work-knowledge/scripts/upgrade.py status --work-id 8 ``` ## 数据与失败边界 diff --git a/.agent/skills/extract-work-knowledge/scripts/upgrade.py b/muse/content/entity/skills/ingest/extract-work-knowledge/scripts/upgrade.py similarity index 99% rename from .agent/skills/extract-work-knowledge/scripts/upgrade.py rename to muse/content/entity/skills/ingest/extract-work-knowledge/scripts/upgrade.py index 0bfeeb5..e44412a 100644 --- a/.agent/skills/extract-work-knowledge/scripts/upgrade.py +++ b/muse/content/entity/skills/ingest/extract-work-knowledge/scripts/upgrade.py @@ -38,8 +38,17 @@ import click # 复用章级管线的敏感降级链与 llm 入口(trust_env/重试/JSON 容错同源)。 # 拆分后 upgrade 与 parse-book 分属两个 skill:parse_llm(敏感降级链+llm 入口+DSN/TENANT)留 # parse-book 字节不动,本脚本单向跨 skill 引用(upgrade→parse-book,合法);upgrade_work_lock 与本脚本同目录。 -sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent)) -sys.path.insert(0, str(pathlib.Path(__file__).resolve().parents[2] / "deconstruct-book" / "scripts")) +_SCRIPT_DIR = pathlib.Path(__file__).resolve().parent +_PROJECT_ROOT = next( + parent + for parent in (_SCRIPT_DIR, *_SCRIPT_DIR.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +_DECONSTRUCT_SCRIPTS = _PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "ingest" / "deconstruct-book" / "scripts" +_EVIDENCE_SCRIPTS = _PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" +for _path in (_SCRIPT_DIR, _DECONSTRUCT_SCRIPTS, _EVIDENCE_SCRIPTS): + if str(_path) not in sys.path: + sys.path.insert(0, str(_path)) from muse_db import DSN, connect # noqa: E402 from parse_llm import m3_json, SensitiveHardStop, IDENTITY, TENANT # noqa: E402 from upgrade_work_lock import UpgradeWorkLockUnavailable, upgrade_work_lock # noqa: E402 @@ -5323,7 +5332,7 @@ def _run(work_id, max_windows, max_calls, model, redo_window, semantic_on, def _propose_upgrade_lesson(*, work_id: int, title: str, done_n: int, calls_n: int) -> dict: """窗批成功后登记 lesson;失败路径不调用,避免半跑污染。""" - evidence = pathlib.Path(__file__).resolve().parents[2] / "record-run-evidence" / "scripts" + evidence = _EVIDENCE_SCRIPTS if str(evidence) not in sys.path: sys.path.insert(0, str(evidence)) from lesson_registry import propose_lesson_dedup # noqa: WPS433 diff --git a/.agent/skills/extract-work-knowledge/scripts/upgrade_work_lock.py b/muse/content/entity/skills/ingest/extract-work-knowledge/scripts/upgrade_work_lock.py similarity index 100% rename from .agent/skills/extract-work-knowledge/scripts/upgrade_work_lock.py rename to muse/content/entity/skills/ingest/extract-work-knowledge/scripts/upgrade_work_lock.py diff --git a/.agent/skills/import-book/SKILL.md b/muse/content/entity/skills/ingest/import-book/SKILL.md similarity index 86% rename from .agent/skills/import-book/SKILL.md rename to muse/content/entity/skills/ingest/import-book/SKILL.md index 858d221..08308df 100644 --- a/.agent/skills/import-book/SKILL.md +++ b/muse/content/entity/skills/ingest/import-book/SKILL.md @@ -1,21 +1,22 @@ --- name: import-book description: 将参考书或用户旧稿 txt 确定性分章并写入作品、章节、正文 block 和来源档案。首次导入完整书稿或明确重导时使用;不调用模型、不改写正文。导入后散落广告/乱码/拉票等语义噪声归 clean-book-text,本 Skill 不做 M3 探测删除。 +disable-model-invocation: true --- # 导入完整书稿 -对应 muse API 面:导入解析旅程(产品-03 §3.7)。落库走 psycopg 直连(凭据同 `access-database`),写入约定见 [`db/表映射.md`](../../../db/表映射.md)。 +对应 muse API 面:导入解析旅程(产品-03 §3.7)。落库走 psycopg 直连(凭据同 `access-database`),写入约定见 [`表映射.md`](../../../../../authority/db/表映射.md)。 ## 用法 ```bash # 预演:只解析打印对账,不落库 -.venv/bin/python .agent/skills/import-book/scripts/import_novel.py --dry-run "../小说清单/机动风暴_骷髅精灵.txt" +.venv/bin/python muse/content/entity/skills/ingest/import-book/scripts/import_novel.py --dry-run "../小说清单/机动风暴_骷髅精灵.txt" # 正式导入(已存在同名作品则拒绝,--force 软删旧行重导) -.venv/bin/python .agent/skills/import-book/scripts/import_novel.py "../小说清单/超神机械师_齐佩甲.txt" -.venv/bin/python .agent/skills/import-book/scripts/import_novel.py --force "../小说清单/机动风暴_骷髅精灵.txt" +.venv/bin/python muse/content/entity/skills/ingest/import-book/scripts/import_novel.py "../小说清单/超神机械师_齐佩甲.txt" +.venv/bin/python muse/content/entity/skills/ingest/import-book/scripts/import_novel.py --force "../小说清单/机动风暴_骷髅精灵.txt" ``` ## 分章规则(按覆盖的真实格式) diff --git a/.agent/skills/import-book/scripts/import_novel.py b/muse/content/entity/skills/ingest/import-book/scripts/import_novel.py similarity index 100% rename from .agent/skills/import-book/scripts/import_novel.py rename to muse/content/entity/skills/ingest/import-book/scripts/import_novel.py diff --git a/.agent/skills/inspect-parse-health/SKILL.md b/muse/content/entity/skills/ingest/inspect-parse-health/SKILL.md similarity index 82% rename from .agent/skills/inspect-parse-health/SKILL.md rename to muse/content/entity/skills/ingest/inspect-parse-health/SKILL.md index a9b8fa2..36a2d8e 100644 --- a/.agent/skills/inspect-parse-health/SKILL.md +++ b/muse/content/entity/skills/ingest/inspect-parse-health/SKILL.md @@ -18,12 +18,12 @@ disable-model-invocation: true ```bash # 全链终态体检:单书或全部书 -.venv/bin/python .agent/skills/inspect-parse-health/scripts/parse_health.py health --work-id 4 -.venv/bin/python .agent/skills/inspect-parse-health/scripts/parse_health.py health +.venv/bin/python muse/content/entity/skills/ingest/inspect-parse-health/scripts/parse_health.py health --work-id 4 +.venv/bin/python muse/content/entity/skills/ingest/inspect-parse-health/scripts/parse_health.py health # 终态样张导出 -.venv/bin/python .agent/skills/inspect-parse-health/scripts/parse_export.py export-patterns --top 1 --combat-top 2 -.venv/bin/python .agent/skills/inspect-parse-health/scripts/parse_export.py export-upgrade --work-id 4 --top 8 +.venv/bin/python muse/content/entity/skills/ingest/inspect-parse-health/scripts/parse_export.py export-patterns --top 1 --combat-top 2 +.venv/bin/python muse/content/entity/skills/ingest/inspect-parse-health/scripts/parse_export.py export-upgrade --work-id 4 --top 8 ``` ## 输出 diff --git a/.agent/skills/inspect-parse-health/scripts/parse_export.py b/muse/content/entity/skills/ingest/inspect-parse-health/scripts/parse_export.py similarity index 100% rename from .agent/skills/inspect-parse-health/scripts/parse_export.py rename to muse/content/entity/skills/ingest/inspect-parse-health/scripts/parse_export.py diff --git a/.agent/skills/inspect-parse-health/scripts/parse_health.py b/muse/content/entity/skills/ingest/inspect-parse-health/scripts/parse_health.py similarity index 100% rename from .agent/skills/inspect-parse-health/scripts/parse_health.py rename to muse/content/entity/skills/ingest/inspect-parse-health/scripts/parse_health.py diff --git a/.agent/skills/repair-work-extraction/SKILL.md b/muse/content/entity/skills/ingest/repair-work-extraction/SKILL.md similarity index 96% rename from .agent/skills/repair-work-extraction/SKILL.md rename to muse/content/entity/skills/ingest/repair-work-extraction/SKILL.md index e706237..052f144 100644 --- a/.agent/skills/repair-work-extraction/SKILL.md +++ b/muse/content/entity/skills/ingest/repair-work-extraction/SKILL.md @@ -21,7 +21,7 @@ disable-model-invocation: true | `scripts/parse_rewash.py` | 存量回洗工具;是否退役由现有数据状态决定。 | ```bash -.venv/bin/python .agent/skills/repair-work-extraction/scripts/maintenance.py \ +.venv/bin/python muse/content/entity/skills/ingest/repair-work-extraction/scripts/maintenance.py \ recover-legacy-failed --work-id 8 --window-no 7 --preview ``` diff --git a/.agent/skills/repair-work-extraction/scripts/maintenance.py b/muse/content/entity/skills/ingest/repair-work-extraction/scripts/maintenance.py similarity index 100% rename from .agent/skills/repair-work-extraction/scripts/maintenance.py rename to muse/content/entity/skills/ingest/repair-work-extraction/scripts/maintenance.py diff --git a/.agent/skills/repair-work-extraction/scripts/migrate_upgrade_windows.py b/muse/content/entity/skills/ingest/repair-work-extraction/scripts/migrate_upgrade_windows.py similarity index 100% rename from .agent/skills/repair-work-extraction/scripts/migrate_upgrade_windows.py rename to muse/content/entity/skills/ingest/repair-work-extraction/scripts/migrate_upgrade_windows.py diff --git a/.agent/skills/repair-work-extraction/scripts/parse_rewash.py b/muse/content/entity/skills/ingest/repair-work-extraction/scripts/parse_rewash.py similarity index 100% rename from .agent/skills/repair-work-extraction/scripts/parse_rewash.py rename to muse/content/entity/skills/ingest/repair-work-extraction/scripts/parse_rewash.py diff --git a/.agent/skills/reset-work-extraction/SKILL.md b/muse/content/entity/skills/ingest/reset-work-extraction/SKILL.md similarity index 93% rename from .agent/skills/reset-work-extraction/SKILL.md rename to muse/content/entity/skills/ingest/reset-work-extraction/SKILL.md index 2592b13..ccb50f8 100644 --- a/.agent/skills/reset-work-extraction/SKILL.md +++ b/muse/content/entity/skills/ingest/reset-work-extraction/SKILL.md @@ -18,10 +18,10 @@ disable-model-invocation: true ```bash # 只读预览 -.venv/bin/python .agent/skills/reset-work-extraction/scripts/reset_upgrade_work.py --work-id 8 +.venv/bin/python muse/content/entity/skills/ingest/reset-work-extraction/scripts/reset_upgrade_work.py --work-id 8 # 真重置 -.venv/bin/python .agent/skills/reset-work-extraction/scripts/reset_upgrade_work.py \ +.venv/bin/python muse/content/entity/skills/ingest/reset-work-extraction/scripts/reset_upgrade_work.py \ --work-id 8 --execute --backup-dir /private/tmp/muse-upgrade-work8-before-reset \ --backup-id --confirmation-sha ``` diff --git a/.agent/skills/reset-work-extraction/scripts/reset_upgrade_work.py b/muse/content/entity/skills/ingest/reset-work-extraction/scripts/reset_upgrade_work.py similarity index 94% rename from .agent/skills/reset-work-extraction/scripts/reset_upgrade_work.py rename to muse/content/entity/skills/ingest/reset-work-extraction/scripts/reset_upgrade_work.py index 2e22aad..bb46edb 100644 --- a/.agent/skills/reset-work-extraction/scripts/reset_upgrade_work.py +++ b/muse/content/entity/skills/ingest/reset-work-extraction/scripts/reset_upgrade_work.py @@ -30,11 +30,18 @@ from psycopg.rows import dict_row # 复用作品抽取 Skill 的连接、租户与同书锁;维护侧不另造兼容实现。 # 备份合同由 backup-work-extraction 独占实现,reset 只做单向调用,不复制第二份验证逻辑。 -_SKILLS_DIR = pathlib.Path(__file__).resolve().parents[2] -sys.path.insert(0, str(pathlib.Path(__file__).resolve().parent)) -sys.path.insert(0, str(_SKILLS_DIR / "extract-work-knowledge" / "scripts")) -sys.path.insert(0, str(_SKILLS_DIR / "deconstruct-book" / "scripts")) -sys.path.insert(0, str(_SKILLS_DIR / "backup-work-extraction" / "scripts")) +_SCRIPT_DIR = pathlib.Path(__file__).resolve().parent +_PROJECT_ROOT = next( + parent + for parent in (_SCRIPT_DIR, *_SCRIPT_DIR.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +_EXTRACTION_SCRIPTS = _PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "ingest" / "extract-work-knowledge" / "scripts" +_DECONSTRUCT_SCRIPTS = _PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "ingest" / "deconstruct-book" / "scripts" +_BACKUP_SCRIPTS = _PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "ingest" / "backup-work-extraction" / "scripts" +for _path in (_SCRIPT_DIR, _EXTRACTION_SCRIPTS, _DECONSTRUCT_SCRIPTS, _BACKUP_SCRIPTS): + if str(_path) not in sys.path: + sys.path.insert(0, str(_path)) import backup_upgrade_work as backup # noqa: E402 from muse_db import DSN, connect # noqa: E402 from parse_llm import TENANT # noqa: E402 @@ -277,7 +284,9 @@ def _reset(work_id, execute, manifest=None, code_identity=None): def _propose_reset_lesson(*, work_id: int, backup_id: str | None) -> dict: """真清七域并断言通过后登记 lesson;预览路径不调用。""" - evidence = _SKILLS_DIR / "record-run-evidence" / "scripts" + evidence = _PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" + if str(evidence) not in sys.path: + sys.path.insert(0, str(evidence)) if str(evidence) not in sys.path: sys.path.insert(0, str(evidence)) from lesson_registry import propose_lesson_dedup # noqa: WPS433 diff --git a/.agent/skills/review-knowledge-cards/SKILL.md b/muse/content/entity/skills/review/review-knowledge-cards/SKILL.md similarity index 95% rename from .agent/skills/review-knowledge-cards/SKILL.md rename to muse/content/entity/skills/review/review-knowledge-cards/SKILL.md index a4e7b5e..a01a530 100644 --- a/.agent/skills/review-knowledge-cards/SKILL.md +++ b/muse/content/entity/skills/review/review-knowledge-cards/SKILL.md @@ -1,6 +1,7 @@ --- name: review-knowledge-cards description: 以三种编辑视角审核公共知识卡的成立性、创作可用性和跨书复用性,并写回 pass、revise 或 reject。拆书产出公共卡后使用;不负责生成卡或确认作品私有知识。 +disable-model-invocation: true --- # 审核公共知识卡 @@ -14,10 +15,10 @@ description: 以三种编辑视角审核公共知识卡的成立性、创作可 ```bash # 审核(全部或指定书的活卡;三角色各一次 M3 调用) -.venv/bin/python .agent/skills/review-knowledge-cards/scripts/review_cards.py review --batch <批次> [--work-id N] [--dry-run] +.venv/bin/python muse/content/entity/skills/review/review-knowledge-cards/scripts/review_cards.py review --batch <批次> [--work-id N] [--dry-run] # 校准:与 golden/scores.json(opus 金标准)对照(换模型/改 prompt 后必跑);过线则写 golden/calibrate-stamp.json -.venv/bin/python .agent/skills/review-knowledge-cards/scripts/review_cards.py calibrate --batch cal-002 +.venv/bin/python muse/content/entity/skills/review/review-knowledge-cards/scripts/review_cards.py calibrate --batch cal-002 ``` 判定阈值:三角色九维均分 ≥3.5 pass / ≥2.5 revise / 其余 reject。 diff --git a/.agent/skills/review-knowledge-cards/golden/scores-cal002-m3旧尺子对照.json b/muse/content/entity/skills/review/review-knowledge-cards/golden/scores-cal002-m3旧尺子对照.json similarity index 100% rename from .agent/skills/review-knowledge-cards/golden/scores-cal002-m3旧尺子对照.json rename to muse/content/entity/skills/review/review-knowledge-cards/golden/scores-cal002-m3旧尺子对照.json diff --git a/.agent/skills/review-knowledge-cards/golden/scores-cal002.json b/muse/content/entity/skills/review/review-knowledge-cards/golden/scores-cal002.json similarity index 100% rename from .agent/skills/review-knowledge-cards/golden/scores-cal002.json rename to muse/content/entity/skills/review/review-knowledge-cards/golden/scores-cal002.json diff --git a/.agent/skills/review-knowledge-cards/golden/scores.json b/muse/content/entity/skills/review/review-knowledge-cards/golden/scores.json similarity index 100% rename from .agent/skills/review-knowledge-cards/golden/scores.json rename to muse/content/entity/skills/review/review-knowledge-cards/golden/scores.json diff --git a/.agent/skills/review-knowledge-cards/golden/金标准-主编-2026-07-13.md b/muse/content/entity/skills/review/review-knowledge-cards/golden/金标准-主编-2026-07-13.md similarity index 100% rename from .agent/skills/review-knowledge-cards/golden/金标准-主编-2026-07-13.md rename to muse/content/entity/skills/review/review-knowledge-cards/golden/金标准-主编-2026-07-13.md diff --git a/.agent/skills/review-knowledge-cards/golden/金标准-番茄作家-2026-07-13.md b/muse/content/entity/skills/review/review-knowledge-cards/golden/金标准-番茄作家-2026-07-13.md similarity index 100% rename from .agent/skills/review-knowledge-cards/golden/金标准-番茄作家-2026-07-13.md rename to muse/content/entity/skills/review/review-knowledge-cards/golden/金标准-番茄作家-2026-07-13.md diff --git a/.agent/skills/review-knowledge-cards/golden/金标准-起点作家-2026-07-13.md b/muse/content/entity/skills/review/review-knowledge-cards/golden/金标准-起点作家-2026-07-13.md similarity index 100% rename from .agent/skills/review-knowledge-cards/golden/金标准-起点作家-2026-07-13.md rename to muse/content/entity/skills/review/review-knowledge-cards/golden/金标准-起点作家-2026-07-13.md diff --git a/.agent/skills/review-knowledge-cards/scripts/review_cards.py b/muse/content/entity/skills/review/review-knowledge-cards/scripts/review_cards.py similarity index 100% rename from .agent/skills/review-knowledge-cards/scripts/review_cards.py rename to muse/content/entity/skills/review/review-knowledge-cards/scripts/review_cards.py diff --git a/.agent/skills/confirm-knowledge-draft/SKILL.md b/muse/content/entity/skills/sovereignty/confirm-knowledge-draft/SKILL.md similarity index 85% rename from .agent/skills/confirm-knowledge-draft/SKILL.md rename to muse/content/entity/skills/sovereignty/confirm-knowledge-draft/SKILL.md index 121866a..8301caf 100644 --- a/.agent/skills/confirm-knowledge-draft/SKILL.md +++ b/muse/content/entity/skills/sovereignty/confirm-knowledge-draft/SKILL.md @@ -1,6 +1,7 @@ --- name: confirm-knowledge-draft description: 用户明确确认后把知识草稿翻成作品正式知识面,写入实体或关系、绑定知识库并迁移向量 owner。抽取或拆书产出的卡需要转正时使用;不处理正文候选、规划确认和冲突裁决。 +disable-model-invocation: true --- # 确认知识草稿(知识轨的 Shadow→Canonical) @@ -13,13 +14,13 @@ description: 用户明确确认后把知识草稿翻成作品正式知识面, ```bash # 试跑单张草稿 -.venv/bin/python .agent/skills/confirm-knowledge-draft/scripts/confirm_knowledge.py \ +.venv/bin/python muse/content/entity/skills/sovereignty/confirm-knowledge-draft/scripts/confirm_knowledge.py \ --draft-id --dry-run # 批量必须显式点名范围 -.venv/bin/python .agent/skills/confirm-knowledge-draft/scripts/confirm_knowledge.py \ +.venv/bin/python muse/content/entity/skills/sovereignty/confirm-knowledge-draft/scripts/confirm_knowledge.py \ --all-entities -.venv/bin/python .agent/skills/confirm-knowledge-draft/scripts/confirm_knowledge.py \ +.venv/bin/python muse/content/entity/skills/sovereignty/confirm-knowledge-draft/scripts/confirm_knowledge.py \ --all-relations ``` diff --git a/.agent/skills/confirm-knowledge-draft/scripts/confirm_knowledge.py b/muse/content/entity/skills/sovereignty/confirm-knowledge-draft/scripts/confirm_knowledge.py similarity index 100% rename from .agent/skills/confirm-knowledge-draft/scripts/confirm_knowledge.py rename to muse/content/entity/skills/sovereignty/confirm-knowledge-draft/scripts/confirm_knowledge.py diff --git a/knowledge/README.md b/muse/content/entity/sources/README.md similarity index 100% rename from knowledge/README.md rename to muse/content/entity/sources/README.md diff --git a/knowledge/参考书/封神演义/档案.md b/muse/content/entity/sources/参考书/封神演义/档案.md similarity index 100% rename from knowledge/参考书/封神演义/档案.md rename to muse/content/entity/sources/参考书/封神演义/档案.md diff --git a/knowledge/参考书/封神演义/第12回.txt b/muse/content/entity/sources/参考书/封神演义/第12回.txt similarity index 100% rename from knowledge/参考书/封神演义/第12回.txt rename to muse/content/entity/sources/参考书/封神演义/第12回.txt diff --git a/knowledge/参考书/封神演义/第13回.txt b/muse/content/entity/sources/参考书/封神演义/第13回.txt similarity index 100% rename from knowledge/参考书/封神演义/第13回.txt rename to muse/content/entity/sources/参考书/封神演义/第13回.txt diff --git a/knowledge/参考书/封神演义/第14回.txt b/muse/content/entity/sources/参考书/封神演义/第14回.txt similarity index 100% rename from knowledge/参考书/封神演义/第14回.txt rename to muse/content/entity/sources/参考书/封神演义/第14回.txt diff --git a/meta/schemas/README.md b/muse/content/meta/schemas/README.md similarity index 90% rename from meta/schemas/README.md rename to muse/content/meta/schemas/README.md index 96ee8d7..20eadab 100644 --- a/meta/schemas/README.md +++ b/muse/content/meta/schemas/README.md @@ -1,6 +1,6 @@ # meta/schemas —— 结构本体设计稿(23 型) -与 [专题-06 §4](../../../design-docs/专题-06-元数据驱动的智能体架构.md) 的 23 型一一对应:型名、domain×scope 两轴、本体分组、边界判据照抄 SoT;**字段部分是本仓的实战设计稿**——在真实创作中试出对错,修订后回填 design-docs 与 W1 种子(回填后在对应文件标「已回填@日期」)。 +与 [专题-06 §4](../../../../../design-docs/专题-06-元数据驱动的智能体架构.md) 的 23 型一一对应:型名、domain×scope 两轴、本体分组、边界判据照抄 SoT;**字段部分是本仓的实战设计稿**——在真实创作中试出对错,修订后回填 design-docs 与 W1 种子(回填后在对应文件标「已回填@日期」)。 ## 使用规则 diff --git a/meta/schemas/chapter.yaml b/muse/content/meta/schemas/chapter.yaml similarity index 100% rename from meta/schemas/chapter.yaml rename to muse/content/meta/schemas/chapter.yaml diff --git a/meta/schemas/character.yaml b/muse/content/meta/schemas/character.yaml similarity index 100% rename from meta/schemas/character.yaml rename to muse/content/meta/schemas/character.yaml diff --git a/meta/schemas/character_relation.yaml b/muse/content/meta/schemas/character_relation.yaml similarity index 100% rename from meta/schemas/character_relation.yaml rename to muse/content/meta/schemas/character_relation.yaml diff --git a/meta/schemas/combat.yaml b/muse/content/meta/schemas/combat.yaml similarity index 100% rename from meta/schemas/combat.yaml rename to muse/content/meta/schemas/combat.yaml diff --git a/meta/schemas/craft.yaml b/muse/content/meta/schemas/craft.yaml similarity index 100% rename from meta/schemas/craft.yaml rename to muse/content/meta/schemas/craft.yaml diff --git a/meta/schemas/emotion.yaml b/muse/content/meta/schemas/emotion.yaml similarity index 100% rename from meta/schemas/emotion.yaml rename to muse/content/meta/schemas/emotion.yaml diff --git a/meta/schemas/event.yaml b/muse/content/meta/schemas/event.yaml similarity index 100% rename from meta/schemas/event.yaml rename to muse/content/meta/schemas/event.yaml diff --git a/meta/schemas/faction.yaml b/muse/content/meta/schemas/faction.yaml similarity index 100% rename from meta/schemas/faction.yaml rename to muse/content/meta/schemas/faction.yaml diff --git a/meta/schemas/fine_outline.yaml b/muse/content/meta/schemas/fine_outline.yaml similarity index 100% rename from meta/schemas/fine_outline.yaml rename to muse/content/meta/schemas/fine_outline.yaml diff --git a/meta/schemas/generation_context.yaml b/muse/content/meta/schemas/generation_context.yaml similarity index 96% rename from meta/schemas/generation_context.yaml rename to muse/content/meta/schemas/generation_context.yaml index 59510b5..fa2ec96 100644 --- a/meta/schemas/generation_context.yaml +++ b/muse/content/meta/schemas/generation_context.yaml @@ -71,4 +71,4 @@ scope: agent indexHints用途: 只用于诊断卡索引替代效应,卡负责定位原文而不替代原文事实,不是事实证据,claimLedger不得引用 接受边界: evaluation、diagnostic、diagnostic_only 一律 acceptanceEligible=false 稳定排序: score DESC, sourceVersion ASC, sourceId ASC, sourceOffset ASC -实现校验器: .agent/skills/assemble-context/scripts/writer_contract.py +实现校验器: muse/lifecycle/context/skills/assemble-context/scripts/writer_contract.py diff --git a/meta/schemas/item.yaml b/muse/content/meta/schemas/item.yaml similarity index 100% rename from meta/schemas/item.yaml rename to muse/content/meta/schemas/item.yaml diff --git a/meta/schemas/location.yaml b/muse/content/meta/schemas/location.yaml similarity index 100% rename from meta/schemas/location.yaml rename to muse/content/meta/schemas/location.yaml diff --git a/meta/schemas/narrative_state.yaml b/muse/content/meta/schemas/narrative_state.yaml similarity index 100% rename from meta/schemas/narrative_state.yaml rename to muse/content/meta/schemas/narrative_state.yaml diff --git a/meta/schemas/novel_work.yaml b/muse/content/meta/schemas/novel_work.yaml similarity index 100% rename from meta/schemas/novel_work.yaml rename to muse/content/meta/schemas/novel_work.yaml diff --git a/meta/schemas/outline.yaml b/muse/content/meta/schemas/outline.yaml similarity index 100% rename from meta/schemas/outline.yaml rename to muse/content/meta/schemas/outline.yaml diff --git a/meta/schemas/pacing.yaml b/muse/content/meta/schemas/pacing.yaml similarity index 100% rename from meta/schemas/pacing.yaml rename to muse/content/meta/schemas/pacing.yaml diff --git a/meta/schemas/power_system.yaml b/muse/content/meta/schemas/power_system.yaml similarity index 100% rename from meta/schemas/power_system.yaml rename to muse/content/meta/schemas/power_system.yaml diff --git a/meta/schemas/reference_work.yaml b/muse/content/meta/schemas/reference_work.yaml similarity index 100% rename from meta/schemas/reference_work.yaml rename to muse/content/meta/schemas/reference_work.yaml diff --git a/meta/schemas/scene.yaml b/muse/content/meta/schemas/scene.yaml similarity index 100% rename from meta/schemas/scene.yaml rename to muse/content/meta/schemas/scene.yaml diff --git a/meta/schemas/scene_pattern.yaml b/muse/content/meta/schemas/scene_pattern.yaml similarity index 100% rename from meta/schemas/scene_pattern.yaml rename to muse/content/meta/schemas/scene_pattern.yaml diff --git a/meta/schemas/style.yaml b/muse/content/meta/schemas/style.yaml similarity index 100% rename from meta/schemas/style.yaml rename to muse/content/meta/schemas/style.yaml diff --git a/meta/schemas/trope.yaml b/muse/content/meta/schemas/trope.yaml similarity index 100% rename from meta/schemas/trope.yaml rename to muse/content/meta/schemas/trope.yaml diff --git a/meta/schemas/work_core.yaml b/muse/content/meta/schemas/work_core.yaml similarity index 100% rename from meta/schemas/work_core.yaml rename to muse/content/meta/schemas/work_core.yaml diff --git a/meta/schemas/world.yaml b/muse/content/meta/schemas/world.yaml similarity index 100% rename from meta/schemas/world.yaml rename to muse/content/meta/schemas/world.yaml diff --git a/.agent/skills/expand-scene/SKILL.md b/muse/content/work/skills/generate/expand-scene/SKILL.md similarity index 100% rename from .agent/skills/expand-scene/SKILL.md rename to muse/content/work/skills/generate/expand-scene/SKILL.md diff --git a/.agent/skills/polish-prose/SKILL.md b/muse/content/work/skills/generate/polish-prose/SKILL.md similarity index 100% rename from .agent/skills/polish-prose/SKILL.md rename to muse/content/work/skills/generate/polish-prose/SKILL.md diff --git a/.agent/skills/rewrite-selection/SKILL.md b/muse/content/work/skills/generate/rewrite-selection/SKILL.md similarity index 96% rename from .agent/skills/rewrite-selection/SKILL.md rename to muse/content/work/skills/generate/rewrite-selection/SKILL.md index 2003d44..3e26a0e 100644 --- a/.agent/skills/rewrite-selection/SKILL.md +++ b/muse/content/work/skills/generate/rewrite-selection/SKILL.md @@ -17,7 +17,7 @@ disable-model-invocation: true ```bash # 动笔前核对 Canonical 块 revision(只读;不一致非零退出) -.venv/bin/python .agent/skills/rewrite-selection/scripts/assert_expected_revision.py \ +.venv/bin/python muse/content/work/skills/generate/rewrite-selection/scripts/assert_expected_revision.py \ --work-id N --chapter-order M --expected-revision R ``` diff --git a/.agent/skills/rewrite-selection/scripts/assert_expected_revision.py b/muse/content/work/skills/generate/rewrite-selection/scripts/assert_expected_revision.py similarity index 100% rename from .agent/skills/rewrite-selection/scripts/assert_expected_revision.py rename to muse/content/work/skills/generate/rewrite-selection/scripts/assert_expected_revision.py diff --git a/.agent/skills/write-next-chapter/SKILL.md b/muse/content/work/skills/generate/write-next-chapter/SKILL.md similarity index 100% rename from .agent/skills/write-next-chapter/SKILL.md rename to muse/content/work/skills/generate/write-next-chapter/SKILL.md diff --git a/.agent/skills/write-next-chapter/scripts/candidate_cas.py b/muse/content/work/skills/generate/write-next-chapter/scripts/candidate_cas.py similarity index 98% rename from .agent/skills/write-next-chapter/scripts/candidate_cas.py rename to muse/content/work/skills/generate/write-next-chapter/scripts/candidate_cas.py index 116ad79..af25941 100644 --- a/.agent/skills/write-next-chapter/scripts/candidate_cas.py +++ b/muse/content/work/skills/generate/write-next-chapter/scripts/candidate_cas.py @@ -3,7 +3,7 @@ 实现 run_writer_pipeline 的 CasStateStore 协议,替换仅供实验的 InMemoryCasStateStore: create/transition/start_next/latest 全部走短事务条件 UPDATE,竞争时返回 None(由编排层 -收敛为 CAS_CONFLICT),不再因进程退出丢失状态。DB 触发器(db/ddl/109)另行锁死迁移 +收敛为 CAS_CONFLICT),不再因进程退出丢失状态。DB 触发器(muse/authority/db/ddl/109)另行锁死迁移 方向、revision 单调 +1 与身份不可变,调用方代码缺陷也无法把链改成非法形状。 """ diff --git a/.agent/skills/write-next-chapter/scripts/dispatch_writer_bridge.py b/muse/content/work/skills/generate/write-next-chapter/scripts/dispatch_writer_bridge.py similarity index 94% rename from .agent/skills/write-next-chapter/scripts/dispatch_writer_bridge.py rename to muse/content/work/skills/generate/write-next-chapter/scripts/dispatch_writer_bridge.py index d4c5c3e..a677404 100644 --- a/.agent/skills/write-next-chapter/scripts/dispatch_writer_bridge.py +++ b/muse/content/work/skills/generate/write-next-chapter/scripts/dispatch_writer_bridge.py @@ -19,15 +19,21 @@ from pathlib import Path from typing import Any, Callable, Mapping SCRIPT_DIR = Path(__file__).resolve().parent -DISPATCH_SCRIPTS = SCRIPT_DIR.parents[1] / "dispatch-agent-task" / "scripts" -ASSEMBLE_SCRIPTS = SCRIPT_DIR.parents[1] / "assemble-context" / "scripts" -for _path in (DISPATCH_SCRIPTS, ASSEMBLE_SCRIPTS): +PROJECT_ROOT = next( + parent + for parent in (SCRIPT_DIR, *SCRIPT_DIR.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +DISPATCH_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "dispatch" / "skills" / "dispatch-agent-task" / "scripts" +ASSEMBLE_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" +READ_TOOLS_DIR = PROJECT_ROOT / "muse" / "authority" / "tools" / "read" +for _path in (PROJECT_ROOT, DISPATCH_SCRIPTS, ASSEMBLE_SCRIPTS, READ_TOOLS_DIR): if str(_path) not in sys.path: sys.path.insert(0, str(_path)) from writer_contract import build_candidate_envelope, build_writer_creative_input # noqa: E402 from dispatch_agent_task import run_dispatch # noqa: E402 -from pi_runner import ExecutionPolicy # noqa: E402 +from framework.adapters.pi.runner import ExecutionPolicy # noqa: E402 from read_tools import TOOL_REGISTRY # noqa: E402 # writer 探索白名单:工具 server 登记表的全部只读工具(登记表是唯一事实源)。 diff --git a/.agent/skills/write-next-chapter/scripts/persist_writer_run.py b/muse/content/work/skills/generate/write-next-chapter/scripts/persist_writer_run.py similarity index 97% rename from .agent/skills/write-next-chapter/scripts/persist_writer_run.py rename to muse/content/work/skills/generate/write-next-chapter/scripts/persist_writer_run.py index d70e84b..d820136 100644 --- a/.agent/skills/write-next-chapter/scripts/persist_writer_run.py +++ b/muse/content/work/skills/generate/write-next-chapter/scripts/persist_writer_run.py @@ -13,8 +13,13 @@ from typing import Any, Mapping SCRIPT_DIR = pathlib.Path(__file__).resolve().parent -EVIDENCE_DIR = SCRIPT_DIR.parents[1] / "record-run-evidence" / "scripts" -READ_CONTEXT_DIR = SCRIPT_DIR.parents[1] / "assemble-context" / "scripts" +PROJECT_ROOT = next( + parent + for parent in (SCRIPT_DIR, *SCRIPT_DIR.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +EVIDENCE_DIR = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" +READ_CONTEXT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" for path in (EVIDENCE_DIR, READ_CONTEXT_DIR): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/.agent/skills/write-next-chapter/scripts/produce_next_chapter.py b/muse/content/work/skills/generate/write-next-chapter/scripts/produce_next_chapter.py similarity index 96% rename from .agent/skills/write-next-chapter/scripts/produce_next_chapter.py rename to muse/content/work/skills/generate/write-next-chapter/scripts/produce_next_chapter.py index f3f5906..a856173 100644 --- a/.agent/skills/write-next-chapter/scripts/produce_next_chapter.py +++ b/muse/content/work/skills/generate/write-next-chapter/scripts/produce_next_chapter.py @@ -13,7 +13,7 @@ → accept_preflight(check_writer_acceptance 纯函数 + acceptance_state 实时重读) → 停止并展示候选,等待用户明确选择改 / 丢弃 / 采纳 -用法:.venv/bin/python .agent/skills/write-next-chapter/scripts/produce_next_chapter.py [目标章号] +用法:.venv/bin/python muse/content/work/skills/generate/write-next-chapter/scripts/produce_next_chapter.py [目标章号] --provider

--model [--thinking T] [--instruction "本轮人指令原文"] 写手唯一执行形态是两阶段框架派发(2026-08-23 对照裁决:直调链退出创作生成); --provider/--model 必须显式给出,不从环境变量推断。 @@ -32,22 +32,24 @@ from pathlib import Path from typing import Any, Mapping SCRIPT_DIR = Path(__file__).resolve().parent -REPO_ROOT = SCRIPT_DIR.parents[3] -AGENT_ROOT = SCRIPT_DIR.parents[2] -SKILLS = AGENT_ROOT / "skills" -for sub in ( - "assemble-context/scripts", - "write-next-chapter/scripts", - "record-run-evidence/scripts", - "check-content-consistency/scripts", - "decide-candidate/scripts", - "prevent-ai-flavor/scripts", - "diagnose-ai-flavor/scripts", - "replay-writer-gate/scripts", -): - p = str(SKILLS / sub) - if p not in sys.path: - sys.path.insert(0, p) +REPO_ROOT = next( + parent + for parent in (SCRIPT_DIR, *SCRIPT_DIR.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +SKILL_SCRIPT_DIRS = ( + REPO_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts", + REPO_ROOT / "muse" / "content" / "work" / "skills" / "generate" / "write-next-chapter" / "scripts", + REPO_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts", + REPO_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "semantic" / "check-content-consistency" / "scripts", + REPO_ROOT / "muse" / "content" / "work" / "skills" / "sovereignty" / "decide-candidate" / "scripts", + REPO_ROOT / "muse" / "lifecycle" / "quality" / "humanization" / "skills" / "prevent-ai-flavor" / "scripts", + REPO_ROOT / "muse" / "lifecycle" / "quality" / "humanization" / "skills" / "diagnose-ai-flavor" / "scripts", + REPO_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "replay" / "replay-writer-gate" / "scripts", +) +for path in SKILL_SCRIPT_DIRS: + if str(path) not in sys.path: + sys.path.insert(0, str(path)) from muse_db import connect, DSN # noqa: E402 from assemble_writer_context import assemble_context # noqa: E402 @@ -90,7 +92,7 @@ from acceptance_state import LiveStateError, build_live_acceptance_state # noqa WORK_ID = 12 -GATE_A_CONFIG = json.loads((SKILLS / "replay-writer-gate" / "configs" / +GATE_A_CONFIG = json.loads((REPO_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "replay" / "replay-writer-gate" / "configs" / "writer-gate-a-deep-space-v1.json").read_text(encoding="utf-8")) GATE_A_WRITER = GATE_A_CONFIG["executionProfiles"]["writer"] GATE_A_DETECTOR = GATE_A_CONFIG["executionProfiles"]["semantic_detector"] diff --git a/.agent/skills/write-next-chapter/scripts/production_evidence_reassemble.py b/muse/content/work/skills/generate/write-next-chapter/scripts/production_evidence_reassemble.py similarity index 100% rename from .agent/skills/write-next-chapter/scripts/production_evidence_reassemble.py rename to muse/content/work/skills/generate/write-next-chapter/scripts/production_evidence_reassemble.py diff --git a/.agent/skills/write-next-chapter/scripts/run_contrast_writer.py b/muse/content/work/skills/generate/write-next-chapter/scripts/run_contrast_writer.py similarity index 98% rename from .agent/skills/write-next-chapter/scripts/run_contrast_writer.py rename to muse/content/work/skills/generate/write-next-chapter/scripts/run_contrast_writer.py index b0deae3..b0192e1 100644 --- a/.agent/skills/write-next-chapter/scripts/run_contrast_writer.py +++ b/muse/content/work/skills/generate/write-next-chapter/scripts/run_contrast_writer.py @@ -13,7 +13,7 @@ - 不跑语义检测与人闸:对照候选没有接受路径,只做机械门留证与盲评比较。 跑法(真实调用需人授权): -.venv/bin/python .agent/skills/write-next-chapter/scripts/run_contrast_writer.py \ +.venv/bin/python muse/content/work/skills/generate/write-next-chapter/scripts/run_contrast_writer.py \ --source-run run-prod-work12-ch3-42beb650 --source-version 9 """ from __future__ import annotations diff --git a/.agent/skills/write-next-chapter/scripts/run_writer.py b/muse/content/work/skills/generate/write-next-chapter/scripts/run_writer.py similarity index 96% rename from .agent/skills/write-next-chapter/scripts/run_writer.py rename to muse/content/work/skills/generate/write-next-chapter/scripts/run_writer.py index 7d156ce..7737761 100644 --- a/.agent/skills/write-next-chapter/scripts/run_writer.py +++ b/muse/content/work/skills/generate/write-next-chapter/scripts/run_writer.py @@ -14,9 +14,15 @@ from decimal import Decimal, ROUND_HALF_UP from typing import Any, Callable, Mapping, Sequence SCRIPT_DIR = pathlib.Path(__file__).resolve().parent -READ_CONTEXT_DIR = SCRIPT_DIR.parents[1] / "assemble-context" / "scripts" -if str(READ_CONTEXT_DIR) not in sys.path: - sys.path.insert(0, str(READ_CONTEXT_DIR)) +PROJECT_ROOT = next( + parent + for parent in (SCRIPT_DIR, *SCRIPT_DIR.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +READ_CONTEXT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" +for _path in (PROJECT_ROOT, READ_CONTEXT_DIR): + if str(_path) not in sys.path: + sys.path.insert(0, str(_path)) from muse_role_contract import load_role_contract_catalog # noqa: E402 from muse_role import ( # noqa: E402 @@ -33,9 +39,9 @@ from muse_role import ( # noqa: E402 verify_role_profile, ) -_ROLE_CATALOG = load_role_contract_catalog(SCRIPT_DIR.parents[3]) +_ROLE_CATALOG = load_role_contract_catalog(PROJECT_ROOT) WRITER_ROLE_PROMPT = ( - (SCRIPT_DIR.parents[2] / "agents" / "writer.md").read_text(encoding="utf-8").rstrip() + (PROJECT_ROOT / ".agent" / "agents" / "writer.md").read_text(encoding="utf-8").rstrip() + "\n\n--- 角色合同(唯一事实源) ---\n" + _ROLE_CATALOG.for_role("writer").contract_prompt ) diff --git a/.agent/skills/write-next-chapter/scripts/run_writer_pipeline.py b/muse/content/work/skills/generate/write-next-chapter/scripts/run_writer_pipeline.py similarity index 98% rename from .agent/skills/write-next-chapter/scripts/run_writer_pipeline.py rename to muse/content/work/skills/generate/write-next-chapter/scripts/run_writer_pipeline.py index 99a9593..b11ba4c 100644 --- a/.agent/skills/write-next-chapter/scripts/run_writer_pipeline.py +++ b/muse/content/work/skills/generate/write-next-chapter/scripts/run_writer_pipeline.py @@ -13,9 +13,13 @@ from dataclasses import dataclass from typing import Any, Callable, Mapping, Protocol, Sequence SCRIPT_DIR = pathlib.Path(__file__).resolve().parent -SKILLS_DIR = SCRIPT_DIR.parents[1] -DETECT_DIR = SKILLS_DIR / "check-content-consistency" / "scripts" -READ_CONTEXT_DIR = SKILLS_DIR / "assemble-context" / "scripts" +PROJECT_ROOT = next( + parent + for parent in (SCRIPT_DIR, *SCRIPT_DIR.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +DETECT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "semantic" / "check-content-consistency" / "scripts" +READ_CONTEXT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" for path in (DETECT_DIR, READ_CONTEXT_DIR): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/.agent/skills/write-next-chapter/scripts/two_phase_writer.py b/muse/content/work/skills/generate/write-next-chapter/scripts/two_phase_writer.py similarity index 96% rename from .agent/skills/write-next-chapter/scripts/two_phase_writer.py rename to muse/content/work/skills/generate/write-next-chapter/scripts/two_phase_writer.py index 599ee40..0d2f561 100644 --- a/.agent/skills/write-next-chapter/scripts/two_phase_writer.py +++ b/muse/content/work/skills/generate/write-next-chapter/scripts/two_phase_writer.py @@ -23,14 +23,20 @@ from pathlib import Path from typing import Any, Callable, Mapping SCRIPT_DIR = Path(__file__).resolve().parent -DISPATCH_SCRIPTS = SCRIPT_DIR.parents[1] / "dispatch-agent-task" / "scripts" -ASSEMBLE_SCRIPTS = SCRIPT_DIR.parents[1] / "assemble-context" / "scripts" -for _path in (DISPATCH_SCRIPTS, ASSEMBLE_SCRIPTS): +PROJECT_ROOT = next( + parent + for parent in (SCRIPT_DIR, *SCRIPT_DIR.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +DISPATCH_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "dispatch" / "skills" / "dispatch-agent-task" / "scripts" +ASSEMBLE_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" +READ_TOOLS_DIR = PROJECT_ROOT / "muse" / "authority" / "tools" / "read" +for _path in (PROJECT_ROOT, DISPATCH_SCRIPTS, ASSEMBLE_SCRIPTS, READ_TOOLS_DIR): if str(_path) not in sys.path: sys.path.insert(0, str(_path)) from dispatch_agent_task import run_dispatch # noqa: E402 -from pi_runner import ExecutionPolicy # noqa: E402 +from framework.adapters.pi.runner import ExecutionPolicy # noqa: E402 from read_tools import TOOL_REGISTRY, execute_tool # noqa: E402 from writer_contract import build_writer_creative_input # noqa: E402 from dispatch_writer_bridge import ( # noqa: E402 diff --git a/.agent/skills/decide-candidate/SKILL.md b/muse/content/work/skills/sovereignty/decide-candidate/SKILL.md similarity index 91% rename from .agent/skills/decide-candidate/SKILL.md rename to muse/content/work/skills/sovereignty/decide-candidate/SKILL.md index 5cd890f..9233a14 100644 --- a/.agent/skills/decide-candidate/SKILL.md +++ b/muse/content/work/skills/sovereignty/decide-candidate/SKILL.md @@ -26,14 +26,14 @@ disable-model-invocation: true 2. **前置通过后,经写入层落库(单事务)**:`scripts/write_canonical.py`(复用 `access-database` 的 DSN) - 接受: ```bash - .venv/bin/python .agent/skills/decide-candidate/scripts/write_canonical.py accept \ + .venv/bin/python muse/content/work/skills/sovereignty/decide-candidate/scripts/write_canonical.py accept \ --expected-revision --rationale "为什么接受" --basis-ref "大纲@日期" --command-id <幂等ID> \ [--approved-deltas <已批准增量JSON数组>] # 先试跑(完整走一遍事务再回滚,校验不落库):加 --dry-run ``` - 丢弃: ```bash - .venv/bin/python .agent/skills/decide-candidate/scripts/write_canonical.py discard --rationale "为什么丢弃" + .venv/bin/python muse/content/work/skills/sovereignty/decide-candidate/scripts/write_canonical.py discard --rationale "为什么丢弃" ``` - 写入层按落库设计 §2.9 单事务执行:写正文块(`content_text`,revision+1,CAS 乐观锁)→ 写来源归因(`muse_content_block_source_attribution`,来源权威落块,架构-02 §3)→ 合并已批准事实增量(`fact_delta.py`,进 `example_fact_ledger` 正典账本)→ 登记投影(`projection_registry.py`,旧 revision 投影翻 stale、新 revision 登记 pending)→ 写命令幂等审计 → 写决策归档(`example_user_decision`)→ 翻候选 `state='accepted'`。**任一失败整体回滚,绝不留无来源指针的正式正文,也绝不产生正文已提交而事实半合并。** - DB 级兜底硬校验(不靠调用方自觉):`run_type` 非 production 拒绝接受(05 §8.4)、`state` 非 passed 拒绝、`semantic_status` 非 passed 拒绝(先审后入)、revision 冲突拒绝。 @@ -48,7 +48,7 @@ disable-model-invocation: true 本 Skill 只管正文轨。另外两条轨各有 owner,表集互不相交: - **知识卡**:归 `confirm-knowledge-draft`。**采纳正文 ≠ 确认知识**,抽取产出的卡变更要单独确认。 -- **规划**(大纲/细纲/设定):归 `plan-story`,由 [`plan-story/scripts/persist_planning.py`](../plan-story/scripts/persist_planning.py) 的 `confirm_section` 在 `example_planning_section` 上做 shadow→confirmed。 +- **规划**(大纲/细纲/设定):归 `plan-story`,由 [`plan-story/scripts/persist_planning.py`](../../../../../lifecycle/flow/skills/book/plan-story/scripts/persist_planning.py) 的 `confirm_section` 在 `example_planning_section` 上做 shadow→confirmed。 ## 红线 diff --git a/.agent/skills/decide-candidate/scripts/acceptance_state.py b/muse/content/work/skills/sovereignty/decide-candidate/scripts/acceptance_state.py similarity index 100% rename from .agent/skills/decide-candidate/scripts/acceptance_state.py rename to muse/content/work/skills/sovereignty/decide-candidate/scripts/acceptance_state.py diff --git a/.agent/skills/decide-candidate/scripts/check_writer_acceptance.py b/muse/content/work/skills/sovereignty/decide-candidate/scripts/check_writer_acceptance.py similarity index 100% rename from .agent/skills/decide-candidate/scripts/check_writer_acceptance.py rename to muse/content/work/skills/sovereignty/decide-candidate/scripts/check_writer_acceptance.py diff --git a/.agent/skills/decide-candidate/scripts/fact_delta.py b/muse/content/work/skills/sovereignty/decide-candidate/scripts/fact_delta.py similarity index 98% rename from .agent/skills/decide-candidate/scripts/fact_delta.py rename to muse/content/work/skills/sovereignty/decide-candidate/scripts/fact_delta.py index a3ffad7..518e587 100644 --- a/.agent/skills/decide-candidate/scripts/fact_delta.py +++ b/muse/content/work/skills/sovereignty/decide-candidate/scripts/fact_delta.py @@ -20,8 +20,12 @@ import sys from typing import Any, Mapping, Sequence SCRIPT_DIR = pathlib.Path(__file__).resolve().parent -SKILLS_DIR = SCRIPT_DIR.parents[1] -READ_CONTEXT_DIR = SKILLS_DIR / "assemble-context" / "scripts" +PROJECT_ROOT = next( + parent + for parent in (SCRIPT_DIR, *SCRIPT_DIR.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +READ_CONTEXT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" if str(READ_CONTEXT_DIR) not in sys.path: sys.path.insert(0, str(READ_CONTEXT_DIR)) diff --git a/.agent/skills/decide-candidate/scripts/projection_registry.py b/muse/content/work/skills/sovereignty/decide-candidate/scripts/projection_registry.py similarity index 100% rename from .agent/skills/decide-candidate/scripts/projection_registry.py rename to muse/content/work/skills/sovereignty/decide-candidate/scripts/projection_registry.py diff --git a/.agent/skills/decide-candidate/scripts/write_canonical.py b/muse/content/work/skills/sovereignty/decide-candidate/scripts/write_canonical.py similarity index 98% rename from .agent/skills/decide-candidate/scripts/write_canonical.py rename to muse/content/work/skills/sovereignty/decide-candidate/scripts/write_canonical.py index 28c1946..c65b91e 100644 --- a/.agent/skills/decide-candidate/scripts/write_canonical.py +++ b/muse/content/work/skills/sovereignty/decide-candidate/scripts/write_canonical.py @@ -28,7 +28,12 @@ from projection_registry import ( ) CREATOR = "confirm" -EVIDENCE_SCRIPTS = Path(__file__).resolve().parents[2] / "record-run-evidence" / "scripts" +PROJECT_ROOT = next( + parent + for parent in (Path(__file__).resolve().parent, *Path(__file__).resolve().parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +EVIDENCE_SCRIPTS = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" if str(EVIDENCE_SCRIPTS) not in sys.path: sys.path.insert(0, str(EVIDENCE_SCRIPTS)) diff --git a/.agent/skills/assemble-context/SKILL.md b/muse/lifecycle/context/skills/assemble-context/SKILL.md similarity index 97% rename from .agent/skills/assemble-context/SKILL.md rename to muse/lifecycle/context/skills/assemble-context/SKILL.md index c31a589..1135713 100644 --- a/.agent/skills/assemble-context/SKILL.md +++ b/muse/lifecycle/context/skills/assemble-context/SKILL.md @@ -6,7 +6,7 @@ disable-model-invocation: true # 统一读取器 -本 skill 只落实读取与投影,不另行定义产品设计。四层语义、WriterContext 和评测边界以[专题-03](../../../../design-docs/专题-03-AI编排上下文与质量评测实现规范.md)为 SoT;字段授权与统一读取规则以[专题-06](../../../../design-docs/专题-06-元数据驱动的智能体架构.md)为 SoT。 +本 skill 只落实读取与投影,不另行定义产品设计。四层语义、WriterContext 和评测边界以[专题-03](../../../../../../design-docs/专题-03-AI编排上下文与质量评测实现规范.md)为 SoT;字段授权与统一读取规则以[专题-06](../../../../../../design-docs/专题-06-元数据驱动的智能体架构.md)为 SoT。 ## 输入 diff --git a/.agent/skills/assemble-context/scripts/assemble_writer_context.py b/muse/lifecycle/context/skills/assemble-context/scripts/assemble_writer_context.py similarity index 100% rename from .agent/skills/assemble-context/scripts/assemble_writer_context.py rename to muse/lifecycle/context/skills/assemble-context/scripts/assemble_writer_context.py diff --git a/.agent/skills/assemble-context/scripts/persist_context_freeze.py b/muse/lifecycle/context/skills/assemble-context/scripts/persist_context_freeze.py similarity index 100% rename from .agent/skills/assemble-context/scripts/persist_context_freeze.py rename to muse/lifecycle/context/skills/assemble-context/scripts/persist_context_freeze.py diff --git a/.agent/skills/assemble-context/scripts/retrieve_writer_sources.py b/muse/lifecycle/context/skills/assemble-context/scripts/retrieve_writer_sources.py similarity index 100% rename from .agent/skills/assemble-context/scripts/retrieve_writer_sources.py rename to muse/lifecycle/context/skills/assemble-context/scripts/retrieve_writer_sources.py diff --git a/.agent/skills/assemble-context/scripts/writer_contract.py b/muse/lifecycle/context/skills/assemble-context/scripts/writer_contract.py similarity index 100% rename from .agent/skills/assemble-context/scripts/writer_contract.py rename to muse/lifecycle/context/skills/assemble-context/scripts/writer_contract.py diff --git a/.agent/skills/embed-knowledge/SKILL.md b/muse/lifecycle/context/skills/embed-knowledge/SKILL.md similarity index 84% rename from .agent/skills/embed-knowledge/SKILL.md rename to muse/lifecycle/context/skills/embed-knowledge/SKILL.md index f528696..b409f94 100644 --- a/.agent/skills/embed-knowledge/SKILL.md +++ b/muse/lifecycle/context/skills/embed-knowledge/SKILL.md @@ -1,28 +1,29 @@ --- name: embed-knowledge description: 使用固定 Qwen3 嵌入模型将知识草稿或实体批量写入 pgvector,并按内容哈希幂等处理 owner 与版本。知识行需要建立或刷新检索向量时使用;不嵌入参考书全文。 +disable-model-invocation: true --- # 嵌入知识内容 -对应 muse API 面:AI 网关(嵌入)。通道事实见 [`db/连接信息.md`](../../../db/连接信息.md):BASE `http://100.64.0.8:3000`、模型 `Qwen/Qwen3-Embedding-8B`、请求体 `"dimensions":1024`(实测生效)、**禁系统代理**(`trust_env=False`)。 +对应 muse API 面:AI 网关(嵌入)。通道事实见 [`连接信息.md`](../../../../authority/db/连接信息.md):BASE `http://100.64.0.8:3000`、模型 `Qwen/Qwen3-Embedding-8B`、请求体 `"dimensions":1024`(实测生效)、**禁系统代理**(`trust_env=False`)。 -库实现装为共享包 `muse-embed`(`-e ./muse-embed`):拆书与检索侧 `from muse_embed import embed_texts, build_embed_text`,`scripts/embed_drafts.py` 只是本 Skill 的 CLI。 +库实现装为共享包 `muse-embed`(`-e ./muse/platform/embed`):拆书与检索侧 `from muse_embed import embed_texts, build_embed_text`,`scripts/embed_drafts.py` 只是本 Skill 的 CLI。 ## 用法 ```bash # 批量补嵌 pending 草稿(无活向量,或活向量的当前 payload+model hash 已过期) -.venv/bin/python .agent/skills/embed-knowledge/scripts/embed_drafts.py +.venv/bin/python muse/lifecycle/context/skills/embed-knowledge/scripts/embed_drafts.py # 指定 work(默认兼容参考书拆书批次,按 source_id)或限量 -.venv/bin/python .agent/skills/embed-knowledge/scripts/embed_drafts.py --work-id 3 --limit 100 +.venv/bin/python muse/lifecycle/context/skills/embed-knowledge/scripts/embed_drafts.py --work-id 3 --limit 100 # 章后抽卡按作品的 draft.work_id 筛选(source_id 是章节 id) -.venv/bin/python .agent/skills/embed-knowledge/scripts/embed_drafts.py --work-id 12 --source-type chapter_extract +.venv/bin/python muse/lifecycle/context/skills/embed-knowledge/scripts/embed_drafts.py --work-id 12 --source-type chapter_extract # 自由文本试嵌(调试/B3 查询端复用同实现) -.venv/bin/python .agent/skills/embed-knowledge/scripts/embed_drafts.py --probe "机甲近战的节奏控制" +.venv/bin/python muse/lifecycle/context/skills/embed-knowledge/scripts/embed_drafts.py --probe "机甲近战的节奏控制" ``` ## 合同 diff --git a/.agent/skills/embed-knowledge/scripts/embed_drafts.py b/muse/lifecycle/context/skills/embed-knowledge/scripts/embed_drafts.py similarity index 100% rename from .agent/skills/embed-knowledge/scripts/embed_drafts.py rename to muse/lifecycle/context/skills/embed-knowledge/scripts/embed_drafts.py diff --git a/.agent/skills/freeze-context/SKILL.md b/muse/lifecycle/context/skills/freeze-context/SKILL.md similarity index 100% rename from .agent/skills/freeze-context/SKILL.md rename to muse/lifecycle/context/skills/freeze-context/SKILL.md diff --git a/.agent/skills/freeze-context/scripts/audit_leakage.py b/muse/lifecycle/context/skills/freeze-context/scripts/audit_leakage.py similarity index 100% rename from .agent/skills/freeze-context/scripts/audit_leakage.py rename to muse/lifecycle/context/skills/freeze-context/scripts/audit_leakage.py diff --git a/.agent/skills/freeze-context/scripts/build_snapshot.py b/muse/lifecycle/context/skills/freeze-context/scripts/build_snapshot.py similarity index 100% rename from .agent/skills/freeze-context/scripts/build_snapshot.py rename to muse/lifecycle/context/skills/freeze-context/scripts/build_snapshot.py diff --git a/.agent/skills/freeze-context/scripts/check_snapshot.py b/muse/lifecycle/context/skills/freeze-context/scripts/check_snapshot.py similarity index 100% rename from .agent/skills/freeze-context/scripts/check_snapshot.py rename to muse/lifecycle/context/skills/freeze-context/scripts/check_snapshot.py diff --git a/.agent/skills/freeze-context/scripts/load_reference_work.py b/muse/lifecycle/context/skills/freeze-context/scripts/load_reference_work.py similarity index 100% rename from .agent/skills/freeze-context/scripts/load_reference_work.py rename to muse/lifecycle/context/skills/freeze-context/scripts/load_reference_work.py diff --git a/.agent/skills/search-knowledge/SKILL.md b/muse/lifecycle/context/skills/search-knowledge/SKILL.md similarity index 82% rename from .agent/skills/search-knowledge/SKILL.md rename to muse/lifecycle/context/skills/search-knowledge/SKILL.md index 2631fd1..44f03c8 100644 --- a/.agent/skills/search-knowledge/SKILL.md +++ b/muse/lifecycle/context/skills/search-knowledge/SKILL.md @@ -1,6 +1,7 @@ --- name: search-knowledge description: 将创作意图嵌入后从 pgvector 召回知识,并按绑定、状态和 aiContext 权限裁剪结果。管理审查或上下文组装需要知识候选时使用;不返回参考书全文,不绕过作品绑定。 +disable-model-invocation: true --- # 检索知识 @@ -11,13 +12,13 @@ description: 将创作意图嵌入后从 pgvector 召回知识,并按绑定、 ```bash # 管理面检索(B3 验证:对 draft 面召回,含草稿行) -.venv/bin/python .agent/skills/search-knowledge/scripts/search.py "主角被围攻时反杀的打斗写法" --scope admin --top 8 +.venv/bin/python muse/lifecycle/context/skills/search-knowledge/scripts/search.py "主角被围攻时反杀的打斗写法" --scope admin --top 8 # 作品面检索(C4:仅已确认 entity + 该作品已绑定的库;work-id 必填) -.venv/bin/python .agent/skills/search-knowledge/scripts/search.py "师徒决裂的情感铺垫" --scope work --work-id 8 --top 5 +.venv/bin/python muse/lifecycle/context/skills/search-knowledge/scripts/search.py "师徒决裂的情感铺垫" --scope work --work-id 8 --top 5 # 按型过滤 + 用途裁剪(按 aiContext 只回显该用途可见字段) -.venv/bin/python .agent/skills/search-knowledge/scripts/search.py "倒计时紧迫感" --type craft --purpose generation +.venv/bin/python muse/lifecycle/context/skills/search-knowledge/scripts/search.py "倒计时紧迫感" --type craft --purpose generation ``` ## 合同 diff --git a/.agent/skills/search-knowledge/scripts/search.py b/muse/lifecycle/context/skills/search-knowledge/scripts/search.py similarity index 100% rename from .agent/skills/search-knowledge/scripts/search.py rename to muse/lifecycle/context/skills/search-knowledge/scripts/search.py diff --git a/.agent/skills/dispatch-agent-task/SKILL.md b/muse/lifecycle/dispatch/skills/dispatch-agent-task/SKILL.md similarity index 65% rename from .agent/skills/dispatch-agent-task/SKILL.md rename to muse/lifecycle/dispatch/skills/dispatch-agent-task/SKILL.md index 45b202f..1ec7ecf 100644 --- a/.agent/skills/dispatch-agent-task/SKILL.md +++ b/muse/lifecycle/dispatch/skills/dispatch-agent-task/SKILL.md @@ -1,6 +1,6 @@ --- name: dispatch-agent-task -description: 把冻结角色任务包派发给 Agent 框架子代理执行并自动留痕:注入角色 prompt 与输出 Schema、按白名单开放工具、归一框架事件流写入代理事件账本,结构化输出经 Draft 2020-12 校验后返回回执。任何 Agent 框架(当前 pi)执行 writer/planner/detector/judge/extractor 角色任务时使用;不经框架的直接 HTTP 批处理走 execute-role-task;本 Skill 不做补证、重写等业务决策。 +description: 把冻结角色任务包派发给 Agent 框架子代理执行并自动留痕:注入角色 prompt 与输出 Schema、按白名单开放工具、归一框架事件流写入代理事件账本,结构化输出经 Draft 2020-12 校验后返回回执。当前生产入口使用 Pi;DSH headless 仅有独立的无工具 fresh 对照适配器,尚未接入本 Skill 的生产派发。执行 writer/planner/detector/judge/extractor 角色任务时使用;不经框架的直接 HTTP 批处理走 execute-role-task;本 Skill 不做补证、重写等业务决策。 disable-model-invocation: true --- @@ -11,7 +11,7 @@ disable-model-invocation: true ## 入口 ``` -.venv/bin/python .agent/skills/dispatch-agent-task/scripts/dispatch_agent_task.py \ +.venv/bin/python muse/lifecycle/dispatch/skills/dispatch-agent-task/scripts/dispatch_agent_task.py \ --spec task.json --provider P --model M [--thinking low] \ [--repo-root .] [--run-id ID] [--run-dir DIR] [--trigger-source user] \ [--session-id ID --session-dir DIR] [--enable-read-tools] @@ -19,15 +19,17 @@ disable-model-invocation: true | 模块 | 职责 | |---|---| -| `scripts/agent_task.py` | 可移植任务包合同:spec 加载校验、角色身份+中央角色合同+Schema 装配、结构化输出校验。 | -| `scripts/pi_runner.py` | pi 框架适配器:argv 构造(`--system-prompt` 注入、`--tools` 白名单、`--no-context-files/--no-skills/--no-extensions` 隔离、会话复用 `--session-id/--session-dir`)、JSON 事件流消费、看门狗超时。 | -| `scripts/read_tools.py` | 探索工具 server 只读实现:五个登记工具(细纲/文风/范式绑定/章节正文/实体检索),只读连接、未知工具拒绝、结果有界;`--list` 输出登记表。 | -| `scripts/muse_read_tools_extension.ts` | 工具 server 的框架扩展:装载时从 `read_tools.py --list` 动态注册工具,每次执行转给只读实现;不经派发器注入环境变量时不注册任何工具。 | -| `scripts/dispatch_agent_task.py` | CLI:运行登记 -> 事件入账 -> 框架执行 -> 校验 -> 证据落库 -> 依赖清单 -> 回执。 | +| `muse/lifecycle/dispatch/skills/dispatch-agent-task/scripts/role_task.py` | Muse 侧任务包装配:spec、角色合同、业务 Schema 和模型策略前置校验。 | +| `framework/primitives/execution.py` | 框架通用执行请求、事件和结果对象;不加载 Muse 合同。 | +| `framework/adapters/pi/runner.py` | Pi 框架适配器:只消费 `FrameworkExecutionRequest`,构造 argv、消费 JSON 事件流并执行超时保护;当前生产入口。 | +| `framework/adapters/dsh/` | DSH headless 对照适配器:只开放无工具 fresh 任务,读取 flush 后 session JSONL;未接入本 Skill 的生产派发。 | +| `muse/lifecycle/dispatch/skills/dispatch-agent-task/scripts/read_tools.py` | 探索工具 server 只读实现:五个登记工具(细纲/文风/范式绑定/章节正文/实体检索),只读连接、未知工具拒绝、结果有界;`--list` 输出登记表。 | +| `framework/adapters/pi/mcp_bridge.ts` | 工具 server 的框架扩展:装载时从 `read_tools.py --list` 动态注册工具,每次执行转给只读实现;不经派发器注入环境变量时不注册任何工具。 | +| `muse/lifecycle/dispatch/skills/dispatch-agent-task/scripts/dispatch_agent_task.py` | CLI:运行登记 -> 事件入账 -> 框架执行 -> 校验 -> 证据落库 -> 依赖清单 -> 回执。 | ## 输入与输出 -- 输入:`AgentTaskSpec` JSON(specVersion=agent-task-v1;role 限五个角色,角色合同来自 `.agent/docs/architecture/角色合同.md`;outputSchema 必须是合法 Draft 2020-12;inputSha256 可选校验)。`provider`、`model`、`thinking` 属于执行策略,其中 `provider` 和 `model` 必须由调用方显式传入并如实记账。 +- 输入:`AgentTaskSpec` JSON(specVersion=agent-task-v1;role 限五个角色,角色合同来自 `muse/sot/角色合同.md`;outputSchema 必须是合法 Draft 2020-12;inputSha256 可选校验)。`provider`、`model`、`thinking` 属于执行策略,其中 `provider` 和 `model` 必须由调用方显式传入并如实记账。 - 输出:回执 JSON(runId、框架、请求/实际模型、逐回合用量与成本、哈希链、证据 ID)与退出码;结构化输出经 `muse_llm.extract_json` + 完整 Draft 2020-12 校验,失败关闭(退出码 4)。 - 事件协议(九类闭集,逐条追加 `example_agent_event`):run.started / agent.started / model.completed / tool.started / tool.completed / agent.completed / agent.failed / run.completed / run.failed。 - 会话复用:`--session-id` + `--session-dir` 继续/创建指定框架会话(同一章补证/修改复用);缺省为一次性会话。会话文件由框架写入指定目录,随运行目录同权限保护。 @@ -37,7 +39,7 @@ disable-model-invocation: true ## 红线 - 适配器不含业务决策:补证、重写、下一步做什么属于框架里的模型与主代理,不属于本 Skill。 -- 只有 `pi_runner.py` 可以直接调用框架二进制;其余任何位置 shell 调模型 CLI 都被架构门禁阻断。 +- 框架二进制只能由 `framework/adapters/` 下的宿主适配器调用;当前 `dispatch-agent-task` 生产路径只调用 `framework/adapters/pi/runner.py`。角色合同、fixed-opus 和额度策略由 Muse 派发层解析,不进入框架。 - 不读取本机模型客户端配置文件;框架凭据走框架自身环境变量,本 Skill 不经手。 - 角色文件只提供身份提示;中央角色合同是稳定边界唯一事实源。系统提示词由适配器按固定顺序装配,不裁剪角色合同;工具白名单外的能力不开放(空名单 = `--no-tools`)。 - 工具 server 只提供登记过的只读工具:不提供裸查询、不写库;登记表(`read_tools.py` TOOL_REGISTRY)是唯一事实源,扩展不自带工具清单。 diff --git a/.agent/skills/dispatch-agent-task/scripts/dispatch_agent_task.py b/muse/lifecycle/dispatch/skills/dispatch-agent-task/scripts/dispatch_agent_task.py similarity index 93% rename from .agent/skills/dispatch-agent-task/scripts/dispatch_agent_task.py rename to muse/lifecycle/dispatch/skills/dispatch-agent-task/scripts/dispatch_agent_task.py index 605c4d1..4f846e7 100644 --- a/.agent/skills/dispatch-agent-task/scripts/dispatch_agent_task.py +++ b/muse/lifecycle/dispatch/skills/dispatch-agent-task/scripts/dispatch_agent_task.py @@ -23,13 +23,22 @@ from pathlib import Path from typing import Any, Callable, Iterable, Mapping SCRIPT_DIR = Path(__file__).resolve().parent +PROJECT_ROOT = next( + parent + for parent in (SCRIPT_DIR, *SCRIPT_DIR.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +if str(PROJECT_ROOT) not in sys.path: + sys.path.insert(0, str(PROJECT_ROOT)) if str(SCRIPT_DIR) not in sys.path: sys.path.insert(0, str(SCRIPT_DIR)) -EVIDENCE_DIR = (SCRIPT_DIR.parent.parent / "record-run-evidence" / "scripts").resolve() -if str(EVIDENCE_DIR) not in sys.path: - sys.path.insert(0, str(EVIDENCE_DIR)) +EVIDENCE_DIR = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" +READ_TOOLS_DIR = PROJECT_ROOT / "muse" / "authority" / "tools" / "read" +for _path in (EVIDENCE_DIR, READ_TOOLS_DIR): + if str(_path) not in sys.path: + sys.path.insert(0, str(_path)) -from agent_task import ( # noqa: E402 +from role_task import ( # noqa: E402 AgentTaskSpec, OutputInvalidError, TaskSpecError, @@ -40,13 +49,15 @@ from agent_task import ( # noqa: E402 from agent_trace import AgentTraceWriter, persist_agent_evidence # noqa: E402 from persist_raw import _check_no_secrets # noqa: E402 import read_tools -from pi_runner import ( # noqa: E402 +from framework.adapters.pi.normalization import normalize_pi_transcript # noqa: E402 +from framework.adapters.pi.runner import ( # noqa: E402 DEFAULT_PI_BIN, AgentStreamOutcome, ExecutionPolicy, FrameworkError, PiAgentRunner, ) +from role_policy import validate_role_execution_policy # noqa: E402 from run_registry import finish_run, new_run_id, start_run # noqa: E402 EXIT_OK = 0 @@ -131,7 +142,7 @@ def _write_private_json(path: Path, value: Mapping[str, Any]) -> None: # 工具 server 扩展路径与内建只读文件工具(探索白名单的两类合法成员)。 -READ_TOOL_EXTENSION = Path(__file__).resolve().parent / "muse_read_tools_extension.ts" +READ_TOOL_EXTENSION = PROJECT_ROOT / "framework" / "adapters" / "pi" / "mcp_bridge.ts" BUILTIN_TOOL_NAMES = frozenset({"read", "grep", "find", "ls"}) @@ -203,19 +214,18 @@ def run_dispatch( # 工具 server 扩展经环境变量定位只读实现;框架进程继承该环境。 os.environ["MUSE_READ_TOOLS_PYTHON"] = sys.executable os.environ["MUSE_READ_TOOLS_SCRIPT"] = str( - Path(__file__).resolve().parent / "read_tools.py" + READ_TOOLS_DIR / "read_tools.py" ) policy_kwargs["extension_path"] = str(READ_TOOL_EXTENSION) effective_policy = replace(policy, **policy_kwargs) - if ( - package.role_contract.model_policy == "fixed-opus" - and "opus" not in effective_policy.model.lower() - ): + try: + validate_role_execution_policy(package, effective_policy) + except ValueError as exc: return ( { "status": "failed", "errorCode": "ROLE_MODEL_POLICY_MISMATCH", - "error": f"角色 {spec.role} 要求 fixed-opus 模型策略", + "error": str(exc), "requestedModelId": effective_policy.requested_model_id, }, EXIT_SPEC_INVALID, @@ -476,7 +486,10 @@ def run_dispatch( ) with os.fdopen(transcript_fd, "wb") as transcript_file: outcome = runner.run( - package, + package.as_framework_request( + session_mode="continue" if session_id is not None else "fresh", + request_id=run_id, + ), effective_policy, writer, timeout_seconds=spec.max_duration_seconds, @@ -537,6 +550,21 @@ def run_dispatch( session_id=outcome.session_id, ) + try: + framework_artifact = normalize_pi_transcript( + transcript_path, + run_dir_path / "framework-events.jsonl", + run_id=run_id, + framework_version="pi-json-v1", + ) + except (OSError, UnicodeError, ValueError) as exc: + return _failed( + "FRAMEWORK_ARTIFACT_INVALID", + f"通用框架事件工件生成失败: {type(exc).__name__}", + EXIT_EVIDENCE_FAILED, + session_id=outcome.session_id, + ) + try: evidence = persist_agent_evidence( run_id=run_id, @@ -624,6 +652,7 @@ def run_dispatch( "sessionId": outcome.session_id, "turns": outcome.turns, "toolCalls": len(outcome.tool_calls), + "unknownFrameworkEvents": list(outcome.unknown_event_types), "costComplete": cost_complete, "leaseId": evidence.get("leaseId"), "llmCallIds": evidence.get("llmCallIds"), @@ -645,6 +674,7 @@ def run_dispatch( durationMs=outcome.duration_ms, turns=outcome.turns, toolCallCount=len(outcome.tool_calls), + unknownFrameworkEvents=list(outcome.unknown_event_types), dependencies=( {"count": dependency_count, "file": "dependencies.json"} if dependency_count @@ -660,6 +690,7 @@ def run_dispatch( json.dumps(structured, ensure_ascii=False, sort_keys=True) ), evidence=evidence, + frameworkArtifact=framework_artifact, ) try: _write_private_json(run_dir_path / "receipt.json", receipt) diff --git a/muse/lifecycle/dispatch/skills/dispatch-agent-task/scripts/role_policy.py b/muse/lifecycle/dispatch/skills/dispatch-agent-task/scripts/role_policy.py new file mode 100644 index 0000000..2af6572 --- /dev/null +++ b/muse/lifecycle/dispatch/skills/dispatch-agent-task/scripts/role_policy.py @@ -0,0 +1,23 @@ +"""Muse 角色模型策略解析与前置校验。""" + +from __future__ import annotations + +from typing import Any + +from framework.adapters.pi.runner import ExecutionPolicy +from role_task import RoleTaskPackage + + +def validate_role_execution_policy( + package: RoleTaskPackage, policy: ExecutionPolicy +) -> None: + """在进入框架适配器前校验 Muse 角色模型合同。""" + + if ( + package.role_contract.model_policy == "fixed-opus" + and "opus" not in policy.model.lower() + ): + raise ValueError(f"角色 {package.spec.role} 要求 fixed-opus 模型策略") + + +__all__ = ["validate_role_execution_policy"] diff --git a/.agent/skills/dispatch-agent-task/scripts/agent_task.py b/muse/lifecycle/dispatch/skills/dispatch-agent-task/scripts/role_task.py similarity index 88% rename from .agent/skills/dispatch-agent-task/scripts/agent_task.py rename to muse/lifecycle/dispatch/skills/dispatch-agent-task/scripts/role_task.py index 2362d3a..899b473 100644 --- a/.agent/skills/dispatch-agent-task/scripts/agent_task.py +++ b/muse/lifecycle/dispatch/skills/dispatch-agent-task/scripts/role_task.py @@ -27,6 +27,7 @@ from muse_role_contract import ( RoleContractError, load_role_contract_catalog, ) +from framework.primitives.execution import FrameworkExecutionRequest SPEC_VERSION = "agent-task-v1" SUPPORTED_AGENT_ROLES = ROLE_NAMES @@ -51,8 +52,8 @@ class TaskSpecError(ValueError): @dataclass(frozen=True) -class AgentTaskSpec: - """一次框架派发的可移植任务定义(无框架、无模型字段)。""" +class RoleTaskRequest: + """Muse 侧角色任务定义;框架字段不进入该对象。""" role: str task_prompt: str @@ -114,7 +115,7 @@ class AgentTaskSpec: return sha256_json(self.input) -def load_spec(path: str | Path) -> AgentTaskSpec: +def load_spec(path: str | Path) -> RoleTaskRequest: """从 JSON 文件加载并校验任务包;解析、字段或哈希异常统一失败关闭。""" try: @@ -138,7 +139,7 @@ def load_spec(path: str | Path) -> AgentTaskSpec: if not isinstance(tools, list): raise TaskSpecError("toolAllowlist 必须是字符串数组") duration = raw.get("maxDurationSeconds", DEFAULT_MAX_DURATION_SECONDS) - spec = AgentTaskSpec( + spec = RoleTaskRequest( role=raw["role"], task_prompt=raw["taskPrompt"], input=raw["input"], @@ -156,10 +157,10 @@ def load_spec(path: str | Path) -> AgentTaskSpec: @dataclass(frozen=True) -class TaskPackage: - """框架适配器实际消费的执行材料(与框架无关)。""" +class RoleTaskPackage: + """Muse 装配出的角色材料;通过显式端口转换给框架。""" - spec: AgentTaskSpec + spec: RoleTaskRequest role_prompt: str role_contract: RoleContract system_prompt: str @@ -169,6 +170,20 @@ class TaskPackage: input_sha256: str spec_sha256: str + def as_framework_request( + self, *, session_mode: str = "fresh", request_id: str | None = None + ) -> FrameworkExecutionRequest: + """把 Muse 材料转换为不含业务语义的框架端口对象。""" + + return FrameworkExecutionRequest( + system_prompt=self.system_prompt, + user_content=self.user_message, + tool_allowlist=self.spec.tool_allowlist, + timeout_seconds=float(self.spec.max_duration_seconds), + request_id=request_id, + session_mode=session_mode, + ) + def as_identity(self) -> dict[str, Any]: """给回执/事件用的身份摘要(不含正文)。""" @@ -193,7 +208,7 @@ def role_prompt_path(repo_root: str | Path, role: str) -> Path: return Path(repo_root) / ".agent" / "agents" / f"{role}.md" -def build_task_package(spec: AgentTaskSpec, repo_root: str | Path) -> TaskPackage: +def build_task_package(spec: RoleTaskRequest, repo_root: str | Path) -> RoleTaskPackage: """装配身份提示、中心角色合同、功能合同与冻结输入。""" root = Path(repo_root) @@ -215,7 +230,7 @@ def build_task_package(spec: AgentTaskSpec, repo_root: str | Path) -> TaskPackag + format_schema_contract(spec.output_schema) ) user_message = spec.task_prompt.strip() + AGENT_TASK_SEPARATOR + canonical_json(spec.input) - return TaskPackage( + return RoleTaskPackage( spec=spec, role_prompt=role_prompt, role_contract=role_contract, @@ -243,11 +258,16 @@ def build_task_package(spec: AgentTaskSpec, repo_root: str | Path) -> TaskPackag ) +# 旧调用方名称保留为 Muse 侧兼容别名;框架不依赖这些名称。 +AgentTaskSpec = RoleTaskRequest +TaskPackage = RoleTaskPackage + + class OutputInvalidError(ValueError): """框架最终输出未通过结构化合同。""" -def validate_structured_output(final_text: str, spec: AgentTaskSpec) -> dict[str, Any]: +def validate_structured_output(final_text: str, spec: RoleTaskRequest) -> dict[str, Any]: """抽取 JSON 并按冻结 schema 校验;失败抛 OutputInvalidError(失败关闭)。""" from muse_llm import extract_json @@ -265,11 +285,13 @@ def validate_structured_output(final_text: str, spec: AgentTaskSpec) -> dict[str __all__ = [ "AGENT_TASK_SEPARATOR", "AgentTaskSpec", + "RoleTaskRequest", "DEFAULT_MAX_DURATION_SECONDS", "OutputInvalidError", "SPEC_VERSION", "SUPPORTED_AGENT_ROLES", "TaskPackage", + "RoleTaskPackage", "TaskSpecError", "TOOL_NAME_PATTERN", "build_task_package", diff --git a/meta/chains/README.md b/muse/lifecycle/flow/chains/README.md similarity index 96% rename from meta/chains/README.md rename to muse/lifecycle/flow/chains/README.md index 7bcf803..bc36ee0 100644 --- a/meta/chains/README.md +++ b/muse/lifecycle/flow/chains/README.md @@ -44,8 +44,8 @@ agent 的提示词按**变化轴**拆三段,不做"一个 agent 一个大 prom - 定基线(voice_baseline)是垫底资产:作品建立/新角色登场时跑,平时不动;它是修订门禁与前置预防的对照物。 - 前置预防(deai_prevention)只降低命中率,不承诺零 AI 味;漏网命中由诊断兜底。 - 挖掘(ai_flavor_mining)不碰本次正文,只在背后进化规则库;升格入口是 `promote-ai-flavor-rule`,规则候选必须过双来源+正反证据+装载门+评测才可能 active。 -- **周期挂载**:以创作**正式权威**变没变为界——检查、报告、accept 授权后的下游 shadow 草稿可自动;草稿转正式与规则激活须人。见 [05 §2](../../.agent/docs/architecture/domains/05-创作流程领域.md)(含交互回合合同 §2.3 与节点 Skill 矩阵 §2.4)。 -- 五技能共享的资产层在 [`humanization/`](../../humanization/):初始拷贝自父仓 muse-deai,验证期由本仓自治演进,升华进 Muse 时才同步回父仓。 +- **周期挂载**:以创作**正式权威**变没变为界——检查、报告、accept 授权后的下游 shadow 草稿可自动;草稿转正式与规则激活须人。见 [05 §2](../../../sot/domains/05-创作流程领域.md)(含交互回合合同 §2.3 与节点 Skill 矩阵 §2.4)。 +- 五技能共享的资产层在 [`humanization/`](../../../lifecycle/quality/humanization):初始拷贝自父仓 muse-deai,验证期由本仓自治演进,升华进 Muse 时才同步回父仓。 ## 公约 diff --git a/.agent/skills/design-story-foundation/SKILL.md b/muse/lifecycle/flow/skills/book/design-story-foundation/SKILL.md similarity index 94% rename from .agent/skills/design-story-foundation/SKILL.md rename to muse/lifecycle/flow/skills/book/design-story-foundation/SKILL.md index 9920aa1..ac798b9 100644 --- a/.agent/skills/design-story-foundation/SKILL.md +++ b/muse/lifecycle/flow/skills/book/design-story-foundation/SKILL.md @@ -37,7 +37,7 @@ disable-model-invocation: true 表达层复核(可用 `humanizer-zh`)后重跑机械门与语义复核清单。 ```bash -.venv/bin/python .agent/skills/design-story-foundation/scripts/validate_candidates.py \ +.venv/bin/python muse/lifecycle/flow/skills/book/design-story-foundation/scripts/validate_candidates.py \ --root-doc docs/design/<作品>-前期设计.md --min-candidates 5 docs/design/candidates/*.md ``` @@ -50,7 +50,7 @@ disable-model-invocation: true 进入 `plan-story` 前必须有用户选定记录,并用机械门校验: ```bash -.venv/bin/python .agent/skills/design-story-foundation/scripts/assert_selection_handoff.py \ +.venv/bin/python muse/lifecycle/flow/skills/book/design-story-foundation/scripts/assert_selection_handoff.py \ docs/design/<作品>-selection.json ``` diff --git a/.agent/skills/design-story-foundation/references/candidate-contract.md b/muse/lifecycle/flow/skills/book/design-story-foundation/references/candidate-contract.md similarity index 100% rename from .agent/skills/design-story-foundation/references/candidate-contract.md rename to muse/lifecycle/flow/skills/book/design-story-foundation/references/candidate-contract.md diff --git a/.agent/skills/design-story-foundation/references/chapter-content-spec-chapters-1-5.md b/muse/lifecycle/flow/skills/book/design-story-foundation/references/chapter-content-spec-chapters-1-5.md similarity index 100% rename from .agent/skills/design-story-foundation/references/chapter-content-spec-chapters-1-5.md rename to muse/lifecycle/flow/skills/book/design-story-foundation/references/chapter-content-spec-chapters-1-5.md diff --git a/.agent/skills/design-story-foundation/references/chapter-content-spec-chapters-6-9.md b/muse/lifecycle/flow/skills/book/design-story-foundation/references/chapter-content-spec-chapters-6-9.md similarity index 100% rename from .agent/skills/design-story-foundation/references/chapter-content-spec-chapters-6-9.md rename to muse/lifecycle/flow/skills/book/design-story-foundation/references/chapter-content-spec-chapters-6-9.md diff --git a/.agent/skills/design-story-foundation/references/chapter-content-spec.md b/muse/lifecycle/flow/skills/book/design-story-foundation/references/chapter-content-spec.md similarity index 100% rename from .agent/skills/design-story-foundation/references/chapter-content-spec.md rename to muse/lifecycle/flow/skills/book/design-story-foundation/references/chapter-content-spec.md diff --git a/.agent/skills/design-story-foundation/scripts/assert_selection_handoff.py b/muse/lifecycle/flow/skills/book/design-story-foundation/scripts/assert_selection_handoff.py similarity index 100% rename from .agent/skills/design-story-foundation/scripts/assert_selection_handoff.py rename to muse/lifecycle/flow/skills/book/design-story-foundation/scripts/assert_selection_handoff.py diff --git a/.agent/skills/design-story-foundation/scripts/candidate_tree.json b/muse/lifecycle/flow/skills/book/design-story-foundation/scripts/candidate_tree.json similarity index 100% rename from .agent/skills/design-story-foundation/scripts/candidate_tree.json rename to muse/lifecycle/flow/skills/book/design-story-foundation/scripts/candidate_tree.json diff --git a/.agent/skills/design-story-foundation/scripts/validate_candidates.py b/muse/lifecycle/flow/skills/book/design-story-foundation/scripts/validate_candidates.py similarity index 100% rename from .agent/skills/design-story-foundation/scripts/validate_candidates.py rename to muse/lifecycle/flow/skills/book/design-story-foundation/scripts/validate_candidates.py diff --git a/.agent/skills/merge-story-candidates/SKILL.md b/muse/lifecycle/flow/skills/book/merge-story-candidates/SKILL.md similarity index 90% rename from .agent/skills/merge-story-candidates/SKILL.md rename to muse/lifecycle/flow/skills/book/merge-story-candidates/SKILL.md index 7d2cc24..f458f2b 100644 --- a/.agent/skills/merge-story-candidates/SKILL.md +++ b/muse/lifecycle/flow/skills/book/merge-story-candidates/SKILL.md @@ -20,16 +20,16 @@ disable-model-invocation: true ```bash # ① 为当前一级章节构建输入包(最新根设定 + 已统合前文 + 各来源候选的本章) -.venv/bin/python .agent/skills/merge-story-candidates/scripts/serial_merge.py packet \ +.venv/bin/python muse/lifecycle/flow/skills/book/merge-story-candidates/scripts/serial_merge.py packet \ --heading "<冻结的一级章标题>" --output /private/tmp/merge-packet-01.md <来源候选>... # ② 由主代理派发 planner 子代理 -# 主代理把 planner 身份提示与 .agent/docs/architecture/角色合同.md 对应章节作为角色 prompt,输入仅包含 +# 主代理把 planner 身份提示与 muse/sot/角色合同.md 对应章节作为角色 prompt,输入仅包含 # serial-merge-contract.md 与当前 merge-packet-01.md;子代理无工具、fresh 会话, # 输出写到 /private/tmp/merge-raw-01.md,并由 record-run-evidence 保存派发回执。 # ③ 校验并接纳本章草案 -.venv/bin/python .agent/skills/merge-story-candidates/scripts/serial_merge.py accept ... +.venv/bin/python muse/lifecycle/flow/skills/book/merge-story-candidates/scripts/serial_merge.py accept ... ``` 每章一个 fresh 高推理代理;不复用上一节点会话,不把来源候选的后续章节提前交给当前代理。 diff --git a/.agent/skills/merge-story-candidates/references/serial-merge-contract.md b/muse/lifecycle/flow/skills/book/merge-story-candidates/references/serial-merge-contract.md similarity index 100% rename from .agent/skills/merge-story-candidates/references/serial-merge-contract.md rename to muse/lifecycle/flow/skills/book/merge-story-candidates/references/serial-merge-contract.md diff --git a/.agent/skills/merge-story-candidates/scripts/serial_merge.py b/muse/lifecycle/flow/skills/book/merge-story-candidates/scripts/serial_merge.py similarity index 100% rename from .agent/skills/merge-story-candidates/scripts/serial_merge.py rename to muse/lifecycle/flow/skills/book/merge-story-candidates/scripts/serial_merge.py diff --git a/.agent/skills/plan-story/SKILL.md b/muse/lifecycle/flow/skills/book/plan-story/SKILL.md similarity index 95% rename from .agent/skills/plan-story/SKILL.md rename to muse/lifecycle/flow/skills/book/plan-story/SKILL.md index 5fb0c52..118cc5f 100644 --- a/.agent/skills/plan-story/SKILL.md +++ b/muse/lifecycle/flow/skills/book/plan-story/SKILL.md @@ -40,7 +40,7 @@ disable-model-invocation: true ## 规划落库(shadow→confirmed) -1. 落库:`.venv/bin/python .agent/skills/plan-story/scripts/persist_planning.py write --work-id N --section-type [--target-chapter N] [--schema-type X] [--version N]`(planner 不碰库/git,主会话落库;先 `--dry-run` 试跑)。 +1. 落库:`.venv/bin/python muse/lifecycle/flow/skills/book/plan-story/scripts/persist_planning.py write --work-id N --section-type [--target-chapter N] [--schema-type X] [--version N]`(planner 不碰库/git,主会话落库;先 `--dry-run` 试跑)。 2. 确认:`persist_planning.py confirm `(用户确认后 shadow→confirmed;**确认后的规划才进生成上下文**)。 3. 规划执行的输入/输出必须可追溯:`record_planning_execution.py --section-id ` 为已落库 section 登记 `example_run`、prompt/response raw 和 `example_run_receipt`;该记录标明 `executionKind=deterministic_persist`,不伪装成模型调用。 历史回执若误把确定性执行写成 `model_match=true`,使用 `repair_deterministic_receipt.py --run-id ` 追加修正 revision;旧回执保持不变。 diff --git a/.agent/skills/plan-story/scripts/persist_planning.py b/muse/lifecycle/flow/skills/book/plan-story/scripts/persist_planning.py similarity index 97% rename from .agent/skills/plan-story/scripts/persist_planning.py rename to muse/lifecycle/flow/skills/book/plan-story/scripts/persist_planning.py index 0f3e97f..9d8c6f6 100644 --- a/.agent/skills/plan-story/scripts/persist_planning.py +++ b/muse/lifecycle/flow/skills/book/plan-story/scripts/persist_planning.py @@ -23,8 +23,12 @@ BOOK_LEVEL_SECTION_TYPES = ("setting", "outline", "state", "assembly") FINE_OUTLINE_OWNER = "plan-chapter" DEFAULT_OWNER_SKILL = "plan-story" # 字段权威(git 侧设计稿):落库字段覆盖门禁按 schema_type 读这里的 <型>.yaml。 -# persist_planning.py 在 .agent/skills/plan-story/scripts/ 下,仓库根是 parents[4]。 -SCHEMAS_DIR = Path(__file__).resolve().parents[4] / "meta" / "schemas" +PROJECT_ROOT = next( + parent + for parent in (Path(__file__).resolve().parent, *Path(__file__).resolve().parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +SCHEMAS_DIR = PROJECT_ROOT / "muse" / "content" / "meta" / "schemas" def assert_section_owner(section_type: str, owner_skill: str) -> None: diff --git a/.agent/skills/plan-story/scripts/record_planning_execution.py b/muse/lifecycle/flow/skills/book/plan-story/scripts/record_planning_execution.py similarity index 96% rename from .agent/skills/plan-story/scripts/record_planning_execution.py rename to muse/lifecycle/flow/skills/book/plan-story/scripts/record_planning_execution.py index d75dc3d..25239df 100644 --- a/.agent/skills/plan-story/scripts/record_planning_execution.py +++ b/muse/lifecycle/flow/skills/book/plan-story/scripts/record_planning_execution.py @@ -12,8 +12,12 @@ import pathlib import sys -ROOT = pathlib.Path(__file__).resolve().parents[2] -_evidence_scripts = ROOT / "record-run-evidence" / "scripts" +ROOT = next( + parent + for parent in (pathlib.Path(__file__).resolve().parent, *pathlib.Path(__file__).resolve().parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +_evidence_scripts = ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" if str(_evidence_scripts) not in sys.path: sys.path.insert(0, str(_evidence_scripts)) from muse_db import connect # noqa: E402 diff --git a/.agent/skills/plan-story/scripts/repair_deterministic_receipt.py b/muse/lifecycle/flow/skills/book/plan-story/scripts/repair_deterministic_receipt.py similarity index 100% rename from .agent/skills/plan-story/scripts/repair_deterministic_receipt.py rename to muse/lifecycle/flow/skills/book/plan-story/scripts/repair_deterministic_receipt.py diff --git a/.agent/skills/plan-story/scripts/select_patterns.py b/muse/lifecycle/flow/skills/book/plan-story/scripts/select_patterns.py similarity index 91% rename from .agent/skills/plan-story/scripts/select_patterns.py rename to muse/lifecycle/flow/skills/book/plan-story/scripts/select_patterns.py index 51c5a0c..0ef21ef 100644 --- a/.agent/skills/plan-story/scripts/select_patterns.py +++ b/muse/lifecycle/flow/skills/book/plan-story/scripts/select_patterns.py @@ -13,8 +13,13 @@ import click HERE = pathlib.Path(__file__).resolve().parent -SKILLS = HERE.parents[1] -for path in (SKILLS / "plan-story" / "scripts", SKILLS / "search-knowledge" / "scripts"): +PROJECT_ROOT = next( + parent + for parent in (HERE, *HERE.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +SEARCH_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "search-knowledge" / "scripts" +for path in (PROJECT_ROOT, HERE, SEARCH_SCRIPTS): if str(path) not in sys.path: sys.path.insert(0, str(path)) from persist_planning import write_section # noqa: E402 diff --git a/.agent/skills/plan-chapter/SKILL.md b/muse/lifecycle/flow/skills/chapter/plan-chapter/SKILL.md similarity index 95% rename from .agent/skills/plan-chapter/SKILL.md rename to muse/lifecycle/flow/skills/chapter/plan-chapter/SKILL.md index e8d84dc..e29c9ae 100644 --- a/.agent/skills/plan-chapter/SKILL.md +++ b/muse/lifecycle/flow/skills/chapter/plan-chapter/SKILL.md @@ -11,7 +11,7 @@ disable-model-invocation: true **与 `plan-story` 的分工**:书级设定/大纲/状态/装配归 `plan-story`;**下一章可写细纲**(`fine_outline` schema)只由本 Skill 产出并落库。`plan-story` 不得写入 `section_type=fine_outline`。落库示例: ```bash -.venv/bin/python .agent/skills/plan-story/scripts/persist_planning.py write \ +.venv/bin/python muse/lifecycle/flow/skills/book/plan-story/scripts/persist_planning.py write \ --work-id N --section-type fine_outline --target-chapter M --schema-type fine_outline \ --owner-skill plan-chapter ``` @@ -38,7 +38,7 @@ disable-model-invocation: true ## 输出合同 -字段权威 = [`meta/schemas/fine_outline.yaml`](../../../meta/schemas/fine_outline.yaml);本节是该合同的产出侧说明,字段集以 yaml 为准。候选必须是一个结构化对象,字段完整且顺序稳定。 +字段权威 = [`fine_outline.yaml`](../../../../../content/meta/schemas/fine_outline.yaml);本节是该合同的产出侧说明,字段集以 yaml 为准。候选必须是一个结构化对象,字段完整且顺序稳定。 **必填**(writer 装配与机械门的硬依赖,缺一不得落库、不得装配): diff --git a/harness/README.md b/muse/lifecycle/quality/harness/README.md similarity index 90% rename from harness/README.md rename to muse/lifecycle/quality/harness/README.md index e0cdebd..40304a5 100644 --- a/harness/README.md +++ b/muse/lifecycle/quality/harness/README.md @@ -41,18 +41,18 @@ harness/ | 路径 | 责任 | 证据边界 | |---|---|---| | `humanization/eval/run_eval.py` | 去 AI 味规则合同和回归陷阱试跑 | 规则合同回放,不证明文学效果 | -| `.agent/skills/evaluate-frozen-replay/` | 正文/细纲冻结回放、盲评和质量门 | 评测编排与质量证据,不是通用 Skill 单测入口 | +| `muse/lifecycle/quality/skills/replay/evaluate-frozen-replay/` | 正文/细纲冻结回放、盲评和质量门 | 评测编排与质量证据,不是通用 Skill 单测入口 | | `harness/` | 跨 Skill 的开发验证与行为评测治理 | 只编排和裁决证据,不拥有业务合同 | ## 3. 权威关系 -- `.agent/skills/*/SKILL.md`:Skill 的运行时行为合同;不放开发测试说明。 -- `.agent/skills/*/scripts/`:Skill 使用的运行时确定性实现与机械门。 +- `skills.json` 的 `skill_path` 指向的 `SKILL.md`:Skill 的运行时行为合同;路径允许嵌套,不放开发测试说明。 +- `skill_path` 同目录的 `scripts/`:Skill 使用的运行时确定性实现与机械门。 - `tests/skills//`:对应 Skill 的实现测试、集成测试和 fake pipeline 测试;测试性质由 harness 清单标注。 - `harness/specs/`:测试、评测与质量评分规范;不被业务 Skill 当作运行时指令读取。 - `harness/manifests/`:测试/评测登记与执行配置;不复制业务字段合同。 - `harness/evals/`:外部行为评测案例、适配器和报告生成逻辑。 -- `.agent/docs/architecture/domains/`:领域与数据权威 SoT;harness 只引用,不复制领域定义。 +- `muse/sot/domains/`:领域与数据权威 SoT;harness 只引用,不复制领域定义。 - `docs/`:单次设计、运行证据和历史资料;不替代 harness 规范。 ## 4. 当前状态 diff --git a/harness/evals/skill_eval.py b/muse/lifecycle/quality/harness/evals/skill_eval.py similarity index 100% rename from harness/evals/skill_eval.py rename to muse/lifecycle/quality/harness/evals/skill_eval.py diff --git a/harness/evals/skills/diagnose-ai-flavor/run_eval.py b/muse/lifecycle/quality/harness/evals/skills/diagnose-ai-flavor/run_eval.py similarity index 82% rename from harness/evals/skills/diagnose-ai-flavor/run_eval.py rename to muse/lifecycle/quality/harness/evals/skills/diagnose-ai-flavor/run_eval.py index ef55a25..1a4f5bd 100644 --- a/harness/evals/skills/diagnose-ai-flavor/run_eval.py +++ b/muse/lifecycle/quality/harness/evals/skills/diagnose-ai-flavor/run_eval.py @@ -14,22 +14,26 @@ import sys from pathlib import Path EVAL_DIR = Path(__file__).resolve().parent -HARNESS_DIR = EVAL_DIR.parents[2] -AGENT_ROOT = HARNESS_DIR.parent +AGENT_ROOT = next( + parent + for parent in (EVAL_DIR, *EVAL_DIR.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +HARNESS_DIR = AGENT_ROOT / "muse" / "lifecycle" / "quality" / "harness" sys.path.insert(0, str(HARNESS_DIR / "evals")) from skill_eval import ( # noqa: E402 EvalAdapterUnavailable, EvalContractError, FakeAdapter, RoleAgentAdapter, run_eval, ) -SKILL_DIR = AGENT_ROOT / ".agent" / "skills" / "diagnose-ai-flavor" +SKILL_DIR = AGENT_ROOT / "muse" / "lifecycle" / "quality" / "humanization" / "skills" / "diagnose-ai-flavor" SCENARIO_FILE = EVAL_DIR / "scenarios.json" # 管道验证用脚本观察:与 scenarios.json 一一对应;只证明引擎裁决链路可用。 _FAKE_OBSERVATIONS = { "positive-basic-diagnosis": { "invoked_commands": [ - ".venv/bin/python .agent/skills/diagnose-ai-flavor/scripts/diagnose_ai_flavor.py run " + ".venv/bin/python muse/lifecycle/quality/humanization/skills/diagnose-ai-flavor/scripts/diagnose_ai_flavor.py run " "--text-file /tmp/text.txt --work-ref synthetic:demo --output /tmp/artifact.json" ], "exit_code": 0, @@ -44,7 +48,7 @@ _FAKE_OBSERVATIONS = { }, "missing-work-ref": { "invoked_commands": [ - ".venv/bin/python .agent/skills/diagnose-ai-flavor/scripts/diagnose_ai_flavor.py run " + ".venv/bin/python muse/lifecycle/quality/humanization/skills/diagnose-ai-flavor/scripts/diagnose_ai_flavor.py run " "--text-file /tmp/text.txt --output /tmp/artifact.json" ], "exit_code": 2, @@ -53,7 +57,7 @@ _FAKE_OBSERVATIONS = { }, "forbidden-modify-text": { "invoked_commands": [ - ".venv/bin/python .agent/skills/diagnose-ai-flavor/scripts/diagnose_ai_flavor.py run " + ".venv/bin/python muse/lifecycle/quality/humanization/skills/diagnose-ai-flavor/scripts/diagnose_ai_flavor.py run " "--text-file /tmp/text.txt --work-ref synthetic:demo --output /tmp/artifact.json" ], "exit_code": 0, diff --git a/harness/evals/skills/diagnose-ai-flavor/scenarios.json b/muse/lifecycle/quality/harness/evals/skills/diagnose-ai-flavor/scenarios.json similarity index 100% rename from harness/evals/skills/diagnose-ai-flavor/scenarios.json rename to muse/lifecycle/quality/harness/evals/skills/diagnose-ai-flavor/scenarios.json diff --git a/harness/evals/test_skill_eval.py b/muse/lifecycle/quality/harness/evals/test_skill_eval.py similarity index 88% rename from harness/evals/test_skill_eval.py rename to muse/lifecycle/quality/harness/evals/test_skill_eval.py index 0544826..9749360 100644 --- a/harness/evals/test_skill_eval.py +++ b/muse/lifecycle/quality/harness/evals/test_skill_eval.py @@ -11,14 +11,19 @@ import sys import tempfile import unittest -PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[2] -sys.path.insert(0, str(PROJECT_ROOT / "harness" / "evals")) -sys.path.insert(0, str(PROJECT_ROOT / "harness" / "evals" / "skills" / "diagnose-ai-flavor")) +PROJECT_ROOT = next( + parent + for parent in (pathlib.Path(__file__).resolve().parent, *pathlib.Path(__file__).resolve().parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +HARNESS_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "harness" +sys.path.insert(0, str(HARNESS_DIR / "evals")) +sys.path.insert(0, str(HARNESS_DIR / "evals" / "skills" / "diagnose-ai-flavor")) import skill_eval as se # noqa: E402 import run_eval as diagnose_eval # noqa: E402 -SKILL_DIR = PROJECT_ROOT / ".agent" / "skills" / "diagnose-ai-flavor" +SKILL_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "humanization" / "skills" / "diagnose-ai-flavor" SCENARIO_FILE = diagnose_eval.SCENARIO_FILE @@ -56,7 +61,7 @@ class EvalEngineTest(unittest.TestCase): def test_forbidden_invocation_is_detected(self): scripted = copy.deepcopy(diagnose_eval._FAKE_OBSERVATIONS) scripted["forbidden-modify-text"]["invoked_commands"].append( - ".venv/bin/python .agent/skills/revise-ai-flavor/scripts/revise_ai_flavor.py --x" + ".venv/bin/python muse/lifecycle/quality/humanization/skills/revise-ai-flavor/scripts/revise_ai_flavor.py --x" ) report = se.run_eval(SKILL_DIR, SCENARIO_FILE, se.FakeAdapter(scripted), adapter_name="fake") verdict = next(v for v in report["verdicts"] if v["scenario_id"] == "forbidden-modify-text") diff --git a/harness/manifests/skills.json b/muse/lifecycle/quality/harness/manifests/skills.json similarity index 80% rename from harness/manifests/skills.json rename to muse/lifecycle/quality/harness/manifests/skills.json index 0ba7707..c24aadf 100644 --- a/harness/manifests/skills.json +++ b/muse/lifecycle/quality/harness/manifests/skills.json @@ -4,7 +4,7 @@ { "name": "access-database", "lifecycle": "platform", - "invocation": "model_routed", + "invocation": "orchestrated", "side_effects": [ "db_write" ], @@ -18,7 +18,7 @@ "质量与回放评测", "去 AI 味与人感" ], - "skill_path": ".agent/skills/access-database/SKILL.md" + "skill_path": "muse/authority/evidence/skills/access-database/SKILL.md" }, { "name": "adjudicate-quality-gate", @@ -33,7 +33,7 @@ "平台运行与证据", "质量与回放评测" ], - "skill_path": ".agent/skills/adjudicate-quality-gate/SKILL.md" + "skill_path": "muse/lifecycle/quality/skills/mechanical/adjudicate-quality-gate/SKILL.md" }, { "name": "assemble-context", @@ -50,7 +50,7 @@ "质量与回放评测", "去 AI 味与人感" ], - "skill_path": ".agent/skills/assemble-context/SKILL.md" + "skill_path": "muse/lifecycle/context/skills/assemble-context/SKILL.md" }, { "name": "backup-work-extraction", @@ -64,12 +64,12 @@ "collaborates_with": [ "平台运行与证据" ], - "skill_path": ".agent/skills/backup-work-extraction/SKILL.md" + "skill_path": "muse/content/entity/skills/ingest/backup-work-extraction/SKILL.md" }, { "name": "call-content-model", "lifecycle": "platform", - "invocation": "model_routed", + "invocation": "orchestrated", "side_effects": [ "external_call" ], @@ -79,7 +79,7 @@ "导入、清洗与抽取", "质量与回放评测" ], - "skill_path": ".agent/skills/call-content-model/SKILL.md" + "skill_path": "muse/platform/llm/skills/call-content-model/SKILL.md" }, { "name": "capture-ai-flavor-cases", @@ -95,7 +95,7 @@ "写作与候选主权", "去 AI 味与人感" ], - "skill_path": ".agent/skills/capture-ai-flavor-cases/SKILL.md" + "skill_path": "muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/SKILL.md" }, { "name": "character-design", @@ -109,7 +109,7 @@ "collaborates_with": [ "质量与回放评测" ], - "skill_path": ".agent/skills/character-design/SKILL.md" + "skill_path": ".agent/skills/writing/character-design/SKILL.md" }, { "name": "character-presentation", @@ -123,7 +123,7 @@ "collaborates_with": [ "去 AI 味与人感" ], - "skill_path": ".agent/skills/character-presentation/SKILL.md" + "skill_path": ".agent/skills/writing/character-presentation/SKILL.md" }, { "name": "check-content-consistency", @@ -139,12 +139,12 @@ "规划与作品基础", "写作与候选主权" ], - "skill_path": ".agent/skills/check-content-consistency/SKILL.md" + "skill_path": "muse/lifecycle/quality/skills/semantic/check-content-consistency/SKILL.md" }, { "name": "clean-book-text", "lifecycle": "ingest", - "invocation": "model_routed", + "invocation": "orchestrated", "side_effects": [ "db_write", "external_call" @@ -154,7 +154,7 @@ "collaborates_with": [ "平台运行与证据" ], - "skill_path": ".agent/skills/clean-book-text/SKILL.md" + "skill_path": "muse/content/entity/skills/ingest/clean-book-text/SKILL.md" }, { "name": "concept-design", @@ -166,12 +166,12 @@ "compounding": "partial", "contract_owner": "规划与作品基础", "collaborates_with": [], - "skill_path": ".agent/skills/concept-design/SKILL.md" + "skill_path": ".agent/skills/planning/concept-design/SKILL.md" }, { "name": "confirm-knowledge-draft", "lifecycle": "sovereignty", - "invocation": "model_routed", + "invocation": "orchestrated", "side_effects": [ "db_write" ], @@ -181,7 +181,7 @@ "导入、清洗与抽取", "上下文与知识检索" ], - "skill_path": ".agent/skills/confirm-knowledge-draft/SKILL.md" + "skill_path": "muse/content/entity/skills/sovereignty/confirm-knowledge-draft/SKILL.md" }, { "name": "decide-candidate", @@ -199,7 +199,7 @@ "规划与作品基础", "写作与候选主权" ], - "skill_path": ".agent/skills/decide-candidate/SKILL.md" + "skill_path": "muse/content/work/skills/sovereignty/decide-candidate/SKILL.md" }, { "name": "deconstruct-book", @@ -216,7 +216,7 @@ "上下文与知识检索", "质量与回放评测" ], - "skill_path": ".agent/skills/deconstruct-book/SKILL.md" + "skill_path": "muse/content/entity/skills/ingest/deconstruct-book/SKILL.md" }, { "name": "design-story-foundation", @@ -231,7 +231,7 @@ "规划与作品基础", "写作与候选主权" ], - "skill_path": ".agent/skills/design-story-foundation/SKILL.md" + "skill_path": "muse/lifecycle/flow/skills/book/design-story-foundation/SKILL.md" }, { "name": "diagnose-ai-flavor", @@ -246,7 +246,7 @@ "质量与回放评测", "写作与候选主权" ], - "skill_path": ".agent/skills/diagnose-ai-flavor/SKILL.md" + "skill_path": "muse/lifecycle/quality/humanization/skills/diagnose-ai-flavor/SKILL.md" }, { "name": "dialogue-craft", @@ -258,12 +258,12 @@ "compounding": "partial", "contract_owner": "写作与候选主权", "collaborates_with": [], - "skill_path": ".agent/skills/dialogue-craft/SKILL.md" + "skill_path": ".agent/skills/writing/dialogue-craft/SKILL.md" }, { "name": "embed-knowledge", "lifecycle": "knowledge", - "invocation": "model_routed", + "invocation": "orchestrated", "side_effects": [ "db_write", "external_call" @@ -273,7 +273,7 @@ "collaborates_with": [ "导入、清洗与抽取" ], - "skill_path": ".agent/skills/embed-knowledge/SKILL.md" + "skill_path": "muse/lifecycle/context/skills/embed-knowledge/SKILL.md" }, { "name": "establish-voice-baseline", @@ -288,7 +288,7 @@ "上下文与知识检索", "写作与候选主权" ], - "skill_path": ".agent/skills/establish-voice-baseline/SKILL.md" + "skill_path": "muse/lifecycle/quality/humanization/skills/establish-voice-baseline/SKILL.md" }, { "name": "evaluate-frozen-replay", @@ -305,7 +305,7 @@ "上下文与知识检索", "写作与候选主权" ], - "skill_path": ".agent/skills/evaluate-frozen-replay/SKILL.md" + "skill_path": "muse/lifecycle/quality/skills/replay/evaluate-frozen-replay/SKILL.md" }, { "name": "execute-role-task", @@ -319,7 +319,7 @@ "collaborates_with": [ "质量与回放评测" ], - "skill_path": ".agent/skills/execute-role-task/SKILL.md" + "skill_path": "muse/platform/llm/skills/execute-role-task/SKILL.md" }, { "name": "dispatch-agent-task", @@ -336,7 +336,7 @@ "写作与候选主权", "质量与回放评测" ], - "skill_path": ".agent/skills/dispatch-agent-task/SKILL.md" + "skill_path": "muse/lifecycle/dispatch/skills/dispatch-agent-task/SKILL.md" }, { "name": "expand-scene", @@ -351,7 +351,7 @@ "上下文与知识检索", "质量与回放评测" ], - "skill_path": ".agent/skills/expand-scene/SKILL.md" + "skill_path": "muse/content/work/skills/generate/expand-scene/SKILL.md" }, { "name": "extract-chapter-knowledge", @@ -368,7 +368,7 @@ "上下文与知识检索", "写作与候选主权" ], - "skill_path": ".agent/skills/extract-chapter-knowledge/SKILL.md" + "skill_path": "muse/content/entity/skills/extract/extract-chapter-knowledge/SKILL.md" }, { "name": "extract-work-knowledge", @@ -384,7 +384,7 @@ "平台运行与证据", "上下文与知识检索" ], - "skill_path": ".agent/skills/extract-work-knowledge/SKILL.md" + "skill_path": "muse/content/entity/skills/ingest/extract-work-knowledge/SKILL.md" }, { "name": "foreshadow-payoff", @@ -398,7 +398,7 @@ "collaborates_with": [ "写作与候选主权" ], - "skill_path": ".agent/skills/foreshadow-payoff/SKILL.md" + "skill_path": ".agent/skills/planning/foreshadow-payoff/SKILL.md" }, { "name": "freeze-context", @@ -413,12 +413,12 @@ "平台运行与证据", "质量与回放评测" ], - "skill_path": ".agent/skills/freeze-context/SKILL.md" + "skill_path": "muse/lifecycle/context/skills/freeze-context/SKILL.md" }, { "name": "import-book", "lifecycle": "ingest", - "invocation": "model_routed", + "invocation": "orchestrated", "side_effects": [ "db_write" ], @@ -427,7 +427,7 @@ "collaborates_with": [ "平台运行与证据" ], - "skill_path": ".agent/skills/import-book/SKILL.md" + "skill_path": "muse/content/entity/skills/ingest/import-book/SKILL.md" }, { "name": "inspect-parse-health", @@ -441,7 +441,7 @@ "collaborates_with": [ "质量与回放评测" ], - "skill_path": ".agent/skills/inspect-parse-health/SKILL.md" + "skill_path": "muse/content/entity/skills/ingest/inspect-parse-health/SKILL.md" }, { "name": "load-replay-reference-work", @@ -456,7 +456,7 @@ "上下文与知识检索", "质量与回放评测" ], - "skill_path": ".agent/skills/load-replay-reference-work/SKILL.md" + "skill_path": "muse/lifecycle/quality/skills/replay/load-replay-reference-work/SKILL.md" }, { "name": "merge-story-candidates", @@ -470,7 +470,7 @@ "collaborates_with": [ "平台运行与证据" ], - "skill_path": ".agent/skills/merge-story-candidates/SKILL.md" + "skill_path": "muse/lifecycle/flow/skills/book/merge-story-candidates/SKILL.md" }, { "name": "narration-pov", @@ -482,7 +482,7 @@ "compounding": "partial", "contract_owner": "写作与候选主权", "collaborates_with": [], - "skill_path": ".agent/skills/narration-pov/SKILL.md" + "skill_path": ".agent/skills/writing/narration-pov/SKILL.md" }, { "name": "narrative-momentum", @@ -496,7 +496,7 @@ "collaborates_with": [ "写作与候选主权" ], - "skill_path": ".agent/skills/narrative-momentum/SKILL.md" + "skill_path": ".agent/skills/planning/narrative-momentum/SKILL.md" }, { "name": "novel-diagnosis", @@ -510,12 +510,12 @@ "collaborates_with": [ "写作与候选主权" ], - "skill_path": ".agent/skills/novel-diagnosis/SKILL.md" + "skill_path": ".agent/skills/diagnosis/novel-diagnosis/SKILL.md" }, { "name": "optimize-content-quality", "lifecycle": "review", - "invocation": "model_routed", + "invocation": "orchestrated", "side_effects": [ "none" ], @@ -525,7 +525,7 @@ "上下文与知识检索", "写作与候选主权" ], - "skill_path": ".agent/skills/optimize-content-quality/SKILL.md" + "skill_path": "muse/lifecycle/quality/skills/judge/optimize-content-quality/SKILL.md" }, { "name": "plan-chapter", @@ -540,7 +540,7 @@ "上下文与知识检索", "质量与回放评测" ], - "skill_path": ".agent/skills/plan-chapter/SKILL.md" + "skill_path": "muse/lifecycle/flow/skills/chapter/plan-chapter/SKILL.md" }, { "name": "plan-story", @@ -556,7 +556,7 @@ "上下文与知识检索", "写作与候选主权" ], - "skill_path": ".agent/skills/plan-story/SKILL.md" + "skill_path": "muse/lifecycle/flow/skills/book/plan-story/SKILL.md" }, { "name": "polish-prose", @@ -572,7 +572,7 @@ "质量与回放评测", "去 AI 味与人感" ], - "skill_path": ".agent/skills/polish-prose/SKILL.md" + "skill_path": "muse/content/work/skills/generate/polish-prose/SKILL.md" }, { "name": "prevent-ai-flavor", @@ -587,7 +587,7 @@ "上下文与知识检索", "写作与候选主权" ], - "skill_path": ".agent/skills/prevent-ai-flavor/SKILL.md" + "skill_path": "muse/lifecycle/quality/humanization/skills/prevent-ai-flavor/SKILL.md" }, { "name": "promote-ai-flavor-rule", @@ -601,7 +601,7 @@ "collaborates_with": [ "质量与回放评测" ], - "skill_path": ".agent/skills/promote-ai-flavor-rule/SKILL.md" + "skill_path": "muse/lifecycle/quality/humanization/skills/promote-ai-flavor-rule/SKILL.md" }, { "name": "prose-craft", @@ -615,7 +615,7 @@ "collaborates_with": [ "去 AI 味与人感" ], - "skill_path": ".agent/skills/prose-craft/SKILL.md" + "skill_path": ".agent/skills/writing/prose-craft/SKILL.md" }, { "name": "record-run-evidence", @@ -634,7 +634,7 @@ "质量与回放评测", "去 AI 味与人感" ], - "skill_path": ".agent/skills/record-run-evidence/SKILL.md" + "skill_path": "muse/authority/evidence/skills/record-run-evidence/SKILL.md" }, { "name": "refresh-runtime-probe", @@ -648,7 +648,7 @@ "collaborates_with": [ "质量与回放评测" ], - "skill_path": ".agent/skills/refresh-runtime-probe/SKILL.md" + "skill_path": "muse/platform/llm/skills/refresh-runtime-probe/SKILL.md" }, { "name": "repair-work-extraction", @@ -663,7 +663,7 @@ "collaborates_with": [ "平台运行与证据" ], - "skill_path": ".agent/skills/repair-work-extraction/SKILL.md" + "skill_path": "muse/content/entity/skills/ingest/repair-work-extraction/SKILL.md" }, { "name": "replay-writer-gate", @@ -680,7 +680,7 @@ "写作与候选主权", "质量与回放评测" ], - "skill_path": ".agent/skills/replay-writer-gate/SKILL.md" + "skill_path": "muse/lifecycle/quality/skills/replay/replay-writer-gate/SKILL.md" }, { "name": "reset-work-extraction", @@ -694,12 +694,12 @@ "collaborates_with": [ "平台运行与证据" ], - "skill_path": ".agent/skills/reset-work-extraction/SKILL.md" + "skill_path": "muse/content/entity/skills/ingest/reset-work-extraction/SKILL.md" }, { "name": "review-knowledge-cards", "lifecycle": "knowledge", - "invocation": "model_routed", + "invocation": "orchestrated", "side_effects": [ "db_write", "external_call" @@ -710,7 +710,7 @@ "平台运行与证据", "质量与回放评测" ], - "skill_path": ".agent/skills/review-knowledge-cards/SKILL.md" + "skill_path": "muse/content/entity/skills/review/review-knowledge-cards/SKILL.md" }, { "name": "revise-ai-flavor", @@ -725,7 +725,7 @@ "质量与回放评测", "写作与候选主权" ], - "skill_path": ".agent/skills/revise-ai-flavor/SKILL.md" + "skill_path": "muse/lifecycle/quality/humanization/skills/revise-ai-flavor/SKILL.md" }, { "name": "rewrite-selection", @@ -741,7 +741,7 @@ "质量与回放评测", "去 AI 味与人感" ], - "skill_path": ".agent/skills/rewrite-selection/SKILL.md" + "skill_path": "muse/content/work/skills/generate/rewrite-selection/SKILL.md" }, { "name": "scene-craft", @@ -755,7 +755,7 @@ "collaborates_with": [ "规划与作品基础" ], - "skill_path": ".agent/skills/scene-craft/SKILL.md" + "skill_path": ".agent/skills/writing/scene-craft/SKILL.md" }, { "name": "score-content-quality", @@ -773,12 +773,12 @@ "写作与候选主权", "质量与回放评测" ], - "skill_path": ".agent/skills/score-content-quality/SKILL.md" + "skill_path": "muse/lifecycle/quality/skills/judge/score-content-quality/SKILL.md" }, { "name": "search-knowledge", "lifecycle": "knowledge", - "invocation": "model_routed", + "invocation": "orchestrated", "side_effects": [ "external_call" ], @@ -789,7 +789,7 @@ "写作与候选主权", "质量与回放评测" ], - "skill_path": ".agent/skills/search-knowledge/SKILL.md" + "skill_path": "muse/lifecycle/context/skills/search-knowledge/SKILL.md" }, { "name": "show-and-omission", @@ -803,7 +803,7 @@ "collaborates_with": [ "去 AI 味与人感" ], - "skill_path": ".agent/skills/show-and-omission/SKILL.md" + "skill_path": ".agent/skills/writing/show-and-omission/SKILL.md" }, { "name": "story-ending", @@ -815,7 +815,7 @@ "compounding": "partial", "contract_owner": "规划与作品基础", "collaborates_with": [], - "skill_path": ".agent/skills/story-ending/SKILL.md" + "skill_path": ".agent/skills/planning/story-ending/SKILL.md" }, { "name": "story-planning", @@ -827,7 +827,7 @@ "compounding": "partial", "contract_owner": "规划与作品基础", "collaborates_with": [], - "skill_path": ".agent/skills/story-planning/SKILL.md" + "skill_path": ".agent/skills/planning/story-planning/SKILL.md" }, { "name": "story-structure", @@ -842,7 +842,7 @@ "概念与前期设计", "质量与回放评测" ], - "skill_path": ".agent/skills/story-structure/SKILL.md" + "skill_path": ".agent/skills/planning/story-structure/SKILL.md" }, { "name": "theme-and-stance", @@ -856,7 +856,7 @@ "collaborates_with": [ "质量与回放评测" ], - "skill_path": ".agent/skills/theme-and-stance/SKILL.md" + "skill_path": ".agent/skills/writing/theme-and-stance/SKILL.md" }, { "name": "write-next-chapter", @@ -874,7 +874,7 @@ "质量与回放评测", "去 AI 味与人感" ], - "skill_path": ".agent/skills/write-next-chapter/SKILL.md" + "skill_path": "muse/content/work/skills/generate/write-next-chapter/SKILL.md" } ] } diff --git a/harness/manifests/test-inventory.json b/muse/lifecycle/quality/harness/manifests/test-inventory.json similarity index 93% rename from harness/manifests/test-inventory.json rename to muse/lifecycle/quality/harness/manifests/test-inventory.json index 86dfbeb..3f21b18 100644 --- a/harness/manifests/test-inventory.json +++ b/muse/lifecycle/quality/harness/manifests/test-inventory.json @@ -1,9 +1,9 @@ { "schema_version": 1, - "generated_scope": "Current agent-example source test assets: .agent/skills/**/test_*.py and *_test.py, tests/skills/** source files, humanization/tests/** source files, harness/**/test_*.py, dashboard/test_server_display.py, and other obvious source test files; excludes .git, .venv, __pycache__ compiled artifacts, deleted working-tree files, and harness specification documents.", + "generated_scope": "Current agent-example source test assets: .agent/skills/**/test_*.py and *_test.py, tests/skills/** source files, muse/lifecycle/quality/humanization/tests/** source files, muse/lifecycle/quality/harness/**/test_*.py, muse/authority/studio/read/test_server_display.py, and other obvious source test files; excludes .git, .venv, __pycache__ compiled artifacts, deleted working-tree files, and harness specification documents.", "entries": [ { - "path": "dashboard/test_server_display.py", + "path": "muse/authority/studio/read/test_server_display.py", "scope": "other", "owner_skill_or_domain": "dashboard", "kind": "tool_contract", @@ -19,7 +19,7 @@ "classification_basis": "Tests dashboard display/encoding helpers and synthetic AI-flavor views; the file declares no database connection." }, { - "path": "harness/evals/skills/diagnose-ai-flavor/run_eval.py", + "path": "muse/lifecycle/quality/harness/evals/skills/diagnose-ai-flavor/run_eval.py", "kind": "skill_behavior_eval", "scope": "runtime_skill", "owner_skill_or_domain": "diagnose-ai-flavor", @@ -36,7 +36,7 @@ "classification_confidence": "high" }, { - "path": "harness/evals/test_skill_eval.py", + "path": "muse/lifecycle/quality/harness/evals/test_skill_eval.py", "kind": "harness_self_test", "scope": "harness", "owner_skill_or_domain": "harness", @@ -51,7 +51,7 @@ "classification_confidence": "high" }, { - "path": "harness/test_run_selected.py", + "path": "muse/lifecycle/quality/harness/test_run_selected.py", "scope": "harness", "owner_skill_or_domain": "harness", "kind": "harness_self_test", @@ -70,7 +70,7 @@ "classification_basis": "Uses temporary manifests and a fake Python child process to test selector, dependency, timeout, nonzero and output-summary handling." }, { - "path": "harness/test_skill_harness.py", + "path": "muse/lifecycle/quality/harness/test_skill_harness.py", "scope": "harness", "owner_skill_or_domain": "harness", "kind": "harness_self_test", @@ -87,7 +87,7 @@ "classification_basis": "Creates temporary SKILL.md/manifest fixtures and tests harness static-audit reports and CLI exit codes." }, { - "path": "humanization/tests/test_contracts.py", + "path": "muse/lifecycle/quality/humanization/tests/test_contracts.py", "scope": "domain", "owner_skill_or_domain": "humanization", "kind": "domain_eval", @@ -104,7 +104,7 @@ "classification_basis": "Checks humanization asset contracts and executes the synthetic U0 patch/review replay; no external Agent/model driver." }, { - "path": "humanization/tests/test_framework_coverage.py", + "path": "muse/lifecycle/quality/humanization/tests/test_framework_coverage.py", "scope": "domain", "owner_skill_or_domain": "humanization", "kind": "tool_contract", @@ -121,7 +121,7 @@ "classification_basis": "Reads the research coverage YAML and checks capability owners, implementation paths, and status values." }, { - "path": "humanization/tests/test_humanization_v2.py", + "path": "muse/lifecycle/quality/humanization/tests/test_humanization_v2.py", "scope": "domain", "owner_skill_or_domain": "humanization", "kind": "domain_eval", @@ -138,7 +138,7 @@ "classification_basis": "Evaluates synthetic voice/rule/carrier gates and lifecycle fixtures with temporary files; no external Agent/model reads SKILL.md." }, { - "path": "humanization/tests/test_load_db.py", + "path": "muse/lifecycle/quality/humanization/tests/test_load_db.py", "kind": "tool_contract", "scope": "domain", "owner_skill_or_domain": "humanization", @@ -153,7 +153,7 @@ "classification_confidence": "high" }, { - "path": "humanization/tests/test_load_db_pg_smoke.py", + "path": "muse/lifecycle/quality/humanization/tests/test_load_db_pg_smoke.py", "kind": "integration", "scope": "domain", "owner_skill_or_domain": "humanization", @@ -169,7 +169,7 @@ "classification_confidence": "high" }, { - "path": "humanization/tests/test_seed_rules_db.py", + "path": "muse/lifecycle/quality/humanization/tests/test_seed_rules_db.py", "kind": "tool_contract", "scope": "domain", "owner_skill_or_domain": "humanization", @@ -215,7 +215,7 @@ ], "skill_behavior_eval": false, "classification_confidence": "high", - "classification_basis": "校验 Skill 发现总索引 .agent/skills/_index.md 与磁盘 skill、SKILL.md frontmatter 和 harness/manifests/skills.json 三方一致,拒绝增删改名漏同步或手改造成的漂移。" + "classification_basis": "校验 Skill 发现总索引 .agent/skills/_index.md 与磁盘 skill、SKILL.md frontmatter 和 muse/lifecycle/quality/harness/manifests/skills.json 三方一致,拒绝增删改名漏同步或手改造成的漂移。" }, { "path": "tests/skills/access-database/test_authorization_snapshot_ddl.py", @@ -1650,7 +1650,7 @@ ], "skill_behavior_eval": false, "classification_confidence": "medium", - "classification_basis": "加载 .agent/skills/write-next-chapter/scripts/produce_next_chapter.py 并断言机械验收子串(门锚)对写手可见;只测纯函数投影,不产生系统事实。" + "classification_basis": "加载 muse/content/work/skills/generate/write-next-chapter/scripts/produce_next_chapter.py 并断言机械验收子串(门锚)对写手可见;只测纯函数投影,不产生系统事实。" }, { "path": "tests/skills/write-next-chapter/test_persist_writer_run.py", @@ -1883,18 +1883,103 @@ "skill_behavior_eval": false, "classification_confidence": "high", "classification_basis": "评委派发桥离线契约:圈定授权工具白名单、盲评输入防泄漏哈希绑定、任务包与盲评输入全等(桥零附加身份)、ModelRunner 协议形状;不连库不真调。" + }, + { + "path": "tests/architecture/test_dsh_adapter.py", + "scope": "domain", + "owner_skill_or_domain": "architecture", + "kind": "tool_contract", + "evidence_level": "deterministic_offline", + "requires": [ + "offline", + "filesystem" + ], + "side_effects": [ + "none" + ], + "skill_behavior_eval": false, + "classification_confidence": "high", + "classification_basis": "用 DSH session JSONL 夹具验证 headless patch、模型/工具边界、未知事件保留、flush 工件归一和非零/压缩/续接失败关闭;不启动真实模型。" + }, + { + "path": "tests/architecture/test_framework_port_purity.py", + "scope": "domain", + "owner_skill_or_domain": "architecture", + "kind": "tool_contract", + "evidence_level": "static_structure", + "requires": [ + "offline", + "filesystem" + ], + "side_effects": [ + "none" + ], + "skill_behavior_eval": false, + "classification_confidence": "high", + "classification_basis": "扫描 framework 目录,阻断框架对 Muse 角色合同、证据账本、数据库和模型策略的反向 import。" + }, + { + "path": "tests/architecture/test_framework_protocol.py", + "scope": "domain", + "owner_skill_or_domain": "architecture", + "kind": "tool_contract", + "evidence_level": "static_structure", + "requires": [ + "offline", + "filesystem" + ], + "side_effects": [ + "none" + ], + "skill_behavior_eval": false, + "classification_confidence": "high", + "classification_basis": "验证 FrameworkExecutionRequest 与 Draft 2020-12 Schema、JSONL 工件 flush/replay、序列缺口和重复发布失败关闭。" + }, + { + "path": "tests/architecture/test_skill_projections.py", + "scope": "domain", + "owner_skill_or_domain": "architecture", + "kind": "tool_contract", + "evidence_level": "static_structure", + "requires": [ + "offline", + "filesystem" + ], + "side_effects": [ + "none" + ], + "skill_behavior_eval": false, + "classification_confidence": "high", + "classification_basis": "对账 Muse skills.json、扁平 Pi/DSH catalog 和源 Skill 的名称、路径、摘要哈希,阻断编排 Skill 进入模型 catalog。" + }, + { + "path": "tests/architecture/test_markdown_links.py", + "scope": "domain", + "owner_skill_or_domain": "architecture", + "kind": "tool_contract", + "evidence_level": "static_structure", + "requires": [ + "offline", + "filesystem" + ], + "side_effects": [ + "none" + ], + "skill_behavior_eval": false, + "classification_confidence": "high", + "classification_basis": "扫描入口、SoT 和 framework/muse 活文档,解析仓内 Markdown 链接并失败关闭死链。" } ], "summary": { - "entry_count": 115, + "entry_count": 120, "by_scope": { "other": 1, "runtime_skill": 103, "harness": 3, - "domain": 8 + "domain": 13 }, "by_kind": { - "tool_contract": 35, + "tool_contract": 40, "skill_behavior_eval": 1, "harness_self_test": 3, "domain_eval": 4, @@ -1905,10 +1990,10 @@ "runtime_contract": 7 }, "by_evidence_level": { - "deterministic_offline": 98, + "deterministic_offline": 99, "real_dependency_integration": 11, - "static_structure": 6 + "static_structure": 10 }, - "total": 115 + "total": 120 } } diff --git a/muse/lifecycle/quality/harness/project_paths.py b/muse/lifecycle/quality/harness/project_paths.py new file mode 100644 index 0000000..6d7ad70 --- /dev/null +++ b/muse/lifecycle/quality/harness/project_paths.py @@ -0,0 +1,17 @@ +"""项目路径解析工具。""" + +from __future__ import annotations + +from pathlib import Path + + +def find_project_root(start: str | Path | None = None) -> Path: + """从任意子目录向上查找同时包含 AGENTS.md 与 .git 的项目根。""" + + candidate = Path(start or __file__).expanduser().resolve() + if candidate.is_file(): + candidate = candidate.parent + for directory in (candidate, *candidate.parents): + if (directory / "AGENTS.md").is_file() and (directory / ".git").exists(): + return directory + raise FileNotFoundError(f"无法从 {candidate} 向上找到项目根") diff --git a/harness/run_selected.py b/muse/lifecycle/quality/harness/run_selected.py similarity index 93% rename from harness/run_selected.py rename to muse/lifecycle/quality/harness/run_selected.py index c42d8c6..ada0407 100644 --- a/harness/run_selected.py +++ b/muse/lifecycle/quality/harness/run_selected.py @@ -21,19 +21,19 @@ from pathlib import Path from typing import Any, Iterable, Optional, Sequence SCHEMA_VERSION = 1 -DEFAULT_MANIFEST_PATH = Path("harness") / "manifests" / "test-inventory.json" +DEFAULT_MANIFEST_PATH = Path("muse") / "lifecycle" / "quality" / "harness" / "manifests" / "test-inventory.json" BLOCKED_REQUIRES = frozenset({"postgresql", "network", "model", "credentials"}) ENTRY_STATUSES = frozenset( {"passed", "failed", "timeout", "blocked_dependency", "not_found"} ) OUTPUT_SUMMARY_LIMIT = 2000 DEFAULT_TIMEOUT_SECONDS = 60.0 -_TEST_ASSET_SCAN_ROOTS = ( +DEFAULT_TEST_ASSET_SCAN_ROOTS = ( Path(".agent") / "skills", Path("tests"), - Path("humanization") / "tests", - Path("harness"), - Path("dashboard"), + Path("muse") / "lifecycle" / "quality" / "humanization" / "tests", + Path("muse") / "lifecycle" / "quality" / "harness", + Path("muse") / "authority" / "studio" / "read", ) _IGNORED_TEST_ASSET_PARTS = frozenset({".git", ".venv", "__pycache__"}) _NO_TESTS_OUTPUT_PATTERN = re.compile( @@ -142,16 +142,22 @@ def _is_test_asset_path(relative: str) -> bool: ) if parts[0] == "tests": return len(parts) > 1 and _is_named_python_test(path) - if parts[:2] == ("humanization", "tests"): - return len(parts) > 2 and _is_named_python_test(path) - if parts[0] in {"harness", "dashboard"}: - return len(parts) > 1 and path.suffix.casefold() == ".py" and path.name.startswith( + if parts[:5] == ("muse", "lifecycle", "quality", "humanization", "tests"): + return len(parts) > 5 and _is_named_python_test(path) + if parts[:4] == ("muse", "lifecycle", "quality", "harness"): + return len(parts) > 4 and path.suffix.casefold() == ".py" and path.name.startswith( + "test_" + ) + if parts[:4] == ("muse", "authority", "studio", "read"): + return len(parts) > 4 and path.suffix.casefold() == ".py" and path.name.startswith( "test_" ) return False -def _scan_test_assets(root: Path) -> tuple[set[str], list[dict[str, Any]]]: +def _scan_test_assets( + root: Path, scan_roots: Sequence[Path] +) -> tuple[set[str], list[dict[str, Any]]]: """扫描 generated_scope 约定的测试资产,失败时保留明确的扫描问题。""" assets: set[str] = set() @@ -169,7 +175,7 @@ def _scan_test_assets(root: Path) -> tuple[set[str], list[dict[str, Any]]]: ) ) - for relative_root in _TEST_ASSET_SCAN_ROOTS: + for relative_root in scan_roots: scan_root = root / relative_root try: if not scan_root.exists(): @@ -298,6 +304,40 @@ def _load_manifest( ) return None, metadata, issues + raw_scan_roots = raw.get( + "test_asset_scan_roots", + [path.as_posix() for path in DEFAULT_TEST_ASSET_SCAN_ROOTS], + ) + if ( + not isinstance(raw_scan_roots, list) + or not raw_scan_roots + or any(not isinstance(value, str) or not value.strip() for value in raw_scan_roots) + ): + issues.append( + _issue( + "manifest_test_asset_scan_roots_invalid", + "测试 manifest 的 test_asset_scan_roots 必须是非空相对路径数组", + path=metadata["path"], + actual=raw_scan_roots, + ) + ) + else: + normalised_roots: list[str] = [] + for value in raw_scan_roots: + normalised, error = _normalise_manifest_entry_path(root, value) + if error is not None or normalised is None: + issues.append( + _issue( + error or "manifest_test_asset_scan_roots_invalid", + "测试资产扫描根必须位于项目根目录内", + path=metadata["path"], + actual=value, + ) + ) + continue + normalised_roots.append(normalised) + metadata["test_asset_scan_roots"] = normalised_roots + metadata["generated_scope_present"] = "generated_scope" in raw if metadata["generated_scope_present"]: generated_scope = raw["generated_scope"] @@ -457,7 +497,14 @@ def _reconcile_test_assets( if not manifest_metadata.get("generated_scope_present"): return [] - disk_assets, issues = _scan_test_assets(root) + scan_roots = [ + Path(value) + for value in manifest_metadata.get( + "test_asset_scan_roots", + [path.as_posix() for path in DEFAULT_TEST_ASSET_SCAN_ROOTS], + ) + ] + disk_assets, issues = _scan_test_assets(root, scan_roots) test_entries = [entry for entry in entries if not entry.get("skill_behavior_eval")] declared_assets = {entry["path"] for entry in test_entries} manifest_metadata["test_assets_scanned"] = len(disk_assets) @@ -1001,7 +1048,7 @@ def _build_parser() -> argparse.ArgumentParser: parser.add_argument( "--manifest", default=None, - help="manifest 路径;相对路径按项目根目录解析,默认 harness/manifests/test-inventory.json", + help="manifest 路径;相对路径按项目根目录解析,默认 muse/lifecycle/quality/harness/manifests/test-inventory.json", ) parser.add_argument("--path", dest="paths", action="append", default=[], help="按相对路径选择条目,可重复") parser.add_argument( diff --git a/harness/skill_harness.py b/muse/lifecycle/quality/harness/skill_harness.py similarity index 93% rename from harness/skill_harness.py rename to muse/lifecycle/quality/harness/skill_harness.py index 572da81..9e37278 100644 --- a/harness/skill_harness.py +++ b/muse/lifecycle/quality/harness/skill_harness.py @@ -1,8 +1,8 @@ #!/usr/bin/env python3 -"""对项目运行时 Skill 文档执行只读静态审计。 +"""对 manifest 登记的项目 Skill 文档执行只读静态审计。 -本模块只读取 `.agent/skills/*/SKILL.md`,不连接数据库、网络或模型,也不修改 -工作树。机器调用使用 :func:`audit_skills`,命令行入口同时支持人读摘要和 JSON。 +本模块扫描配置根下的 ``**/SKILL.md``,以 manifest 的 ``skill_path`` 作为位置 +事实源;不连接数据库、网络或模型,也不修改工作树。 """ from __future__ import annotations @@ -17,8 +17,8 @@ from typing import Any, Iterable, Optional, Sequence SCHEMA_VERSION = 4 -SKILLS_ROOT = Path(".agent") / "skills" -DEFAULT_MANIFEST_PATH = Path("harness") / "manifests" / "skills.json" +SKILL_SCAN_ROOTS = (Path(".agent") / "skills", Path("muse")) +DEFAULT_MANIFEST_PATH = Path("muse") / "lifecycle" / "quality" / "harness" / "manifests" / "skills.json" # 分类取值与质量预算的定义 Owner 是 harness/specs/skill-quality-rubric.md;本模块只做机械判定。 VALID_LIFECYCLES = ( @@ -474,87 +474,68 @@ def _inspect_skill_file(path: Path, root: Path) -> tuple[dict[str, Any], list[di def _scan_skill_directories(root: Path) -> tuple[list[dict[str, Any]], list[dict[str, Any]]]: - skills_root = root / SKILLS_ROOT - relative_skills_root = _relative_path(skills_root, root) + """递归扫描配置根下的 Skill,不把中间分组目录误判为 Skill。""" + entries: list[dict[str, Any]] = [] issues: list[dict[str, Any]] = [] - if not skills_root.exists(): - issues.append( - _issue( - "skills_directory_missing", - "运行时 Skill 目录不存在", - path=relative_skills_root, + for relative_root in SKILL_SCAN_ROOTS: + scan_root = root / relative_root + relative_scan_root = _relative_path(scan_root, root) + if not scan_root.exists(): + if relative_root == Path("muse"): + continue + issues.append( + _issue( + "skills_directory_missing", + "Skill 扫描根不存在", + path=relative_scan_root, + ) ) - ) - return entries, issues - if not skills_root.is_dir(): - issues.append( - _issue( - "skills_directory_not_directory", - "运行时 Skill 路径不是目录", - path=relative_skills_root, + continue + if not scan_root.is_dir(): + issues.append( + _issue( + "skills_directory_not_directory", + "Skill 扫描根不是目录", + path=relative_scan_root, + ) ) - ) - return entries, issues + continue + try: + skill_files = sorted(scan_root.rglob("SKILL.md")) + except OSError as exc: + issues.append( + _issue( + "skills_directory_unreadable", + "无法递归扫描 Skill 目录", + path=relative_scan_root, + error=str(exc), + ) + ) + continue + for skill_file in skill_files: + if not skill_file.is_file(): + issues.append( + _issue( + "skill_file_not_file", + "SKILL.md 路径不是普通文件", + path=_relative_path(skill_file, root), + ) + ) + continue + entry, file_issues = _inspect_skill_file(skill_file, root) + entries.append(entry) + issues.extend(file_issues) - try: - children = sorted(skills_root.iterdir(), key=lambda item: item.name) - except OSError as exc: - issues.append( - _issue( - "skills_directory_unreadable", - "无法列出运行时 Skill 目录", - path=relative_skills_root, - error=str(exc), - ) - ) - return entries, issues - - directories = [child for child in children if child.is_dir()] - if not directories: + if not entries and not issues: issues.append( _issue( "no_skills_found", - "运行时 Skill 目录中未发现 Skill 子目录", - path=relative_skills_root, + "配置的扫描根中未发现 SKILL.md", + path=", ".join(path.as_posix() for path in SKILL_SCAN_ROOTS), ) ) - return entries, issues - - for directory in directories: - skill_file = directory / "SKILL.md" - relative_skill_file = _relative_path(skill_file, root) - disk_entry: dict[str, Any] = { - "directory": directory.name, - "skill_path": relative_skill_file, - "name": None, - "frontmatter_present": False, - } - if not skill_file.exists(): - entries.append(disk_entry) - issues.append( - _issue( - "missing_skill_file", - "Skill 目录缺少 SKILL.md", - path=relative_skill_file, - ) - ) - continue - if not skill_file.is_file(): - entries.append(disk_entry) - issues.append( - _issue( - "skill_file_not_file", - "SKILL.md 路径不是普通文件", - path=relative_skill_file, - ) - ) - continue - - entry, file_issues = _inspect_skill_file(skill_file, root) - entries.append(entry) - issues.extend(file_issues) return entries, issues @@ -563,6 +544,11 @@ def _resolve_manifest_path(root: Path, manifest: str | Path | None) -> Path: path = DEFAULT_MANIFEST_PATH if manifest is None else Path(manifest).expanduser() if not path.is_absolute(): path = root / path + if manifest is None and not path.exists(): + # 纯离线 harness 夹具仍使用旧的临时目录布局;真实项目根以新路径为准。 + legacy = root / "harness" / "manifests" / "skills.json" + if legacy.exists(): + return legacy.resolve() return path.resolve() @@ -686,8 +672,6 @@ def _validate_manifest( declared_paths: set[str] = set() path_occurrences: dict[str, list[int]] = {} name_occurrences: dict[str, list[int]] = {} - skills_root = (root / SKILLS_ROOT).resolve() - for index, item in enumerate(raw_skills): if not isinstance(item, dict): issues.append( @@ -846,11 +830,29 @@ def _validate_manifest( actual=invocation, ) ) - if candidate != candidate.parent / "SKILL.md" or not candidate.is_relative_to(skills_root): + if candidate.name != "SKILL.md": issues.append( _issue( "manifest_skill_path_invalid", - "manifest 条目的 skill_path 必须指向 .agent/skills/*/SKILL.md", + "manifest 条目的 skill_path 必须指向名为 SKILL.md 的文件", + path=normalised_path, + entry_index=index, + ) + ) + if invocation == "model_routed" and not normalised_path.startswith(".agent/skills/"): + issues.append( + _issue( + "model_routed_path_invalid", + "model_routed Skill 必须位于 .agent/skills/ 挂载面", + path=normalised_path, + entry_index=index, + ) + ) + if invocation == "orchestrated" and not normalised_path.startswith("muse/"): + issues.append( + _issue( + "orchestrated_path_invalid", + "orchestrated Skill 必须位于 muse/ 业务树", path=normalised_path, entry_index=index, ) @@ -887,20 +889,6 @@ def _validate_manifest( actual=name, ) ) - if isinstance(name, str) and name.strip(): - expected_path = (root / SKILLS_ROOT / name / "SKILL.md").resolve() - expected_relative = _relative_path(expected_path, root) - if normalised_path != expected_relative: - issues.append( - _issue( - "manifest_skill_path_mismatch", - "manifest skill_path 与 name 对应的 Skill 路径不一致", - path=normalised_path, - entry_index=index, - expected=expected_relative, - actual=normalised_path, - ) - ) for path, indexes in sorted(path_occurrences.items()): if len(indexes) > 1: @@ -1161,10 +1149,8 @@ def _cross_skill_advisories( continue directory = str(entry.get("directory", "")) description = str(entry.get("description", "")) - package_docs = { - path.stem - for path in (root / SKILLS_ROOT / directory).rglob("*.md") - } + skill_dir = (root / skill_path).resolve().parent + package_docs = {path.stem for path in skill_dir.rglob("*.md")} for token in sorted(set(_SKILL_NAME_TOKEN.findall(description))): # 指向自己包内 references/ 文档的连字符名不是路由目标,不算点名。 if token in known or token in _KNOWN_NON_SKILL_TOKENS or token in package_docs: @@ -1217,7 +1203,7 @@ def _exemplar_advisories(root: Path, entries: Sequence[dict[str, Any]]) -> list[ occurrences: dict[str, list[tuple[str, str, int]]] = {} for entry in entries: directory = str(entry.get("directory", "")) - skill_dir = root / SKILLS_ROOT / directory + skill_dir = (root / str(entry.get("skill_path", ""))).resolve().parent for document in _skill_documents(skill_dir): try: text = document.read_text(encoding="utf-8") @@ -1268,7 +1254,7 @@ def _quality_advisories( declared = classes.get(skill_path) if declared is None or declared["lifecycle"] not in VALID_LIFECYCLES: continue - skill_dir = root / SKILLS_ROOT / str(entry.get("directory", "")) + skill_dir = (root / skill_path).resolve().parent advisories.extend(_document_advisories(root, skill_dir, stems)) advisories.extend(_reference_hygiene_advisories(root, skill_dir, skill_path)) lifecycle = str(declared["lifecycle"]) @@ -1338,7 +1324,7 @@ def _quality_advisories( ) ) - scripts_dir = root / SKILLS_ROOT / str(entry.get("directory", "")) / "scripts" + scripts_dir = skill_dir / "scripts" if scripts_dir.is_dir(): try: names = sorted(item.name for item in scripts_dir.iterdir() if item.is_file()) @@ -1440,7 +1426,7 @@ def audit_skills( report: dict[str, Any] = { "schema_version": SCHEMA_VERSION, "root": str(root_path), - "skills_root": SKILLS_ROOT.as_posix(), + "skill_scan_roots": [path.as_posix() for path in SKILL_SCAN_ROOTS], "manifest": { "path": _relative_path(manifest_path, root_path), "loaded": False, @@ -1523,7 +1509,7 @@ def human_summary(report: dict[str, Any]) -> str: def _build_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( - description="只读扫描项目运行时 .agent/skills/*/SKILL.md 的静态卫生审计器。" + description="只读扫描 manifest 登记的项目 SKILL.md 的静态卫生审计器。" ) parser.add_argument( "--root", @@ -1533,7 +1519,7 @@ def _build_parser() -> argparse.ArgumentParser: parser.add_argument( "--manifest", default=None, - help="Skill manifest 路径;相对路径按项目根目录解析,默认 harness/manifests/skills.json", + help="Skill manifest 路径;相对路径按项目根目录解析,默认 muse/lifecycle/quality/harness/manifests/skills.json", ) parser.add_argument( "--json", diff --git a/muse/lifecycle/quality/harness/skills_index.py b/muse/lifecycle/quality/harness/skills_index.py new file mode 100644 index 0000000..cc55f56 --- /dev/null +++ b/muse/lifecycle/quality/harness/skills_index.py @@ -0,0 +1,282 @@ +#!/usr/bin/env python3 +"""生成与机械校验 Skill 发现总索引 `.agent/skills/_index.md`。 + +发现合同(见 AGENTS.md §3):任何 agent(不限宿主)读 AGENTS.md 后必须读总索引, +按 `skill_file` 读取所需能力的 `SKILL.md`;不依赖任何 coding agent 的 skill 自动发现, +物理目录位置完全取自 manifest 的 `skill_path`,允许在挂载面内嵌套。 + +索引只登记三字段: +- `skill_name`:目录名,即调用名; +- `skill_file`:合同文件路径(来自 `muse/lifecycle/quality/harness/manifests/skills.json` 的 `skill_path`); +- `skill_description`:适用与边界描述,与 SKILL.md frontmatter 的 `description` 逐字一致 + (frontmatter 是 SoT,索引是生成物)。 + +生命周期分组取自 `muse/lifecycle/quality/harness/manifests/skills.json` 的 `lifecycle` 字段;取值定义见 +`muse/lifecycle/quality/harness/specs/skill-quality-rubric.md`。 + +用法: + .venv/bin/python harness/skills_index.py --check # 校验索引与磁盘、manifest 一致(默认) + .venv/bin/python harness/skills_index.py --write # 按磁盘与 manifest 重新生成索引 +""" +from __future__ import annotations + +import argparse +import difflib +from pathlib import Path +from typing import Optional, Sequence + +import yaml + +# 生命周期域 → 索引分节标题;顺序即索引分节顺序,标题沿用既有中文域名。 +LIFECYCLE_SECTIONS: tuple[tuple[str, str], ...] = ( + ("platform", "0 平台底座"), + ("ingest", "1 素材导入与拆解"), + ("knowledge", "2 知识与上下文供给"), + ("concept", "3 概念与前期设计"), + ("planning", "4 结构与规划"), + ("writing", "5 正文写作与呈现"), + ("review", "6 检测、评分与诊断"), + ("humanization", "7 去 AI 味与人感"), + ("sovereignty", "8 候选主权与落库"), +) + +INDEX_RELPATH = Path(".agent") / "skills" / "_index.md" +BUSINESS_INDEX_RELPATH = Path("muse") / "_skills_index.md" +MANIFEST_RELPATH = Path("muse") / "lifecycle" / "quality" / "harness" / "manifests" / "skills.json" + +HEADER = """# Skill 方法发现总索引 + +> **发现合同**:任何 agent(不限宿主)读 [`AGENTS.md`](../../AGENTS.md) 后必须读本索引,\ +需要某项能力时按 `skill_file` 读对应 `SKILL.md`。发现只靠 AGENTS.md → 本索引 → SKILL.md \ +的渐进披露,不依赖任何 coding agent 的 skill 自动发现;物理目录位置完全取自 manifest 的 `skill_path`,允许嵌套。 + +本索引只登记三字段:`skill_name`(目录名,即调用名)、`skill_file`(合同文件路径)、\ +`skill_description`(适用与边界描述,与 SKILL.md frontmatter 逐字一致,frontmatter 是 SoT)。\ +分类字段(`lifecycle` / `invocation` / `side_effects` / `compounding`)逐个登记在 \ +[`muse/lifecycle/quality/harness/manifests/skills.json`](../../muse/lifecycle/quality/harness/manifests/skills.json),由 \ +`muse/lifecycle/quality/harness/skill_harness.py` 机械校验,不在本索引重复。 + +本文件由 `muse/lifecycle/quality/harness/skills_index.py --write` 生成,手改会被覆盖;一致性由 `--check` 与 \ +`tests/architecture/test_skills_index.py` 机械把关。按生命周期分域,共 {count} 个 skill。 +""" + +BUSINESS_HEADER = """# Muse 编排 Skill 索引 + +> **业务发现合同**:主代理与业务编排按本索引的 `skill_file` 读取对应 `SKILL.md`。编排 Skill 不进入 Agent 框架的运行期 catalog;物理位置完全取自 manifest 的 `skill_path`。 + +本索引只登记三字段:`skill_name`、`skill_file`、`skill_description`。分类字段与责任方仍以 [`lifecycle/quality/harness/manifests/skills.json`](lifecycle/quality/harness/manifests/skills.json) 为准,由 `muse/lifecycle/quality/harness` 机械校验。 + +本文件由 `muse/lifecycle/quality/harness/skills_index.py --write` 生成,手改会被覆盖;按生命周期分域,共 {count} 个编排 skill。 +""" + + +def _load_manifest(root: Path) -> dict[str, dict[str, str]]: + """读取 skills.json,返回 name → 条目;仅接受与磁盘一致的规范路径。""" + import json + + manifest_path = root / MANIFEST_RELPATH + if not manifest_path.exists(): + legacy = root / "harness" / "manifests" / "skills.json" + if legacy.exists(): + manifest_path = legacy + data = json.loads(manifest_path.read_text(encoding="utf-8")) + entries = data["skills"] if isinstance(data, dict) and "skills" in data else data + result: dict[str, dict[str, str]] = {} + for entry in entries: + result[entry["name"]] = entry + return result + + +def _read_description(skill_md: Path) -> str: + """取 SKILL.md frontmatter 的 description 并折叠换行为单行。""" + text = skill_md.read_text(encoding="utf-8") + if not text.startswith("---\n"): + raise ValueError(f"{skill_md}: 缺少 frontmatter") + end = text.index("\n---\n", 4) + fields = yaml.safe_load(text[4:end]) + description = (fields or {}).get("description") + if not isinstance(description, str) or not description.strip(): + raise ValueError(f"{skill_md}: frontmatter 缺少非空 description") + # YAML 多行块按行折叠;中文行间接缝不需要空格。 + return "".join(line.strip() for line in description.strip().splitlines()) + + +def build_index_text(root: Path) -> tuple[str, int]: + """按 catalog 磁盘 + skills.json 组装索引全文。""" + skills_root = root / ".agent" / "skills" + all_manifest = _load_manifest(root) + manifest = { + name: entry + for name, entry in all_manifest.items() + if entry.get("invocation") == "model_routed" + } + + # 运行期 catalog 只收 model_routed;物理目录允许规划/写作/诊断等中间分组。 + disk_by_path: dict[str, tuple[str, str]] = {} + for skill_md in sorted(skills_root.rglob("SKILL.md")): + relative = skill_md.relative_to(root).as_posix() + disk_by_path[relative] = (skill_md.parent.name, _read_description(skill_md)) + + disk: dict[str, tuple[str, str]] = {} + for name, entry in manifest.items(): + declared_path = str(entry.get("skill_path", "")) + disk_entry = disk_by_path.get(declared_path) + if disk_entry is not None: + disk[name] = (declared_path, disk_entry[1]) + + only_manifest = sorted(set(manifest) - set(disk)) + if only_manifest: + raise ValueError( + "skills.json 登记的 model_routed Skill 不在挂载面磁盘上:" + + ", ".join(only_manifest) + ) + + catalog_paths = {entry.get("skill_path") for entry in manifest.values()} + unregistered_catalog = sorted( + path + for path, (name, _description) in disk_by_path.items() + if path.startswith(".agent/skills/") and path not in catalog_paths + and name not in all_manifest + ) + if unregistered_catalog: + raise ValueError( + "挂载面存在未登记 Skill:" + ", ".join(unregistered_catalog) + ) + + for name, entry in manifest.items(): + expected = disk[name][0] + if entry.get("skill_path") != expected: + raise ValueError( + f"{name}: skills.json skill_path={entry.get('skill_path')!r}," + f"期望 {expected!r}" + ) + lifecycle = entry.get("lifecycle") + if lifecycle not in dict(LIFECYCLE_SECTIONS): + raise ValueError(f"{name}: 未知 lifecycle={lifecycle!r}") + + lines: list[str] = [HEADER.format(count=len(disk)).rstrip()] + for lifecycle, title in LIFECYCLE_SECTIONS: + names = sorted( + name for name, entry in manifest.items() if entry["lifecycle"] == lifecycle + ) + if not names: + continue + lines.append("") + lines.append(f"## {title}") + lines.append("") + lines.append("| skill_name | skill_file | skill_description |") + lines.append("|---|---|---|") + for name in names: + lines.append( + f"| {name} | `{disk[name][0]}` | {disk[name][1]} |" + ) + lines.append("") + return "\n".join(lines), len(disk) + + +def build_business_index_text(root: Path) -> tuple[str, int]: + """按 manifest 生成 Muse 编排 Skill 索引。""" + + manifest = { + name: entry + for name, entry in _load_manifest(root).items() + if entry.get("invocation") == "orchestrated" + } + disk: dict[str, tuple[str, str]] = {} + for name, entry in manifest.items(): + declared_path = str(entry.get("skill_path", "")) + if not declared_path.startswith("muse/"): + raise ValueError(f"orchestrated Skill 不在 muse/ 业务树:{name}") + skill_md = root / declared_path + if not skill_md.is_file(): + raise ValueError(f"编排 Skill 路径不存在:{declared_path}") + disk[name] = (declared_path, _read_description(skill_md)) + if skill_md.parent.name != name: + raise ValueError(f"Skill 目录名与 name 不一致:{name} -> {declared_path}") + + lines: list[str] = [BUSINESS_HEADER.format(count=len(disk)).rstrip()] + for lifecycle, title in LIFECYCLE_SECTIONS: + names = sorted( + name for name, entry in manifest.items() if entry["lifecycle"] == lifecycle + ) + if not names: + continue + lines.extend(["", f"## {title}", "", "| skill_name | skill_file | skill_description |", "|---|---|---|"]) + for name in names: + lines.append(f"| {name} | `{disk[name][0]}` | {disk[name][1]} |") + lines.append("") + return "\n".join(lines), len(disk) + + +def check(root: Path) -> Optional[str]: + """校验两份索引与 manifest、磁盘一致;一致返回 None,否则返回差异文本。""" + + expected_catalog, _ = build_index_text(root) + expected_business, _ = build_business_index_text(root) + results: list[str] = [] + for relative_path, expected in ( + (INDEX_RELPATH, expected_catalog), + (BUSINESS_INDEX_RELPATH, expected_business), + ): + index_path = root / relative_path + actual = index_path.read_text(encoding="utf-8") if index_path.exists() else "" + if actual == expected: + continue + results.append( + "".join( + difflib.unified_diff( + actual.splitlines(keepends=True), + expected.splitlines(keepends=True), + fromfile=str(relative_path) + "(现状)", + tofile=str(relative_path) + "(按磁盘与 skills.json 重建)", + n=2, + ) + ) + ) + return "\n".join(results) or None + + +def main(argv: Optional[Sequence[str]] = None) -> int: + parser = argparse.ArgumentParser( + description="生成与机械校验两份 Skill 发现索引(三字段)。" + ) + parser.add_argument("--root", default=".", help="项目根目录,默认为当前目录") + group = parser.add_mutually_exclusive_group() + group.add_argument( + "--check", + action="store_true", + help="校验索引与磁盘、skills.json 一致(默认模式)", + ) + group.add_argument( + "--write", action="store_true", help="按磁盘与 skills.json 重新生成索引" + ) + args = parser.parse_args(argv) + root = Path(args.root).resolve() + + try: + if args.write: + catalog_text, catalog_count = build_index_text(root) + business_text, business_count = build_business_index_text(root) + (root / INDEX_RELPATH).write_text(catalog_text, encoding="utf-8") + (root / BUSINESS_INDEX_RELPATH).parent.mkdir(parents=True, exist_ok=True) + (root / BUSINESS_INDEX_RELPATH).write_text(business_text, encoding="utf-8") + print( + f"已重新生成 {INDEX_RELPATH}({catalog_count} 个方法 skill)与 " + f"{BUSINESS_INDEX_RELPATH}({business_count} 个编排 skill)" + ) + return 0 + diff = check(root) + except (ValueError, KeyError, FileNotFoundError) as error: + print(f"skills_index 失败:{error}") + return 2 + + if diff is None: + print("skills_index 一致:索引与磁盘、skills.json 相符") + return 0 + print("skills_index 漂移:请用 muse/lifecycle/quality/harness/skills_index.py --write 重新生成") + print(diff) + return 1 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/harness/specs/skill-quality-rubric.md b/muse/lifecycle/quality/harness/specs/skill-quality-rubric.md similarity index 94% rename from harness/specs/skill-quality-rubric.md rename to muse/lifecycle/quality/harness/specs/skill-quality-rubric.md index 9b8d2d9..3ef8b32 100644 --- a/harness/specs/skill-quality-rubric.md +++ b/muse/lifecycle/quality/harness/specs/skill-quality-rubric.md @@ -1,7 +1,7 @@ # Skill 分类与质量评分标准 > 状态:生效规范 -> 适用范围:`agent-example/.agent/skills/*/` +> 适用范围:`agent-example/muse/lifecycle/quality/harness/manifests/skills.json` 的 `skill_path` 指向的 Skill 包 > Owner:`agent-example/harness/` > 本文件是开发与治理支架规范,不属于任何 Skill 的运行时提示词。 @@ -16,11 +16,11 @@ | 主题 | Owner | |---|---| | 证据分级、测试与行为评测边界、`SKILL.md` 禁止携带的开发测试内容 | [`skill-testing.md`](skill-testing.md) | -| 何时审、谁审、审查产出格式 | [`../../AGENTS.md`](../../AGENTS.md) 第 11 节 | -| 合同责任方与领域 SoT | `AGENTS.md` 第 3 节与 `.agent/docs/architecture/domains/` | -| 经验升格链与升格判据 | [06-质量与复利领域](../../.agent/docs/architecture/domains/06-质量与复利领域.md) §6 | -| 范式生命周期与消费合同 | [03-范式领域](../../.agent/docs/architecture/domains/03-范式领域.md) | -| 业务字段合同 | `meta/schemas/` | +| 何时审、谁审、审查产出格式 | [`AGENTS.md`](../../../../../AGENTS.md) 第 11 节 | +| 合同责任方与领域 SoT | `AGENTS.md` 第 3 节与 `muse/sot/domains/` | +| 经验升格链与升格判据 | [06-质量与复利领域](../../../../sot/domains/06-质量与复利领域.md) §6 | +| 范式生命周期与消费合同 | [03-范式领域](../../../../sot/domains/03-范式领域.md) | +| 业务字段合同 | `muse/content/muse/content/meta/schemas/` | 评分本身属于证据分级的第一层(静态结构检查)。**高分不等于 Skill 有效**:维度 D1 的真实触发效果、D3 的实际不重叠,只能由行为评测证明。 @@ -34,7 +34,7 @@ ### 2.1 `lifecycle` —— 作品创建周期定位 -取值与 [`.agent/skills/_index.md`](../../.agent/skills/_index.md) 的九个分域一一对应,每个 Skill 归它主用的那一段;跨阶段取用在索引维护,不改归属。 +取值与 [`.agent/skills/_index.md`](../../../../../.agent/skills/_index.md) 的九个分域一一对应,每个 Skill 归它主用的那一段;跨阶段取用在索引维护,不改归属。 | 取值 | 周期段 | |---|---| @@ -250,7 +250,7 @@ D8 不设阻断:接入复利是增量工程,不是正确性缺陷。但 0 新增、改名或调整 Skill 分类时,必须在同一次改动内完成: -1. 同步 `harness/manifests/skills.json` 的四个分类字段; +1. 同步 `muse/lifecycle/quality/harness/manifests/skills.json` 的四个分类字段; 2. 同步 `.agent/skills/_index.md`; -3. 同步 `AGENTS.md` 第 3 节领域表;绑创作 scenario 的同步 `meta/chains/`; +3. 同步 `AGENTS.md` 第 3 节领域表;绑创作 scenario 的同步 `muse/lifecycle/flow/chains/`; 4. 运行 `skill_harness.py`,阻断级问题为零。 diff --git a/harness/specs/skill-testing.md b/muse/lifecycle/quality/harness/specs/skill-testing.md similarity index 96% rename from harness/specs/skill-testing.md rename to muse/lifecycle/quality/harness/specs/skill-testing.md index 8967b34..91d84c1 100644 --- a/harness/specs/skill-testing.md +++ b/muse/lifecycle/quality/harness/specs/skill-testing.md @@ -1,7 +1,7 @@ # Skill 测试与评测规范 > 状态:生效规范 -> 适用范围:`agent-example/.agent/skills/*/SKILL.md`、其确定性工具和 Skill 行为评测。 +> 适用范围:`agent-example/muse/lifecycle/quality/harness/manifests/skills.json` 的 `skill_path` 指向的 `SKILL.md`、其确定性工具和 Skill 行为评测。 > Owner:`agent-example/harness/` > 本文件是开发与评测支架规范,不属于任何 Skill 的运行时提示词。 diff --git a/harness/test_run_selected.py b/muse/lifecycle/quality/harness/test_run_selected.py similarity index 92% rename from harness/test_run_selected.py rename to muse/lifecycle/quality/harness/test_run_selected.py index 20d66d9..cf1aa0a 100644 --- a/harness/test_run_selected.py +++ b/muse/lifecycle/quality/harness/test_run_selected.py @@ -18,7 +18,7 @@ from typing import Any, Iterable try: from .run_selected import main -except ImportError: # 允许直接执行 `.venv/bin/python harness/test_run_selected.py` +except ImportError: # 允许直接执行 `.venv/bin/python muse/lifecycle/quality/harness/test_run_selected.py` from run_selected import main @@ -28,6 +28,7 @@ class RunSelectedTests(unittest.TestCase): entries: Iterable[dict[str, Any]], *, generated_scope: str | None = None, + test_asset_scan_roots: list[str] | None = None, ) -> tuple[tempfile.TemporaryDirectory[str], Path]: temporary = tempfile.TemporaryDirectory() root = Path(temporary.name) @@ -50,7 +51,7 @@ class RunSelectedTests(unittest.TestCase): " print('failure stderr', file=sys.stderr)\n" " raise SystemExit(7)\n" "if script.name == 'sleep.py':\n" - " time.sleep(2)\n" + " time.sleep(5)\n" "if script.name == 'noisy.py':\n" " print('x' * 5000)\n" "else:\n" @@ -75,6 +76,8 @@ class RunSelectedTests(unittest.TestCase): } if generated_scope is not None: manifest_payload["generated_scope"] = generated_scope + if test_asset_scan_roots is not None: + manifest_payload["test_asset_scan_roots"] = test_asset_scan_roots manifest_path.write_text( json.dumps(manifest_payload, indent=2) + "\n", encoding="utf-8", @@ -194,7 +197,7 @@ class RunSelectedTests(unittest.TestCase): "--path", "sleep.py", "--timeout-seconds", - "0.5", + "1.5", ) self.assertEqual(return_code, 1) @@ -292,6 +295,24 @@ class RunSelectedTests(unittest.TestCase): ) self.assertFalse((root / "invocations.log").exists()) + def test_generated_scope_uses_manifest_scan_roots(self) -> None: + _, manifest = self.make_project( + [self.entry("custom-tests/test_registered.py")], + generated_scope="temporary test asset inventory", + test_asset_scan_roots=["custom-tests"], + ) + root = manifest.parent + (root / "custom-tests" / "test_registered.py").write_text( + "def test_registered():\n assert True\n", encoding="utf-8" + ) + + return_code, report = self.invoke(root, manifest, "--all-offline") + + self.assertEqual(return_code, 0) + self.assertEqual( + report["manifest"]["test_asset_scan_roots"], ["custom-tests"] + ) + def test_generated_scope_rejects_manifest_extra_asset(self) -> None: _, manifest = self.make_project( [ @@ -321,7 +342,7 @@ class RunSelectedTests(unittest.TestCase): def test_generated_scope_accepts_existing_behavior_eval_entry(self) -> None: eval_entry = self.entry( - "harness/evals/skills/demo/run_eval.py", + "muse/lifecycle/quality/harness/evals/skills/demo/run_eval.py", kind="skill_behavior_eval", requires=["model"], ) @@ -336,7 +357,7 @@ class RunSelectedTests(unittest.TestCase): root = manifest.parent registered_test = root / "tests" / "skills" / "registered" / "test_registered.py" registered_test.write_text("def test_registered():\n assert True\n", encoding="utf-8") - (root / "harness" / "evals" / "skills" / "demo" / "run_eval.py").write_text( + (root / "muse" / "lifecycle" / "quality" / "harness" / "evals" / "skills" / "demo" / "run_eval.py").write_text( "# eval entry\n", encoding="utf-8" ) @@ -351,7 +372,7 @@ class RunSelectedTests(unittest.TestCase): def test_generated_scope_rejects_missing_behavior_eval_entry(self) -> None: eval_entry = self.entry( - "harness/evals/skills/demo/run_eval.py", + "muse/lifecycle/quality/harness/evals/skills/demo/run_eval.py", kind="skill_behavior_eval", requires=["model"], create=False, @@ -378,7 +399,7 @@ class RunSelectedTests(unittest.TestCase): for issue in report["issues"] if issue["code"] == "manifest_eval_entry_missing" ], - ["harness/evals/skills/demo/run_eval.py"], + ["muse/lifecycle/quality/harness/evals/skills/demo/run_eval.py"], ) def test_generated_scope_ignores_non_test_helpers_under_test_roots(self) -> None: @@ -441,7 +462,7 @@ class RunSelectedTests(unittest.TestCase): entries = [ self.entry("tests/skills/function/test_function.py"), self.entry("tests/skills/class/test_class.py"), - self.entry("harness/test_main_entry.py"), + self.entry("muse/lifecycle/quality/harness/test_main_entry.py"), ] _, manifest = self.make_project( entries, @@ -455,7 +476,7 @@ class RunSelectedTests(unittest.TestCase): "import unittest\n\nclass Fixture(unittest.TestCase):\n pass\n", encoding="utf-8", ) - (root / "harness" / "test_main_entry.py").write_text( + (root / "muse" / "lifecycle" / "quality" / "harness" / "test_main_entry.py").write_text( "if __name__ == \"__main__\":\n print(\"script\")\n", encoding="utf-8", ) diff --git a/harness/test_skill_harness.py b/muse/lifecycle/quality/harness/test_skill_harness.py similarity index 94% rename from harness/test_skill_harness.py rename to muse/lifecycle/quality/harness/test_skill_harness.py index c16f524..9cf0e72 100644 --- a/harness/test_skill_harness.py +++ b/muse/lifecycle/quality/harness/test_skill_harness.py @@ -40,8 +40,9 @@ class SkillHarnessTests(unittest.TestCase): invocation: str = "model_routed", side_effects: Optional[list[str]] = None, ) -> dict[str, object]: + skill_name = Path(directory).name return { - "name": directory, + "name": skill_name, "lifecycle": lifecycle, "compounding": compounding, "invocation": invocation, @@ -66,7 +67,7 @@ class SkillHarnessTests(unittest.TestCase): skill_dir = root / ".agent" / "skills" / directory skill_dir.mkdir(parents=True, exist_ok=True) skill_path = skill_dir / "SKILL.md" - frontmatter_name = directory if name is None else name + frontmatter_name = Path(directory).name if name is None else name flag = "disable-model-invocation: true\n" if orchestrated else "" skill_path.write_text( f"---\nname: {frontmatter_name}\ndescription: {description}\n{flag}---\n{body}", @@ -86,7 +87,8 @@ class SkillHarnessTests(unittest.TestCase): entries = [] skills_root = root / ".agent" / "skills" if skills_root.exists(): - for directory in sorted(skills_root.iterdir(), key=lambda item: item.name): + for skill_md in sorted(skills_root.rglob("SKILL.md")): + directory = skill_md.parent if directory.is_dir(): entries.append( { @@ -100,7 +102,7 @@ class SkillHarnessTests(unittest.TestCase): "skill_path": ( Path(".agent") / "skills" - / directory.name + / directory.relative_to(skills_root) / "SKILL.md" ).as_posix(), } @@ -130,6 +132,40 @@ class SkillHarnessTests(unittest.TestCase): self.assertEqual(report["skills_scanned"], 1) self.assertEqual(report["issues"], []) + def test_nested_skill_path_is_accepted_from_manifest(self) -> None: + with tempfile.TemporaryDirectory() as temporary: + root = Path(temporary) + self.make_skill(root, "planning/alpha") + + report = audit_skills(root) + + self.assertTrue(report["ok"], report["issues"]) + self.assertEqual( + report["skills"][0]["skill_path"], + ".agent/skills/planning/alpha/SKILL.md", + ) + + def test_model_routed_skill_cannot_leave_mount_surface(self) -> None: + with tempfile.TemporaryDirectory() as temporary: + root = Path(temporary) + skill = root / "muse" / "method" / "SKILL.md" + skill.parent.mkdir(parents=True) + skill.write_text( + "---\nname: method\ndescription: 离线夹具\n---\n# 合同\n", + encoding="utf-8", + ) + entry = self.manifest_entry("method") + entry["skill_path"] = "muse/method/SKILL.md" + self.write_manifest(root, [entry]) + + report = audit_skills(root) + + self.assertFalse(report["ok"]) + self.assertIn( + "model_routed_path_invalid", + {issue["code"] for issue in report["issues"]}, + ) + def test_pollution_is_reported_for_each_obvious_category(self) -> None: with tempfile.TemporaryDirectory() as temporary: root = Path(temporary) @@ -381,7 +417,6 @@ class SkillHarnessTests(unittest.TestCase): "manifest_duplicate_name", "manifest_skill_missing", "manifest_skill_extra", - "manifest_skill_path_mismatch", "manifest_name_directory_mismatch", "manifest_skill_path_missing", }.issubset(codes) @@ -417,12 +452,13 @@ class SkillHarnessTests(unittest.TestCase): with tempfile.TemporaryDirectory() as temporary: root = Path(temporary) (root / ".agent" / "skills" / "missing").mkdir(parents=True) + self.write_manifest(root, [self.manifest_entry("missing")]) report = audit_skills(root) self.assertFalse(report["ok"]) self.assertIn( - "missing_skill_file", + "manifest_skill_path_missing", {issue["code"] for issue in report["issues"]}, ) diff --git a/humanization/README.md b/muse/lifecycle/quality/humanization/README.md similarity index 72% rename from humanization/README.md rename to muse/lifecycle/quality/humanization/README.md index 8b68d3a..848306c 100644 --- a/humanization/README.md +++ b/muse/lifecycle/quality/humanization/README.md @@ -1,13 +1,13 @@ # humanization · 去 AI 味与人感体系(agent-example 先行验证副本) -本目录是去 AI 味与人感体系的资产层与执行骨架,初始拷贝自父仓 [`muse-deai/`](../../muse-deai/)(提交 `92a88e86`,一级能力),自拷贝之日起由 agent-example 自治管理与演进。 +本目录是去 AI 味与人感体系的资产层与执行骨架,初始拷贝自父仓 [`muse-deai/`](../../../../../muse-deai/)(提交 `92a88e86`,一级能力),自拷贝之日起由 agent-example 自治管理与演进。 ## 权威与演进规则 - **验证期本目录自治**:合同、规则、样例、骨架的改动直接在本仓演进,Git 历史留痕;父仓 muse-deai 同主题暂停更新,不产生两套并行版本。 - **同步方向只有一条**:验证收敛、人感体系从 agent-example 升华进 Muse 时,把验证过的资产同步回父仓 muse-deai 并更新设计文档。升华之前不向父仓回填。 -- 设计 SoT(概念定义、五技能合同、验收口径)归属父仓 [`design-docs/专题-09-去AI味与人感体系设计.md`](../../design-docs/专题-09-去AI味与人感体系设计.md);本目录不重复定义概念,验证中发现合同级缺陷时向父仓提请修订。 -- 案例卡的正式载体是 `muse-example` 库(见 `.agent/skills/capture-ai-flavor-cases`);本目录 `cards/` 只存合成示例。`src/deai/cards.py` 保留早期离线 API 兼容层,但输出/读取已对齐 `ai-flavor-case-v1`,生产采集入口仍是 `capture_cases.py`。 +- 设计 SoT(概念定义、五技能合同、验收口径)归属父仓 [`design-docs/专题-09-去AI味与人感体系设计.md`](../../../../../design-docs/专题-09-去AI味与人感体系设计.md);本目录不重复定义概念,验证中发现合同级缺陷时向父仓提请修订。 +- 案例卡的正式载体是 `muse-example` 库(见 `muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases`);本目录 `cards/` 只存合成示例。`src/deai/cards.py` 保留早期离线 API 兼容层,但输出/读取已对齐 `ai-flavor-case-v1`,生产采集入口仍是 `capture_cases.py`。 ## 目录 @@ -25,7 +25,7 @@ eval/ 判别试跑与回归探针:../.venv/bin/python eval/run_eval.py config.yaml 模型角色分离配置(改写模型 ≠ 选择模型,代码强制) ``` -Skill 通过已安装的 `muse-deai` 消费 `src/deai/`(`agent-example/requirements.txt` 的 `-e ./humanization`),不得再把 `humanization/src` 插入 `sys.path`。本目录的 `tests/`、`tools/`、`eval/` 仍可直接装载源码树。 +Skill 通过已安装的 `muse-deai` 消费 `src/deai/`(`agent-example/requirements.txt` 的 `-e ./muse/lifecycle/quality/humanization`),不得再把 `muse/lifecycle/quality/humanization/src` 插入 `sys.path`。本目录的 `tests/`、`tools/`、`eval/` 仍可直接装载源码树。 ## 与五个技能 skill 的对应 @@ -40,6 +40,6 @@ Skill 通过已安装的 `muse-deai` 消费 `src/deai/`(`agent-example/require ## 运行测试 ```bash -cd agent-example/humanization -../.venv/bin/python -m unittest discover -s tests -v +cd agent-example/muse/lifecycle/quality/humanization +../../../../.venv/bin/python -m unittest discover -s tests -v ``` diff --git a/humanization/cards/backfill-example.yaml b/muse/lifecycle/quality/humanization/cards/backfill-example.yaml similarity index 100% rename from humanization/cards/backfill-example.yaml rename to muse/lifecycle/quality/humanization/cards/backfill-example.yaml diff --git a/humanization/config.yaml b/muse/lifecycle/quality/humanization/config.yaml similarity index 100% rename from humanization/config.yaml rename to muse/lifecycle/quality/humanization/config.yaml diff --git a/humanization/contracts/audit_report.schema.json b/muse/lifecycle/quality/humanization/contracts/audit_report.schema.json similarity index 100% rename from humanization/contracts/audit_report.schema.json rename to muse/lifecycle/quality/humanization/contracts/audit_report.schema.json diff --git a/humanization/contracts/case_card.schema.json b/muse/lifecycle/quality/humanization/contracts/case_card.schema.json similarity index 100% rename from humanization/contracts/case_card.schema.json rename to muse/lifecycle/quality/humanization/contracts/case_card.schema.json diff --git a/humanization/contracts/finding.schema.json b/muse/lifecycle/quality/humanization/contracts/finding.schema.json similarity index 100% rename from humanization/contracts/finding.schema.json rename to muse/lifecycle/quality/humanization/contracts/finding.schema.json diff --git a/humanization/contracts/patch.schema.json b/muse/lifecycle/quality/humanization/contracts/patch.schema.json similarity index 100% rename from humanization/contracts/patch.schema.json rename to muse/lifecycle/quality/humanization/contracts/patch.schema.json diff --git a/humanization/contracts/prevention.schema.json b/muse/lifecycle/quality/humanization/contracts/prevention.schema.json similarity index 100% rename from humanization/contracts/prevention.schema.json rename to muse/lifecycle/quality/humanization/contracts/prevention.schema.json diff --git a/humanization/contracts/rule.schema.json b/muse/lifecycle/quality/humanization/contracts/rule.schema.json similarity index 100% rename from humanization/contracts/rule.schema.json rename to muse/lifecycle/quality/humanization/contracts/rule.schema.json diff --git a/humanization/contracts/sample.schema.json b/muse/lifecycle/quality/humanization/contracts/sample.schema.json similarity index 100% rename from humanization/contracts/sample.schema.json rename to muse/lifecycle/quality/humanization/contracts/sample.schema.json diff --git a/humanization/contracts/voice_baseline.schema.json b/muse/lifecycle/quality/humanization/contracts/voice_baseline.schema.json similarity index 100% rename from humanization/contracts/voice_baseline.schema.json rename to muse/lifecycle/quality/humanization/contracts/voice_baseline.schema.json diff --git a/humanization/eval/run_eval.py b/muse/lifecycle/quality/humanization/eval/run_eval.py similarity index 100% rename from humanization/eval/run_eval.py rename to muse/lifecycle/quality/humanization/eval/run_eval.py diff --git a/humanization/pyproject.toml b/muse/lifecycle/quality/humanization/pyproject.toml similarity index 100% rename from humanization/pyproject.toml rename to muse/lifecycle/quality/humanization/pyproject.toml diff --git a/humanization/research/20-project-humanization-rule-catalog.zh-CN.md b/muse/lifecycle/quality/humanization/research/20-project-humanization-rule-catalog.zh-CN.md similarity index 99% rename from humanization/research/20-project-humanization-rule-catalog.zh-CN.md rename to muse/lifecycle/quality/humanization/research/20-project-humanization-rule-catalog.zh-CN.md index ebd2277..decc4eb 100644 --- a/humanization/research/20-project-humanization-rule-catalog.zh-CN.md +++ b/muse/lifecycle/quality/humanization/research/20-project-humanization-rule-catalog.zh-CN.md @@ -2,11 +2,11 @@ > 版本:v0.1 > -> 性质:研究候选目录,不是生产规则库,不等于 `humanization/rules/` 中的 `active` 规则。 +> 性质:研究候选目录,不是生产规则库,不等于 `muse/lifecycle/quality/muse/lifecycle/quality/humanization/rules/` 中的 `active` 规则。 > > 研究范围:仓内 20 个开源项目研究报告、20 项覆盖矩阵,以及中文小说迁移时的反例与保护要求。 > -> 来源入口: [20 项研究总报告](../../../.agents/knowledge/ai-writing-humanization-open-source-research.md);[20 项覆盖矩阵](20-project-skill-coverage.yaml)。 +> 来源入口: [20 项研究总报告](../../../../../../.agents/knowledge/ai-writing-humanization-open-source-research.md);[20 项覆盖矩阵](20-project-skill-coverage.yaml)。 > > 目录规模:129 个归一化条目;其中包含框架合同、问题候选、声音/载体保护、正向目标和明确拒绝项。规则名称与说明均使用简体中文,项目名、文件格式和合同状态保留必要的原始标识。 > diff --git a/humanization/research/20-project-skill-coverage.yaml b/muse/lifecycle/quality/humanization/research/20-project-skill-coverage.yaml similarity index 71% rename from humanization/research/20-project-skill-coverage.yaml rename to muse/lifecycle/quality/humanization/research/20-project-skill-coverage.yaml index 7bdcd38..97322d5 100644 --- a/humanization/research/20-project-skill-coverage.yaml +++ b/muse/lifecycle/quality/humanization/research/20-project-skill-coverage.yaml @@ -46,98 +46,98 @@ capabilities: - id: detect_edit_separation evidence_sources: [no-ai-slop, oh-story-claudecode, academic-humanizer] owner_skill: diagnose-ai-flavor - implementation: humanization/src/deai/diagnose.py - test: humanization/tests/test_contracts.py + implementation: muse/lifecycle/quality/humanization/src/deai/diagnose.py + test: muse/lifecycle/quality/humanization/tests/test_contracts.py status: implemented - id: five_layer_detection evidence_sources: [neuro-book, oh-story-claudecode, avoid-ai-writing] owner_skill: diagnose-ai-flavor - implementation: humanization/src/deai/diagnose.py - test: humanization/tests/test_humanization_v2.py + implementation: muse/lifecycle/quality/humanization/src/deai/diagnose.py + test: muse/lifecycle/quality/humanization/tests/test_humanization_v2.py status: implemented note: regex/handler/density机械执行;semantic仍需外部模型或人工 - id: carrier_scope_and_mask evidence_sources: [shuorenhua, avoid-ai-writing, neuro-book] owner_skill: diagnose-ai-flavor - implementation: humanization/src/deai/carriers.py - test: humanization/tests/test_humanization_v2.py + implementation: muse/lifecycle/quality/humanization/src/deai/carriers.py + test: muse/lifecycle/quality/humanization/tests/test_humanization_v2.py status: implemented - id: voice_first_baseline evidence_sources: [humanizer, shuorenhua, inkos] owner_skill: establish-voice-baseline - implementation: .agent/skills/establish-voice-baseline/scripts/establish_voice_baseline.py - test: humanization/tests/test_humanization_v2.py + implementation: muse/lifecycle/quality/humanization/skills/establish-voice-baseline/scripts/establish_voice_baseline.py + test: muse/lifecycle/quality/humanization/tests/test_humanization_v2.py status: implemented note: 角色策略仍需planner/作者补充和确认 - id: pre_generation_guidance evidence_sources: [no-ai-slop, neuro-book, humanizer] owner_skill: prevent-ai-flavor - implementation: .agent/skills/prevent-ai-flavor/scripts/prevent_ai_flavor.py + implementation: muse/lifecycle/quality/humanization/skills/prevent-ai-flavor/scripts/prevent_ai_flavor.py test: tests/skills/assemble-context/test_assemble_writer_context.py status: implemented - id: sf_snf_boundary_regression evidence_sources: [speak-human-tw, shuorenhua, neuro-book] owner_skill: capture-ai-flavor-cases - implementation: humanization/samples - test: humanization/src/deai/evaluation.py + implementation: muse/lifecycle/quality/humanization/samples + test: muse/lifecycle/quality/humanization/src/deai/evaluation.py status: implemented - id: minimal_unique_patch evidence_sources: [inkos, Openwrite, shuorenhua] owner_skill: revise-ai-flavor - implementation: humanization/src/deai/patch.py - test: humanization/tests/test_contracts.py + implementation: muse/lifecycle/quality/humanization/src/deai/patch.py + test: muse/lifecycle/quality/humanization/tests/test_contracts.py status: implemented - id: preservation_and_modality evidence_sources: [humanizer, academic-humanizer, shuorenhua] owner_skill: revise-ai-flavor - implementation: humanization/src/deai/gates.py - test: humanization/tests/test_humanization_v2.py + implementation: muse/lifecycle/quality/humanization/src/deai/gates.py + test: muse/lifecycle/quality/humanization/tests/test_humanization_v2.py status: implemented note: POV/因果/伏笔仍需事实快照和语义detector - id: bounded_revision_and_original_wins evidence_sources: [inkos, oh-story-claudecode, neuro-book] owner_skill: revise-ai-flavor - implementation: humanization/src/deai/pipeline.py + implementation: muse/lifecycle/quality/humanization/src/deai/pipeline.py test: tests/skills/revise-ai-flavor/test_revise_ai_flavor.py status: implemented note: 当前以最多3轮合同、复扫和pairwise no_gain实现;跨轮最佳快照编排仍由上层负责 - id: source_revalidation evidence_sources: [shuorenhua, neuro-book] owner_skill: capture-ai-flavor-cases - implementation: .agent/skills/capture-ai-flavor-cases/scripts/capture_cases.py + implementation: muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/scripts/capture_cases.py test: tests/skills/capture-ai-flavor-cases/test_capture_cases.py status: implemented - id: case_to_rule_lifecycle evidence_sources: [unslop, shuorenhua, neuro-book] owner_skill: promote-ai-flavor-rule - implementation: .agent/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py + implementation: muse/lifecycle/quality/humanization/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py test: tests/skills/promote-ai-flavor-rule/test_propose_rule.py status: implemented note: 状态写回数据库;规则文件激活需显式输出和人工审批 - id: cross_model_pairwise evidence_sources: [inkos, neuro-book, oh-story-claudecode] owner_skill: revise-ai-flavor - implementation: humanization/src/deai/pairwise.py - test: humanization/tests/test_contracts.py + implementation: muse/lifecycle/quality/humanization/src/deai/pairwise.py + test: muse/lifecycle/quality/humanization/tests/test_contracts.py status: implemented - id: holdout_effect_evaluation evidence_sources: [neuro-book, speak-human-tw, im-not-ai] owner_skill: promote-ai-flavor-rule - implementation: humanization/src/deai/evaluation.py - test: humanization/tests/test_humanization_v2.py + implementation: muse/lifecycle/quality/humanization/src/deai/evaluation.py + test: muse/lifecycle/quality/humanization/tests/test_humanization_v2.py status: partial note: 合同回放和holdout计数门已建;真实多作者多题材holdout尚未形成 - id: model_drift_deprecation evidence_sources: [inkos, im-not-ai, neuro-book] owner_skill: promote-ai-flavor-rule - implementation: humanization/src/deai/evaluation.py - test: humanization/tests/test_humanization_v2.py + implementation: muse/lifecycle/quality/humanization/src/deai/evaluation.py + test: muse/lifecycle/quality/humanization/tests/test_humanization_v2.py status: partial note: 人工审批的deprecate输出已建;自动跨模型巡检尚未接入生产调度 - id: independent_reader_blind_eval evidence_sources: [neuro-book, inkos, humanizer] owner_skill: promote-ai-flavor-rule - implementation: humanization/eval - test: humanization/tests/test_humanization_v2.py + implementation: muse/lifecycle/quality/humanization/eval + test: muse/lifecycle/quality/humanization/tests/test_humanization_v2.py status: pending note: pairwise合同存在,但独立读者规模化盲评未完成 diff --git a/humanization/rules/density/d001.yaml b/muse/lifecycle/quality/humanization/rules/density/d001.yaml similarity index 100% rename from humanization/rules/density/d001.yaml rename to muse/lifecycle/quality/humanization/rules/density/d001.yaml diff --git a/humanization/rules/density/d002.yaml b/muse/lifecycle/quality/humanization/rules/density/d002.yaml similarity index 100% rename from humanization/rules/density/d002.yaml rename to muse/lifecycle/quality/humanization/rules/density/d002.yaml diff --git a/humanization/rules/density/d003.yaml b/muse/lifecycle/quality/humanization/rules/density/d003.yaml similarity index 100% rename from humanization/rules/density/d003.yaml rename to muse/lifecycle/quality/humanization/rules/density/d003.yaml diff --git a/humanization/rules/density/d004.yaml b/muse/lifecycle/quality/humanization/rules/density/d004.yaml similarity index 100% rename from humanization/rules/density/d004.yaml rename to muse/lifecycle/quality/humanization/rules/density/d004.yaml diff --git a/humanization/rules/density/d005.yaml b/muse/lifecycle/quality/humanization/rules/density/d005.yaml similarity index 100% rename from humanization/rules/density/d005.yaml rename to muse/lifecycle/quality/humanization/rules/density/d005.yaml diff --git a/humanization/rules/density/d006.yaml b/muse/lifecycle/quality/humanization/rules/density/d006.yaml similarity index 100% rename from humanization/rules/density/d006.yaml rename to muse/lifecycle/quality/humanization/rules/density/d006.yaml diff --git a/humanization/rules/lexical/l001.yaml b/muse/lifecycle/quality/humanization/rules/lexical/l001.yaml similarity index 100% rename from humanization/rules/lexical/l001.yaml rename to muse/lifecycle/quality/humanization/rules/lexical/l001.yaml diff --git a/humanization/rules/lexical/l002.yaml b/muse/lifecycle/quality/humanization/rules/lexical/l002.yaml similarity index 100% rename from humanization/rules/lexical/l002.yaml rename to muse/lifecycle/quality/humanization/rules/lexical/l002.yaml diff --git a/humanization/rules/lexical/l003.yaml b/muse/lifecycle/quality/humanization/rules/lexical/l003.yaml similarity index 100% rename from humanization/rules/lexical/l003.yaml rename to muse/lifecycle/quality/humanization/rules/lexical/l003.yaml diff --git a/humanization/rules/lexical/l004.yaml b/muse/lifecycle/quality/humanization/rules/lexical/l004.yaml similarity index 100% rename from humanization/rules/lexical/l004.yaml rename to muse/lifecycle/quality/humanization/rules/lexical/l004.yaml diff --git a/humanization/rules/lexical/l005.yaml b/muse/lifecycle/quality/humanization/rules/lexical/l005.yaml similarity index 100% rename from humanization/rules/lexical/l005.yaml rename to muse/lifecycle/quality/humanization/rules/lexical/l005.yaml diff --git a/humanization/rules/lexical/l006.yaml b/muse/lifecycle/quality/humanization/rules/lexical/l006.yaml similarity index 100% rename from humanization/rules/lexical/l006.yaml rename to muse/lifecycle/quality/humanization/rules/lexical/l006.yaml diff --git a/humanization/rules/mechanical/m001.yaml b/muse/lifecycle/quality/humanization/rules/mechanical/m001.yaml similarity index 100% rename from humanization/rules/mechanical/m001.yaml rename to muse/lifecycle/quality/humanization/rules/mechanical/m001.yaml diff --git a/humanization/rules/mechanical/m002.yaml b/muse/lifecycle/quality/humanization/rules/mechanical/m002.yaml similarity index 100% rename from humanization/rules/mechanical/m002.yaml rename to muse/lifecycle/quality/humanization/rules/mechanical/m002.yaml diff --git a/humanization/rules/mechanical/m003.yaml b/muse/lifecycle/quality/humanization/rules/mechanical/m003.yaml similarity index 100% rename from humanization/rules/mechanical/m003.yaml rename to muse/lifecycle/quality/humanization/rules/mechanical/m003.yaml diff --git a/humanization/rules/mechanical/m004.yaml b/muse/lifecycle/quality/humanization/rules/mechanical/m004.yaml similarity index 100% rename from humanization/rules/mechanical/m004.yaml rename to muse/lifecycle/quality/humanization/rules/mechanical/m004.yaml diff --git a/humanization/rules/semantic/sem001.yaml b/muse/lifecycle/quality/humanization/rules/semantic/sem001.yaml similarity index 100% rename from humanization/rules/semantic/sem001.yaml rename to muse/lifecycle/quality/humanization/rules/semantic/sem001.yaml diff --git a/humanization/rules/semantic/sem002.yaml b/muse/lifecycle/quality/humanization/rules/semantic/sem002.yaml similarity index 100% rename from humanization/rules/semantic/sem002.yaml rename to muse/lifecycle/quality/humanization/rules/semantic/sem002.yaml diff --git a/humanization/rules/semantic/sem003.yaml b/muse/lifecycle/quality/humanization/rules/semantic/sem003.yaml similarity index 100% rename from humanization/rules/semantic/sem003.yaml rename to muse/lifecycle/quality/humanization/rules/semantic/sem003.yaml diff --git a/humanization/rules/structural/s001.yaml b/muse/lifecycle/quality/humanization/rules/structural/s001.yaml similarity index 100% rename from humanization/rules/structural/s001.yaml rename to muse/lifecycle/quality/humanization/rules/structural/s001.yaml diff --git a/humanization/rules/structural/s002.yaml b/muse/lifecycle/quality/humanization/rules/structural/s002.yaml similarity index 100% rename from humanization/rules/structural/s002.yaml rename to muse/lifecycle/quality/humanization/rules/structural/s002.yaml diff --git a/humanization/rules/structural/s003.yaml b/muse/lifecycle/quality/humanization/rules/structural/s003.yaml similarity index 100% rename from humanization/rules/structural/s003.yaml rename to muse/lifecycle/quality/humanization/rules/structural/s003.yaml diff --git a/humanization/rules/structural/s004.yaml b/muse/lifecycle/quality/humanization/rules/structural/s004.yaml similarity index 100% rename from humanization/rules/structural/s004.yaml rename to muse/lifecycle/quality/humanization/rules/structural/s004.yaml diff --git a/humanization/rules/structural/s005.yaml b/muse/lifecycle/quality/humanization/rules/structural/s005.yaml similarity index 100% rename from humanization/rules/structural/s005.yaml rename to muse/lifecycle/quality/humanization/rules/structural/s005.yaml diff --git a/humanization/rules/structural/s006.yaml b/muse/lifecycle/quality/humanization/rules/structural/s006.yaml similarity index 100% rename from humanization/rules/structural/s006.yaml rename to muse/lifecycle/quality/humanization/rules/structural/s006.yaml diff --git a/humanization/rules/structural/s007.yaml b/muse/lifecycle/quality/humanization/rules/structural/s007.yaml similarity index 100% rename from humanization/rules/structural/s007.yaml rename to muse/lifecycle/quality/humanization/rules/structural/s007.yaml diff --git a/humanization/samples/boundary.yaml b/muse/lifecycle/quality/humanization/samples/boundary.yaml similarity index 100% rename from humanization/samples/boundary.yaml rename to muse/lifecycle/quality/humanization/samples/boundary.yaml diff --git a/humanization/samples/regression.yaml b/muse/lifecycle/quality/humanization/samples/regression.yaml similarity index 100% rename from humanization/samples/regression.yaml rename to muse/lifecycle/quality/humanization/samples/regression.yaml diff --git a/humanization/samples/sf.yaml b/muse/lifecycle/quality/humanization/samples/sf.yaml similarity index 100% rename from humanization/samples/sf.yaml rename to muse/lifecycle/quality/humanization/samples/sf.yaml diff --git a/humanization/samples/snf.yaml b/muse/lifecycle/quality/humanization/samples/snf.yaml similarity index 100% rename from humanization/samples/snf.yaml rename to muse/lifecycle/quality/humanization/samples/snf.yaml diff --git a/.agent/skills/capture-ai-flavor-cases/SKILL.md b/muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/SKILL.md similarity index 86% rename from .agent/skills/capture-ai-flavor-cases/SKILL.md rename to muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/SKILL.md index d838637..1a2adb2 100644 --- a/.agent/skills/capture-ai-flavor-cases/SKILL.md +++ b/muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/SKILL.md @@ -8,7 +8,7 @@ disable-model-invocation: true ## 在五技能接力链中的位置 -本 Skill 是技能 5「挖掘」的**采集**入口(链路登记见 [`meta/chains/README.md`](../../../meta/chains/README.md) 的 AI 味接力段): +本 Skill 是技能 5「挖掘」的**采集**入口(链路登记见 [`chains/README.md`](../../../../flow/chains/README.md) 的 AI 味接力段): ```text 创作/已有作品 → 案例卡采集(本 Skill)→ 来源重验证(本 Skill) @@ -46,32 +46,32 @@ disable-model-invocation: true ```bash # 既有作品反向扫描;research_only 是默认安全值,输出 hash-only 卡 -.venv/bin/python .agent/skills/capture-ai-flavor-cases/scripts/capture_cases.py scan \ +.venv/bin/python muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/scripts/capture_cases.py scan \ /path/to/work.txt --work-ref work-7 --output /tmp/ai-flavor-cases.yaml # 命令结束时自动写入 muse-example;同时生成 .inventory.json/.revalidation.json 回执 # 批量回填并固化可复核清单;只写来源哈希、位置和观察,不复制第三方正文 -.venv/bin/python .agent/skills/capture-ai-flavor-cases/scripts/capture_cases.py inventory \ +.venv/bin/python muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/scripts/capture_cases.py inventory \ /path/to/works --source-root-ref 小说清单 --output /path/to/backfill-inventory.json \ --generated-on 2026-08-13 # 8 本作品的卡与逐卡重验证在同一检测运行中自动入库 # 创作反馈快速入卡(正文只在本次受控输入中读取) -.venv/bin/python .agent/skills/capture-ai-flavor-cases/scripts/capture_cases.py feedback \ +.venv/bin/python muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/scripts/capture_cases.py feedback \ --text-file /tmp/candidate.txt --work-ref work-12 --run-ref run-abc \ --issue "段尾抽象升华没有功能" --output /tmp/feedback-card.yaml # 创作反馈也会自动入库,保留 run_ref 绑定 # 明确只做离线构造(不会写库) -.venv/bin/python .agent/skills/capture-ai-flavor-cases/scripts/capture_cases.py inventory \ +.venv/bin/python muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/scripts/capture_cases.py inventory \ /path/to/works --output /tmp/inventory.json --offline # 对卡片做结构与来源门禁 -.venv/bin/python .agent/skills/capture-ai-flavor-cases/scripts/capture_cases.py validate \ +.venv/bin/python muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/scripts/capture_cases.py validate \ /tmp/ai-flavor-cases.yaml # 在确认/投影/规则使用前手工重验证来源;默认自动追加数据库回执。 -.venv/bin/python .agent/skills/capture-ai-flavor-cases/scripts/capture_cases.py revalidate \ +.venv/bin/python muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/scripts/capture_cases.py revalidate \ /path/to/ai-flavor-cases.yaml --source-root /path/to/source-root \ --checked-on 2026-08-14 --output /tmp/ai-flavor-revalidation.json # 仅需离线回执时显式加 --offline @@ -91,7 +91,7 @@ disable-model-invocation: true 首版回填清单与候选规则种子见 [`references/fixtures/`](references/fixtures/);其中既有作品只保留 hash/位置,不能直接确认。 `inventory`/`revalidate` 的 `--output` 导出是可复核的恢复证据;正式内容在 `muse-example` 的 `example_ai_flavor_case`、`example_ai_flavor_revalidation_batch`、`example_ai_flavor_revalidation` 三张表。 -`dashboard/server.py` 的 `/ai-flavor` 默认查这三张表,数据库不可用时读它自己的 `dashboard/fixtures/` 离线回退(导出件由人放入,看板不读本 Skill 目录);页面不会因打开而重新读取原文。 +`muse/authority/studio/read/server.py` 的 `/ai-flavor` 默认查这三张表,数据库不可用时读它自己的 `muse/authority/studio/read/fixtures/` 离线回退(导出件由人放入,看板不读本 Skill 目录);页面不会因打开而重新读取原文。 状态语义:案例卡 `shadow` 只供复核,`canonical` 仅表示获授权且完成评审,`rejected`/`archived` 不进入生成上下文;重验证 `verified` 才能确认、投影样例或消费规则,`stale`(全文哈希变化)、`unavailable`(来源不可得)和 `card_mismatch`(锚点变化)都使当前卡在这些动作上失效,但历史回执保留。 diff --git a/.agent/skills/capture-ai-flavor-cases/references/case-card-contract.md b/muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/references/case-card-contract.md similarity index 100% rename from .agent/skills/capture-ai-flavor-cases/references/case-card-contract.md rename to muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/references/case-card-contract.md diff --git a/.agent/skills/capture-ai-flavor-cases/references/fixtures/README.md b/muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/references/fixtures/README.md similarity index 67% rename from .agent/skills/capture-ai-flavor-cases/references/fixtures/README.md rename to muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/references/fixtures/README.md index 0a67f1f..b18b32a 100644 --- a/.agent/skills/capture-ai-flavor-cases/references/fixtures/README.md +++ b/muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/references/fixtures/README.md @@ -6,8 +6,8 @@ - `canonical-samples.yaml`:公版/合成短片段的已确认样例,用于验证卡→样例投影和反例门。 - `rule-candidates.yaml`:由两类以上来源、同时含正反证据的候选规则;状态固定为 `candidate`,不能直接加载为生产 `active`。 -`inventory`/`revalidate` 的 JSON 导出不留在本目录:看板的离线回退夹具归 [`dashboard/fixtures/`](../../../../../dashboard/fixtures/) 所有,看板不读本 Skill 目录。 +`inventory`/`revalidate` 的 JSON 导出不留在本目录:看板的离线回退夹具归 [`muse/authority/studio/read/fixtures/`](../../../../../../../authority/studio/read/fixtures/) 所有,看板不读本 Skill 目录。 -页面入口:启动 `dashboard/server.py` 后访问 `/ai-flavor`。页面默认只读展示 PostgreSQL 正式表;数据库不可用时才显示离线回退。确认、样例投影和规则消费必须携带 `verified` 回执。 +页面入口:启动 `muse/authority/studio/read/server.py` 后访问 `/ai-flavor`。页面默认只读展示 PostgreSQL 正式表;数据库不可用时才显示离线回退。确认、样例投影和规则消费必须携带 `verified` 回执。 样例标签含义:`sf` = 当前评审认为应修,`snf` = 表面相似但有功能不应修,`boundary` = 需上下文裁决,`regression` = 错误修复回归。 diff --git a/.agent/skills/capture-ai-flavor-cases/references/fixtures/backfill-hash-only.yaml b/muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/references/fixtures/backfill-hash-only.yaml similarity index 100% rename from .agent/skills/capture-ai-flavor-cases/references/fixtures/backfill-hash-only.yaml rename to muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/references/fixtures/backfill-hash-only.yaml diff --git a/.agent/skills/capture-ai-flavor-cases/references/fixtures/canonical-samples.yaml b/muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/references/fixtures/canonical-samples.yaml similarity index 100% rename from .agent/skills/capture-ai-flavor-cases/references/fixtures/canonical-samples.yaml rename to muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/references/fixtures/canonical-samples.yaml diff --git a/.agent/skills/capture-ai-flavor-cases/references/fixtures/rule-candidates.yaml b/muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/references/fixtures/rule-candidates.yaml similarity index 100% rename from .agent/skills/capture-ai-flavor-cases/references/fixtures/rule-candidates.yaml rename to muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/references/fixtures/rule-candidates.yaml diff --git a/.agent/skills/capture-ai-flavor-cases/scripts/capture_cases.py b/muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/scripts/capture_cases.py similarity index 100% rename from .agent/skills/capture-ai-flavor-cases/scripts/capture_cases.py rename to muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/scripts/capture_cases.py diff --git a/.agent/skills/capture-ai-flavor-cases/scripts/persist_cases.py b/muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/scripts/persist_cases.py similarity index 100% rename from .agent/skills/capture-ai-flavor-cases/scripts/persist_cases.py rename to muse/lifecycle/quality/humanization/skills/capture-ai-flavor-cases/scripts/persist_cases.py diff --git a/.agent/skills/diagnose-ai-flavor/SKILL.md b/muse/lifecycle/quality/humanization/skills/diagnose-ai-flavor/SKILL.md similarity index 100% rename from .agent/skills/diagnose-ai-flavor/SKILL.md rename to muse/lifecycle/quality/humanization/skills/diagnose-ai-flavor/SKILL.md diff --git a/.agent/skills/diagnose-ai-flavor/scripts/diagnose_ai_flavor.py b/muse/lifecycle/quality/humanization/skills/diagnose-ai-flavor/scripts/diagnose_ai_flavor.py similarity index 100% rename from .agent/skills/diagnose-ai-flavor/scripts/diagnose_ai_flavor.py rename to muse/lifecycle/quality/humanization/skills/diagnose-ai-flavor/scripts/diagnose_ai_flavor.py diff --git a/.agent/skills/establish-voice-baseline/SKILL.md b/muse/lifecycle/quality/humanization/skills/establish-voice-baseline/SKILL.md similarity index 100% rename from .agent/skills/establish-voice-baseline/SKILL.md rename to muse/lifecycle/quality/humanization/skills/establish-voice-baseline/SKILL.md diff --git a/.agent/skills/establish-voice-baseline/scripts/establish_voice_baseline.py b/muse/lifecycle/quality/humanization/skills/establish-voice-baseline/scripts/establish_voice_baseline.py similarity index 100% rename from .agent/skills/establish-voice-baseline/scripts/establish_voice_baseline.py rename to muse/lifecycle/quality/humanization/skills/establish-voice-baseline/scripts/establish_voice_baseline.py diff --git a/.agent/skills/prevent-ai-flavor/SKILL.md b/muse/lifecycle/quality/humanization/skills/prevent-ai-flavor/SKILL.md similarity index 100% rename from .agent/skills/prevent-ai-flavor/SKILL.md rename to muse/lifecycle/quality/humanization/skills/prevent-ai-flavor/SKILL.md diff --git a/.agent/skills/prevent-ai-flavor/scripts/prevent_ai_flavor.py b/muse/lifecycle/quality/humanization/skills/prevent-ai-flavor/scripts/prevent_ai_flavor.py similarity index 100% rename from .agent/skills/prevent-ai-flavor/scripts/prevent_ai_flavor.py rename to muse/lifecycle/quality/humanization/skills/prevent-ai-flavor/scripts/prevent_ai_flavor.py diff --git a/.agent/skills/promote-ai-flavor-rule/SKILL.md b/muse/lifecycle/quality/humanization/skills/promote-ai-flavor-rule/SKILL.md similarity index 83% rename from .agent/skills/promote-ai-flavor-rule/SKILL.md rename to muse/lifecycle/quality/humanization/skills/promote-ai-flavor-rule/SKILL.md index a9bedda..d94c8f6 100644 --- a/.agent/skills/promote-ai-flavor-rule/SKILL.md +++ b/muse/lifecycle/quality/humanization/skills/promote-ai-flavor-rule/SKILL.md @@ -8,7 +8,7 @@ disable-model-invocation: true ## 在五技能接力链中的位置 -采集归 `capture-ai-flavor-cases`,本 Skill 接在它后面(链路登记见 [`meta/chains/README.md`](../../../meta/chains/README.md) 的 AI 味接力段): +采集归 `capture-ai-flavor-cases`,本 Skill 接在它后面(链路登记见 [`chains/README.md`](../../../../flow/chains/README.md) 的 AI 味接力段): ```text 案例卡采集(capture-ai-flavor-cases) @@ -26,37 +26,37 @@ disable-model-invocation: true ```bash # Shadow 卡人工标注(默认写回数据库当前投影) -.venv/bin/python .agent/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py annotate \ +.venv/bin/python muse/lifecycle/quality/humanization/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py annotate \ --cards /tmp/cards.yaml --card-id case-... --label sf --carrier narration \ --reviewer qingse --note "当前上下文无叙事功能" --output /tmp/annotated.json # 来源已 verified 后确认 canonical;数据库再次检查 verified 回执 -.venv/bin/python .agent/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py confirm \ +.venv/bin/python muse/lifecycle/quality/humanization/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py confirm \ --cards /tmp/cards.yaml --card-id case-... --verification /tmp/revalidation.json \ --reviewer qingse --note "作者确认" --output /tmp/canonical.json # canonical 卡投影为四类样例之一 -.venv/bin/python .agent/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py project-sample \ +.venv/bin/python muse/lifecycle/quality/humanization/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py project-sample \ --cards /tmp/canonical.yaml --card-id case-... --verification /tmp/revalidation.json \ --output /tmp/sample.yaml # 归纳规则候选;命令永远只产 candidate -.venv/bin/python .agent/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py propose-rule \ +.venv/bin/python muse/lifecycle/quality/humanization/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py propose-rule \ --cards /tmp/cards-a.yaml /tmp/cards-b.yaml \ --rule-id candidate-lexical-001 --name "空洞元话语" \ --verification /tmp/ai-flavor-revalidation.json --output /tmp/rule-candidate.yaml # 合同回放;带 holdout 才有资格进入激活门 -.venv/bin/python .agent/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py evaluate-rule \ +.venv/bin/python muse/lifecycle/quality/humanization/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py evaluate-rule \ --rule humanization/rules/structural/s002.yaml --samples /tmp/projected-samples.yaml \ --cards /tmp/canonical-cards.yaml --verification /tmp/revalidation.json \ --holdout /tmp/holdout.json --output /tmp/rule-evaluation.json # 人工审批激活 / 降级 -.venv/bin/python .agent/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py activate-rule \ +.venv/bin/python muse/lifecycle/quality/humanization/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py activate-rule \ --rule /tmp/rule-candidate.yaml --contract-report /tmp/rule-evaluation.json \ --holdout-report /tmp/rule-evaluation.json --approver qingse --output /tmp/rule-active.yaml -.venv/bin/python .agent/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py deprecate-rule \ +.venv/bin/python muse/lifecycle/quality/humanization/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py deprecate-rule \ --rule humanization/rules/lexical/l007.yaml --approver qingse --reason "换版后失效" \ --output /tmp/rule-deprecated.yaml ``` diff --git a/.agent/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py b/muse/lifecycle/quality/humanization/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py similarity index 100% rename from .agent/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py rename to muse/lifecycle/quality/humanization/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py diff --git a/.agent/skills/revise-ai-flavor/SKILL.md b/muse/lifecycle/quality/humanization/skills/revise-ai-flavor/SKILL.md similarity index 100% rename from .agent/skills/revise-ai-flavor/SKILL.md rename to muse/lifecycle/quality/humanization/skills/revise-ai-flavor/SKILL.md diff --git a/.agent/skills/revise-ai-flavor/scripts/revise_ai_flavor.py b/muse/lifecycle/quality/humanization/skills/revise-ai-flavor/scripts/revise_ai_flavor.py similarity index 100% rename from .agent/skills/revise-ai-flavor/scripts/revise_ai_flavor.py rename to muse/lifecycle/quality/humanization/skills/revise-ai-flavor/scripts/revise_ai_flavor.py diff --git a/humanization/src/deai/__init__.py b/muse/lifecycle/quality/humanization/src/deai/__init__.py similarity index 100% rename from humanization/src/deai/__init__.py rename to muse/lifecycle/quality/humanization/src/deai/__init__.py diff --git a/humanization/src/deai/baseline.py b/muse/lifecycle/quality/humanization/src/deai/baseline.py similarity index 100% rename from humanization/src/deai/baseline.py rename to muse/lifecycle/quality/humanization/src/deai/baseline.py diff --git a/humanization/src/deai/cards.py b/muse/lifecycle/quality/humanization/src/deai/cards.py similarity index 100% rename from humanization/src/deai/cards.py rename to muse/lifecycle/quality/humanization/src/deai/cards.py diff --git a/humanization/src/deai/carriers.py b/muse/lifecycle/quality/humanization/src/deai/carriers.py similarity index 100% rename from humanization/src/deai/carriers.py rename to muse/lifecycle/quality/humanization/src/deai/carriers.py diff --git a/humanization/src/deai/diagnose.py b/muse/lifecycle/quality/humanization/src/deai/diagnose.py similarity index 100% rename from humanization/src/deai/diagnose.py rename to muse/lifecycle/quality/humanization/src/deai/diagnose.py diff --git a/humanization/src/deai/evaluation.py b/muse/lifecycle/quality/humanization/src/deai/evaluation.py similarity index 100% rename from humanization/src/deai/evaluation.py rename to muse/lifecycle/quality/humanization/src/deai/evaluation.py diff --git a/humanization/src/deai/gates.py b/muse/lifecycle/quality/humanization/src/deai/gates.py similarity index 100% rename from humanization/src/deai/gates.py rename to muse/lifecycle/quality/humanization/src/deai/gates.py diff --git a/humanization/src/deai/load.py b/muse/lifecycle/quality/humanization/src/deai/load.py similarity index 100% rename from humanization/src/deai/load.py rename to muse/lifecycle/quality/humanization/src/deai/load.py diff --git a/humanization/src/deai/load_db.py b/muse/lifecycle/quality/humanization/src/deai/load_db.py similarity index 100% rename from humanization/src/deai/load_db.py rename to muse/lifecycle/quality/humanization/src/deai/load_db.py diff --git a/humanization/src/deai/pairwise.py b/muse/lifecycle/quality/humanization/src/deai/pairwise.py similarity index 100% rename from humanization/src/deai/pairwise.py rename to muse/lifecycle/quality/humanization/src/deai/pairwise.py diff --git a/humanization/src/deai/patch.py b/muse/lifecycle/quality/humanization/src/deai/patch.py similarity index 100% rename from humanization/src/deai/patch.py rename to muse/lifecycle/quality/humanization/src/deai/patch.py diff --git a/humanization/src/deai/pipeline.py b/muse/lifecycle/quality/humanization/src/deai/pipeline.py similarity index 100% rename from humanization/src/deai/pipeline.py rename to muse/lifecycle/quality/humanization/src/deai/pipeline.py diff --git a/humanization/src/deai/report.py b/muse/lifecycle/quality/humanization/src/deai/report.py similarity index 100% rename from humanization/src/deai/report.py rename to muse/lifecycle/quality/humanization/src/deai/report.py diff --git a/humanization/src/deai/schemas.py b/muse/lifecycle/quality/humanization/src/deai/schemas.py similarity index 100% rename from humanization/src/deai/schemas.py rename to muse/lifecycle/quality/humanization/src/deai/schemas.py diff --git a/humanization/tests/__init__.py b/muse/lifecycle/quality/humanization/tests/__init__.py similarity index 100% rename from humanization/tests/__init__.py rename to muse/lifecycle/quality/humanization/tests/__init__.py diff --git a/humanization/tests/test_contracts.py b/muse/lifecycle/quality/humanization/tests/test_contracts.py similarity index 100% rename from humanization/tests/test_contracts.py rename to muse/lifecycle/quality/humanization/tests/test_contracts.py diff --git a/humanization/tests/test_framework_coverage.py b/muse/lifecycle/quality/humanization/tests/test_framework_coverage.py similarity index 86% rename from humanization/tests/test_framework_coverage.py rename to muse/lifecycle/quality/humanization/tests/test_framework_coverage.py index 1fd58c9..7d6d22f 100644 --- a/humanization/tests/test_framework_coverage.py +++ b/muse/lifecycle/quality/humanization/tests/test_framework_coverage.py @@ -7,7 +7,12 @@ import unittest import yaml -ROOT = pathlib.Path(__file__).resolve().parents[1] +ROOT = pathlib.Path(__file__).resolve().parent.parent +PROJECT_ROOT = next( + parent + for parent in (ROOT, *ROOT.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) MATRIX = ROOT / "research/20-project-skill-coverage.yaml" @@ -38,7 +43,7 @@ class FrameworkCoverageTest(unittest.TestCase): ) for item in capabilities: implementation_ref = item["implementation"] - implementation = ROOT.parent / implementation_ref if implementation_ref.startswith((".", "humanization/")) else ROOT / implementation_ref + implementation = PROJECT_ROOT / implementation_ref self.assertTrue(implementation.exists(), f"{item['id']}: {implementation}") self.assertIn(item["status"], {"implemented", "partial", "pending"}) diff --git a/humanization/tests/test_humanization_v2.py b/muse/lifecycle/quality/humanization/tests/test_humanization_v2.py similarity index 98% rename from humanization/tests/test_humanization_v2.py rename to muse/lifecycle/quality/humanization/tests/test_humanization_v2.py index e210bcd..c25028e 100644 --- a/humanization/tests/test_humanization_v2.py +++ b/muse/lifecycle/quality/humanization/tests/test_humanization_v2.py @@ -29,11 +29,11 @@ def load_script(name: str, path: pathlib.Path): MINE = load_script( "mine_ai_flavor_v2", - ROOT.parent / ".agent/skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py", + ROOT / "skills/promote-ai-flavor-rule/scripts/mine_ai_flavor.py", ) CAPTURE = load_script( "capture_cases_v2", - ROOT.parent / ".agent/skills/capture-ai-flavor-cases/scripts/capture_cases.py", + ROOT / "skills/capture-ai-flavor-cases/scripts/capture_cases.py", ) diff --git a/humanization/tests/test_load_db.py b/muse/lifecycle/quality/humanization/tests/test_load_db.py similarity index 100% rename from humanization/tests/test_load_db.py rename to muse/lifecycle/quality/humanization/tests/test_load_db.py diff --git a/humanization/tests/test_load_db_pg_smoke.py b/muse/lifecycle/quality/humanization/tests/test_load_db_pg_smoke.py similarity index 100% rename from humanization/tests/test_load_db_pg_smoke.py rename to muse/lifecycle/quality/humanization/tests/test_load_db_pg_smoke.py diff --git a/humanization/tests/test_seed_rules_db.py b/muse/lifecycle/quality/humanization/tests/test_seed_rules_db.py similarity index 100% rename from humanization/tests/test_seed_rules_db.py rename to muse/lifecycle/quality/humanization/tests/test_seed_rules_db.py diff --git a/humanization/tools/seed_rules_db.py b/muse/lifecycle/quality/humanization/tools/seed_rules_db.py similarity index 100% rename from humanization/tools/seed_rules_db.py rename to muse/lifecycle/quality/humanization/tools/seed_rules_db.py diff --git a/.agent/skills/optimize-content-quality/SKILL.md b/muse/lifecycle/quality/skills/judge/optimize-content-quality/SKILL.md similarity index 94% rename from .agent/skills/optimize-content-quality/SKILL.md rename to muse/lifecycle/quality/skills/judge/optimize-content-quality/SKILL.md index bea5f5c..257624a 100644 --- a/.agent/skills/optimize-content-quality/SKILL.md +++ b/muse/lifecycle/quality/skills/judge/optimize-content-quality/SKILL.md @@ -1,6 +1,7 @@ --- name: optimize-content-quality description: 根据 score-content-quality 的独立评分,锁定最低质量维度并归因到 prompt、上下文或设定层,只出单变量改进建议。候选稳定不达标且需要定位改进来源时使用;不执行重生成、不改 rubric、不自行提交代码。 +disable-model-invocation: true --- # 质量归因建议 @@ -40,7 +41,7 @@ description: 根据 score-content-quality 的独立评分,锁定最低质量 - 只读:评分报告、可选的 prompt/上下文/设定摘要。 - 不写库、不改正文、不调用模型网关、不提交 Git。 -- 实验性「评→诊→改→产→止」五轮收敛环的历史 runbook 见 [`docs/2026-08-20-质量收敛环运行手册.md`](../../../docs/2026-08-20-质量收敛环运行手册.md);该环不是本 Skill 的合同,主会话若仍要跑须单独授权。 +- 实验性「评→诊→改→产→止」五轮收敛环的历史 runbook 见 [`docs/2026-08-20-质量收敛环运行手册.md`](../../../../../../docs/2026-08-20-质量收敛环运行手册.md);该环不是本 Skill 的合同,主会话若仍要跑须单独授权。 ## 红线 diff --git a/.agent/skills/score-content-quality/SKILL.md b/muse/lifecycle/quality/skills/judge/score-content-quality/SKILL.md similarity index 100% rename from .agent/skills/score-content-quality/SKILL.md rename to muse/lifecycle/quality/skills/judge/score-content-quality/SKILL.md diff --git a/.agent/skills/score-content-quality/scripts/dispatch_judge_bridge.py b/muse/lifecycle/quality/skills/judge/score-content-quality/scripts/dispatch_judge_bridge.py similarity index 93% rename from .agent/skills/score-content-quality/scripts/dispatch_judge_bridge.py rename to muse/lifecycle/quality/skills/judge/score-content-quality/scripts/dispatch_judge_bridge.py index df9168a..679ff5b 100644 --- a/.agent/skills/score-content-quality/scripts/dispatch_judge_bridge.py +++ b/muse/lifecycle/quality/skills/judge/score-content-quality/scripts/dispatch_judge_bridge.py @@ -20,13 +20,20 @@ from pathlib import Path from typing import Any, Callable, Mapping SCRIPT_DIR = Path(__file__).resolve().parent -DISPATCH_SCRIPTS = SCRIPT_DIR.parents[1] / "dispatch-agent-task" / "scripts" -if str(DISPATCH_SCRIPTS) not in sys.path: - sys.path.insert(0, str(DISPATCH_SCRIPTS)) +PROJECT_ROOT = next( + parent + for parent in (SCRIPT_DIR, *SCRIPT_DIR.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +DISPATCH_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "dispatch" / "skills" / "dispatch-agent-task" / "scripts" +READ_TOOLS_DIR = PROJECT_ROOT / "muse" / "authority" / "tools" / "read" +for _path in (PROJECT_ROOT, DISPATCH_SCRIPTS, READ_TOOLS_DIR): + if str(_path) not in sys.path: + sys.path.insert(0, str(_path)) from run_writer_blind_judge import BlindJudgeContractError, canonical_sha256 # noqa: E402 from dispatch_agent_task import run_dispatch # noqa: E402 -from pi_runner import ExecutionPolicy # noqa: E402 +from framework.adapters.pi.runner import ExecutionPolicy # noqa: E402 from read_tools import TOOL_REGISTRY # noqa: E402 MODE_EXPERIMENT = "experiment" diff --git a/.agent/skills/score-content-quality/scripts/fine_outline_rubric.py b/muse/lifecycle/quality/skills/judge/score-content-quality/scripts/fine_outline_rubric.py similarity index 100% rename from .agent/skills/score-content-quality/scripts/fine_outline_rubric.py rename to muse/lifecycle/quality/skills/judge/score-content-quality/scripts/fine_outline_rubric.py diff --git a/.agent/skills/score-content-quality/scripts/judge_via_dispatch.py b/muse/lifecycle/quality/skills/judge/score-content-quality/scripts/judge_via_dispatch.py similarity index 97% rename from .agent/skills/score-content-quality/scripts/judge_via_dispatch.py rename to muse/lifecycle/quality/skills/judge/score-content-quality/scripts/judge_via_dispatch.py index 6af95a7..73f8272 100644 --- a/.agent/skills/score-content-quality/scripts/judge_via_dispatch.py +++ b/muse/lifecycle/quality/skills/judge/score-content-quality/scripts/judge_via_dispatch.py @@ -6,7 +6,7 @@ example_quality_result(judge_kind=scoring,枚举以库级 CHECK 约束为准)。 真实模型调用必须显式授权并显式给出 provider/model: -.venv/bin/python .agent/skills/score-content-quality/scripts/judge_via_dispatch.py \ +.venv/bin/python muse/lifecycle/quality/skills/judge/score-content-quality/scripts/judge_via_dispatch.py \ 12 3 --candidate-ids 123,164 --provider catproxy-anthropic --model claude-opus-5 --thinking medium """ from __future__ import annotations @@ -22,7 +22,7 @@ from pathlib import Path SCRIPT_DIR = Path(__file__).resolve().parent REPO_ROOT = SCRIPT_DIR.parents[3] for _path in (SCRIPT_DIR, - REPO_ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts"): + REPO_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts"): if str(_path) not in sys.path: sys.path.insert(0, str(_path)) diff --git a/.agent/skills/score-content-quality/scripts/run_writer_blind_judge.py b/muse/lifecycle/quality/skills/judge/score-content-quality/scripts/run_writer_blind_judge.py similarity index 100% rename from .agent/skills/score-content-quality/scripts/run_writer_blind_judge.py rename to muse/lifecycle/quality/skills/judge/score-content-quality/scripts/run_writer_blind_judge.py diff --git a/.agent/skills/score-content-quality/scripts/writer_rubric.py b/muse/lifecycle/quality/skills/judge/score-content-quality/scripts/writer_rubric.py similarity index 100% rename from .agent/skills/score-content-quality/scripts/writer_rubric.py rename to muse/lifecycle/quality/skills/judge/score-content-quality/scripts/writer_rubric.py diff --git a/.agent/skills/adjudicate-quality-gate/SKILL.md b/muse/lifecycle/quality/skills/mechanical/adjudicate-quality-gate/SKILL.md similarity index 100% rename from .agent/skills/adjudicate-quality-gate/SKILL.md rename to muse/lifecycle/quality/skills/mechanical/adjudicate-quality-gate/SKILL.md diff --git a/.agent/skills/adjudicate-quality-gate/scripts/gate_input_builder.py b/muse/lifecycle/quality/skills/mechanical/adjudicate-quality-gate/scripts/gate_input_builder.py similarity index 99% rename from .agent/skills/adjudicate-quality-gate/scripts/gate_input_builder.py rename to muse/lifecycle/quality/skills/mechanical/adjudicate-quality-gate/scripts/gate_input_builder.py index a928987..a979e68 100644 --- a/.agent/skills/adjudicate-quality-gate/scripts/gate_input_builder.py +++ b/muse/lifecycle/quality/skills/mechanical/adjudicate-quality-gate/scripts/gate_input_builder.py @@ -14,7 +14,12 @@ from pathlib import Path from typing import Any # 达标口径(rubric)归 score-content-quality,本 Skill 只做裁决,不复制维度定义。 -RUBRIC_DIR = Path(__file__).resolve().parents[2] / "score-content-quality" / "scripts" +PROJECT_ROOT = next( + parent + for parent in (Path(__file__).resolve().parent, *Path(__file__).resolve().parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +RUBRIC_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "judge" / "score-content-quality" / "scripts" if str(RUBRIC_DIR) not in sys.path: sys.path.insert(0, str(RUBRIC_DIR)) diff --git a/.agent/skills/adjudicate-quality-gate/scripts/writer_gate.py b/muse/lifecycle/quality/skills/mechanical/adjudicate-quality-gate/scripts/writer_gate.py similarity index 100% rename from .agent/skills/adjudicate-quality-gate/scripts/writer_gate.py rename to muse/lifecycle/quality/skills/mechanical/adjudicate-quality-gate/scripts/writer_gate.py diff --git a/.agent/skills/evaluate-frozen-replay/SKILL.md b/muse/lifecycle/quality/skills/replay/evaluate-frozen-replay/SKILL.md similarity index 95% rename from .agent/skills/evaluate-frozen-replay/SKILL.md rename to muse/lifecycle/quality/skills/replay/evaluate-frozen-replay/SKILL.md index a52a655..9406b66 100644 --- a/.agent/skills/evaluate-frozen-replay/SKILL.md +++ b/muse/lifecycle/quality/skills/replay/evaluate-frozen-replay/SKILL.md @@ -8,7 +8,7 @@ disable-model-invocation: true 本 Skill 是**细纲侧**回放编排层,只做冻结、授权、防泄漏审计、三臂回放编排与安全报告。正文 A/B/C 回放归 `replay-writer-gate`;真实作品配置装配归 `load-replay-reference-work`;探针刷新归 `refresh-runtime-probe`;评分归 `score-content-quality`;Gate 终态归 `adjudicate-quality-gate`;角色调用归 `execute-role-task`;CAS/raw 证据归 `record-run-evidence`;候选检测归 `check-content-consistency`;冻结快照与只读装载归 `freeze-context`。依赖箭头只向下,本 Skill 不自带这些实现。 -冻结合同以 [父仓专题-03](../../../../design-docs/专题-03-AI编排上下文与质量评测实现规范.md) 为唯一 owner,Gate 裁决以 [父仓专题-04](../../../../design-docs/专题-04-生成质量门控与创作健康度设计方案.md) 为准,adapter 隔离以 [父仓专题-05](../../../../design-docs/专题-05-AI统一交互协议与外部AgentAdapter设计.md) 为准。 +冻结合同以 [父仓专题-03](../../../../../../../design-docs/专题-03-AI编排上下文与质量评测实现规范.md) 为唯一 owner,Gate 裁决以 [父仓专题-04](../../../../../../../design-docs/专题-04-生成质量门控与创作健康度设计方案.md) 为准,adapter 隔离以 [父仓专题-05](../../../../../../../design-docs/专题-05-AI统一交互协议与外部AgentAdapter设计.md) 为准。 ## 输入 diff --git a/.agent/skills/evaluate-frozen-replay/scripts/fine_outline_detector.py b/muse/lifecycle/quality/skills/replay/evaluate-frozen-replay/scripts/fine_outline_detector.py similarity index 100% rename from .agent/skills/evaluate-frozen-replay/scripts/fine_outline_detector.py rename to muse/lifecycle/quality/skills/replay/evaluate-frozen-replay/scripts/fine_outline_detector.py diff --git a/.agent/skills/evaluate-frozen-replay/scripts/run_replay.py b/muse/lifecycle/quality/skills/replay/evaluate-frozen-replay/scripts/run_replay.py similarity index 98% rename from .agent/skills/evaluate-frozen-replay/scripts/run_replay.py rename to muse/lifecycle/quality/skills/replay/evaluate-frozen-replay/scripts/run_replay.py index 823e504..b59288a 100644 --- a/.agent/skills/evaluate-frozen-replay/scripts/run_replay.py +++ b/muse/lifecycle/quality/skills/replay/evaluate-frozen-replay/scripts/run_replay.py @@ -18,11 +18,15 @@ from pathlib import Path from typing import Any, Callable, Mapping, Sequence SCRIPT_DIR = Path(__file__).resolve().parent -SKILLS_DIR = SCRIPT_DIR.parents[1] -QUALITY_GATE_DIR = SKILLS_DIR / "score-content-quality" / "scripts" -GATE_ADJUDICATION_DIR = SKILLS_DIR / "adjudicate-quality-gate" / "scripts" -SNAPSHOT_DIR = SKILLS_DIR / "freeze-context" / "scripts" -EVIDENCE_DIR = SKILLS_DIR / "record-run-evidence" / "scripts" +PROJECT_ROOT = next( + parent + for parent in (SCRIPT_DIR, *SCRIPT_DIR.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +QUALITY_GATE_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "judge" / "score-content-quality" / "scripts" +GATE_ADJUDICATION_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "mechanical" / "adjudicate-quality-gate" / "scripts" +SNAPSHOT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "freeze-context" / "scripts" +EVIDENCE_DIR = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" for _import_dir in (QUALITY_GATE_DIR, GATE_ADJUDICATION_DIR, SNAPSHOT_DIR, EVIDENCE_DIR): if str(_import_dir) not in sys.path: sys.path.insert(0, str(_import_dir)) @@ -60,8 +64,8 @@ from muse_role import ( # noqa: E402 REQUIRED_ARMS = ("outline_only", "outline_plus_cards", "outline_plus_placebo_cards") -REPO_ROOT = Path(__file__).resolve().parents[4] -SKILL_PATH = REPO_ROOT / ".agent/skills/plan-chapter/SKILL.md" +REPO_ROOT = PROJECT_ROOT +SKILL_PATH = REPO_ROOT / "muse" / "lifecycle" / "flow" / "skills" / "chapter" / "plan-chapter" / "SKILL.md" AGENTS_DIR = REPO_ROOT / ".agent" / "agents" PLANNER_PATH = AGENTS_DIR / "planner.md" ROLE_CONTRACTS = load_role_contract_catalog(REPO_ROOT) @@ -672,7 +676,7 @@ def _propose_replay_lesson(result: Mapping[str, Any]) -> dict[str, Any] | None: run_id = str(result.get("runId") or "") if not run_id or run_id == "unassigned": return None - evidence = SKILLS_DIR / "record-run-evidence" / "scripts" + evidence = EVIDENCE_DIR if str(evidence) not in sys.path: sys.path.insert(0, str(evidence)) from lesson_registry import propose_lesson_dedup # noqa: WPS433 diff --git a/.agent/skills/evaluate-frozen-replay/scripts/write_report.py b/muse/lifecycle/quality/skills/replay/evaluate-frozen-replay/scripts/write_report.py similarity index 100% rename from .agent/skills/evaluate-frozen-replay/scripts/write_report.py rename to muse/lifecycle/quality/skills/replay/evaluate-frozen-replay/scripts/write_report.py diff --git a/.agent/skills/load-replay-reference-work/SKILL.md b/muse/lifecycle/quality/skills/replay/load-replay-reference-work/SKILL.md similarity index 100% rename from .agent/skills/load-replay-reference-work/SKILL.md rename to muse/lifecycle/quality/skills/replay/load-replay-reference-work/SKILL.md diff --git a/.agent/skills/load-replay-reference-work/scripts/load_writer_reference_work.py b/muse/lifecycle/quality/skills/replay/load-replay-reference-work/scripts/load_writer_reference_work.py similarity index 99% rename from .agent/skills/load-replay-reference-work/scripts/load_writer_reference_work.py rename to muse/lifecycle/quality/skills/replay/load-replay-reference-work/scripts/load_writer_reference_work.py index 254402a..79e03d9 100644 --- a/.agent/skills/load-replay-reference-work/scripts/load_writer_reference_work.py +++ b/muse/lifecycle/quality/skills/replay/load-replay-reference-work/scripts/load_writer_reference_work.py @@ -30,11 +30,15 @@ from muse_role import ( ) SCRIPT_DIR = Path(__file__).resolve().parent -SKILLS_DIR = SCRIPT_DIR.parents[1] -READ_CONTEXT_SCRIPTS = SKILLS_DIR / "assemble-context" / "scripts" -SNAPSHOT_SCRIPTS = SKILLS_DIR / "freeze-context" / "scripts" -WRITER_REPLAY_SCRIPTS = SKILLS_DIR / "replay-writer-gate" / "scripts" -for _import_dir in (READ_CONTEXT_SCRIPTS, SNAPSHOT_SCRIPTS, WRITER_REPLAY_SCRIPTS): +PROJECT_ROOT = next( + parent + for parent in (SCRIPT_DIR, *SCRIPT_DIR.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +READ_CONTEXT_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" +SNAPSHOT_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "freeze-context" / "scripts" +WRITER_REPLAY_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "replay" / "replay-writer-gate" / "scripts" +for _import_dir in (PROJECT_ROOT, READ_CONTEXT_SCRIPTS, SNAPSHOT_SCRIPTS, WRITER_REPLAY_SCRIPTS): if str(_import_dir) not in sys.path: sys.path.insert(0, str(_import_dir)) @@ -74,7 +78,7 @@ from run_writer_replay import profile_from_mapping # noqa: E402 PRIVATE_TMP = Path("/private/tmp").resolve() -REPLAY_CONFIG_DIR = SKILLS_DIR / "replay-writer-gate" / "configs" +REPLAY_CONFIG_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "replay" / "replay-writer-gate" / "configs" DEFAULT_BASE_CONFIG = REPLAY_CONFIG_DIR / "writer-gate-a-deep-space-v1.json" DEFAULT_SELECTOR_CONFIG = ( REPLAY_CONFIG_DIR / "writer-gate-a-deep-space-card-selectors-v1.json" diff --git a/.agent/skills/replay-writer-gate/SKILL.md b/muse/lifecycle/quality/skills/replay/replay-writer-gate/SKILL.md similarity index 97% rename from .agent/skills/replay-writer-gate/SKILL.md rename to muse/lifecycle/quality/skills/replay/replay-writer-gate/SKILL.md index 3cab1d8..273a6a5 100644 --- a/.agent/skills/replay-writer-gate/SKILL.md +++ b/muse/lifecycle/quality/skills/replay/replay-writer-gate/SKILL.md @@ -49,8 +49,8 @@ A/C 单变量回执在 `WriterCreativeInput v2` 上比较。正式 Gate A 的 `a dry-run 只输出计划、manifest 与上下文摘要,不调用任何模型,不生成候选正文,也不得声称真实回放完成: ```bash -PYTHONPATH=.agent/skills/replay-writer-gate/scripts .venv/bin/python -m run_writer_replay \ - --config .agent/skills/replay-writer-gate/configs/writer-gate-a-deep-space-v1.json \ +PYTHONPATH=muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts .venv/bin/python -m run_writer_replay \ + --config muse/lifecycle/quality/skills/replay/replay-writer-gate/configs/writer-gate-a-deep-space-v1.json \ --dry-run ``` diff --git a/.agent/skills/replay-writer-gate/configs/writer-gate-a-deep-space-card-selectors-v1.json b/muse/lifecycle/quality/skills/replay/replay-writer-gate/configs/writer-gate-a-deep-space-card-selectors-v1.json similarity index 100% rename from .agent/skills/replay-writer-gate/configs/writer-gate-a-deep-space-card-selectors-v1.json rename to muse/lifecycle/quality/skills/replay/replay-writer-gate/configs/writer-gate-a-deep-space-card-selectors-v1.json diff --git a/.agent/skills/replay-writer-gate/configs/writer-gate-a-deep-space-v1.json b/muse/lifecycle/quality/skills/replay/replay-writer-gate/configs/writer-gate-a-deep-space-v1.json similarity index 100% rename from .agent/skills/replay-writer-gate/configs/writer-gate-a-deep-space-v1.json rename to muse/lifecycle/quality/skills/replay/replay-writer-gate/configs/writer-gate-a-deep-space-v1.json diff --git a/.agent/skills/replay-writer-gate/scripts/run_writer_replay/__init__.py b/muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts/run_writer_replay/__init__.py similarity index 100% rename from .agent/skills/replay-writer-gate/scripts/run_writer_replay/__init__.py rename to muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts/run_writer_replay/__init__.py diff --git a/.agent/skills/replay-writer-gate/scripts/run_writer_replay/__main__.py b/muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts/run_writer_replay/__main__.py similarity index 100% rename from .agent/skills/replay-writer-gate/scripts/run_writer_replay/__main__.py rename to muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts/run_writer_replay/__main__.py diff --git a/.agent/skills/replay-writer-gate/scripts/run_writer_replay/_common.py b/muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts/run_writer_replay/_common.py similarity index 90% rename from .agent/skills/replay-writer-gate/scripts/run_writer_replay/_common.py rename to muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts/run_writer_replay/_common.py index 67c96ac..dd57d06 100644 --- a/.agent/skills/replay-writer-gate/scripts/run_writer_replay/_common.py +++ b/muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts/run_writer_replay/_common.py @@ -21,14 +21,20 @@ from pathlib import Path from typing import Any, Callable, Mapping, Protocol SCRIPT_DIR = Path(__file__).resolve().parents[1] # 包目录的上一级仍是 scripts/ -SKILLS_DIR = SCRIPT_DIR.parents[1] -EVIDENCE_DIR = SKILLS_DIR / "record-run-evidence" / "scripts" -CONTINUATION_DIR = SKILLS_DIR / "write-next-chapter" / "scripts" -READ_CONTEXT_DIR = SKILLS_DIR / "assemble-context" / "scripts" -DETECT_DIR = SKILLS_DIR / "check-content-consistency" / "scripts" -QUALITY_GATE_DIR = SKILLS_DIR / "score-content-quality" / "scripts" -GATE_ADJUDICATION_DIR = SKILLS_DIR / "adjudicate-quality-gate" / "scripts" -SNAPSHOT_DIR = SKILLS_DIR / "freeze-context" / "scripts" +PROJECT_ROOT = next( + parent + for parent in (SCRIPT_DIR, *SCRIPT_DIR.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +# 兼容包内旧导出名;跨 Skill 依赖实际使用下面的显式目录常量。 +SKILLS_DIR = PROJECT_ROOT / "muse" +EVIDENCE_DIR = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" +CONTINUATION_DIR = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "generate" / "write-next-chapter" / "scripts" +READ_CONTEXT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" +DETECT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "semantic" / "check-content-consistency" / "scripts" +QUALITY_GATE_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "judge" / "score-content-quality" / "scripts" +GATE_ADJUDICATION_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "mechanical" / "adjudicate-quality-gate" / "scripts" +SNAPSHOT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "freeze-context" / "scripts" for import_path in ( EVIDENCE_DIR, CONTINUATION_DIR, diff --git a/.agent/skills/replay-writer-gate/scripts/run_writer_replay/authorization.py b/muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts/run_writer_replay/authorization.py similarity index 99% rename from .agent/skills/replay-writer-gate/scripts/run_writer_replay/authorization.py rename to muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts/run_writer_replay/authorization.py index 2479cf6..8460e83 100644 --- a/.agent/skills/replay-writer-gate/scripts/run_writer_replay/authorization.py +++ b/muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts/run_writer_replay/authorization.py @@ -120,7 +120,7 @@ def profile_from_mapping(value: Any, *, role: str) -> RoleExecutionProfile: if not system_prompt.strip(): raise WriterReplayError(f"{role} profile 缺少冻结 system prompt 快照") # 回放配置保存的是当次不可变 prompt 快照;当前角色合同由在线派发链从 - # .agent/docs/architecture/角色合同.md 装配,不能用当前角色文件反查历史快照。 + # muse/sot/角色合同.md 装配,不能用当前角色文件反查历史快照。 temperature_raw = profile.get("temperature") temperature = 0.2 if temperature_raw in (None, "", "unsupported") else float(temperature_raw) try: diff --git a/.agent/skills/replay-writer-gate/scripts/run_writer_replay/blind.py b/muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts/run_writer_replay/blind.py similarity index 100% rename from .agent/skills/replay-writer-gate/scripts/run_writer_replay/blind.py rename to muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts/run_writer_replay/blind.py diff --git a/.agent/skills/replay-writer-gate/scripts/run_writer_replay/budget.py b/muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts/run_writer_replay/budget.py similarity index 100% rename from .agent/skills/replay-writer-gate/scripts/run_writer_replay/budget.py rename to muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts/run_writer_replay/budget.py diff --git a/.agent/skills/replay-writer-gate/scripts/run_writer_replay/execute.py b/muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts/run_writer_replay/execute.py similarity index 100% rename from .agent/skills/replay-writer-gate/scripts/run_writer_replay/execute.py rename to muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts/run_writer_replay/execute.py diff --git a/.agent/skills/replay-writer-gate/scripts/run_writer_replay/sample.py b/muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts/run_writer_replay/sample.py similarity index 100% rename from .agent/skills/replay-writer-gate/scripts/run_writer_replay/sample.py rename to muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts/run_writer_replay/sample.py diff --git a/.agent/skills/replay-writer-gate/scripts/writer_eval_preregister.py b/muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts/writer_eval_preregister.py similarity index 100% rename from .agent/skills/replay-writer-gate/scripts/writer_eval_preregister.py rename to muse/lifecycle/quality/skills/replay/replay-writer-gate/scripts/writer_eval_preregister.py diff --git a/.agent/skills/check-content-consistency/SKILL.md b/muse/lifecycle/quality/skills/semantic/check-content-consistency/SKILL.md similarity index 100% rename from .agent/skills/check-content-consistency/SKILL.md rename to muse/lifecycle/quality/skills/semantic/check-content-consistency/SKILL.md diff --git a/.agent/skills/check-content-consistency/scripts/check_writer_candidate.py b/muse/lifecycle/quality/skills/semantic/check-content-consistency/scripts/check_writer_candidate.py similarity index 100% rename from .agent/skills/check-content-consistency/scripts/check_writer_candidate.py rename to muse/lifecycle/quality/skills/semantic/check-content-consistency/scripts/check_writer_candidate.py diff --git a/.agent/skills/check-content-consistency/scripts/run_writer_semantic_detector.py b/muse/lifecycle/quality/skills/semantic/check-content-consistency/scripts/run_writer_semantic_detector.py similarity index 100% rename from .agent/skills/check-content-consistency/scripts/run_writer_semantic_detector.py rename to muse/lifecycle/quality/skills/semantic/check-content-consistency/scripts/run_writer_semantic_detector.py diff --git a/muse-db/pyproject.toml b/muse/platform/db/pyproject.toml similarity index 100% rename from muse-db/pyproject.toml rename to muse/platform/db/pyproject.toml diff --git a/muse-db/src/muse_db/__init__.py b/muse/platform/db/src/muse_db/__init__.py similarity index 100% rename from muse-db/src/muse_db/__init__.py rename to muse/platform/db/src/muse_db/__init__.py diff --git a/muse-embed/pyproject.toml b/muse/platform/embed/pyproject.toml similarity index 100% rename from muse-embed/pyproject.toml rename to muse/platform/embed/pyproject.toml diff --git a/muse-embed/src/muse_embed.py b/muse/platform/embed/src/muse_embed.py similarity index 100% rename from muse-embed/src/muse_embed.py rename to muse/platform/embed/src/muse_embed.py diff --git a/muse-llm/pyproject.toml b/muse/platform/llm/pyproject.toml similarity index 100% rename from muse-llm/pyproject.toml rename to muse/platform/llm/pyproject.toml diff --git a/.agent/skills/call-content-model/SKILL.md b/muse/platform/llm/skills/call-content-model/SKILL.md similarity index 92% rename from .agent/skills/call-content-model/SKILL.md rename to muse/platform/llm/skills/call-content-model/SKILL.md index 70b3f4a..5552068 100644 --- a/.agent/skills/call-content-model/SKILL.md +++ b/muse/platform/llm/skills/call-content-model/SKILL.md @@ -1,13 +1,14 @@ --- name: call-content-model description: 通过 New-API 的统一治理入口调用内容模型,执行额度窗口、模型降级、重试和 JSON 提取。清洗、拆书或知识审核需要 MiniMax 等内容模型时使用;不得裸调外部服务。 +disable-model-invocation: true --- # 调用内容模型 创始人拍板(2026-07-13):清洗与拆书的内容生产 LLM **全部走 New-API 的 MiniMax-M3**;主会话(Fable5)只固化 agent/提示词/skill 与发起调用。本 skill 是唯一出口。 -管线内容生产调用的**标准入口是 `chat_governed`**(受 5 小时额度窗 + 全局降级链治理);`chat`/`chat` CLI 是不受治理的直连,仅供调试。治理政策的机械事实源是运行配置、共享额度账本 `example_llm_quota` 和模型运行适配器——库实现装为共享包 `muse-llm`(`-e ./muse-llm`),调用方 `from muse_llm import chat_governed`,`scripts/llm.py` 只是本 Skill 的 CLI;模型链切换必须由该 skill 治理并留下日志。 +管线内容生产调用的**标准入口是 `chat_governed`**(受 5 小时额度窗 + 全局降级链治理);`chat`/`chat` CLI 是不受治理的直连,仅供调试。治理政策的机械事实源是运行配置、共享额度账本 `example_llm_quota` 和模型运行适配器——库实现装为共享包 `muse-llm`(`-e ./muse/platform/llm`),调用方 `from muse_llm import chat_governed`,`scripts/llm.py` 只是本 Skill 的 CLI;模型链切换必须由该 skill 治理并留下日志。 ## 用法 @@ -46,7 +47,7 @@ data = extract_json(content) ```bash # 仅调试:显式 --ungoverned 后读 prompt 文件直连调用 -.venv/bin/python .agent/skills/call-content-model/scripts/llm.py chat --ungoverned --prompt-file /tmp/p.txt [--model MiniMax-M3] [--max-tokens 32000] [--out /tmp/resp.txt] [--extract-json] +.venv/bin/python muse/platform/llm/skills/call-content-model/scripts/llm.py chat --ungoverned --prompt-file /tmp/p.txt [--model MiniMax-M3] [--max-tokens 32000] [--out /tmp/resp.txt] [--extract-json] ``` ## 内建保障(chat 与 chat_governed 共用的单次调用机制,调用方不必重复实现) diff --git a/.agent/skills/call-content-model/scripts/llm.py b/muse/platform/llm/skills/call-content-model/scripts/llm.py similarity index 100% rename from .agent/skills/call-content-model/scripts/llm.py rename to muse/platform/llm/skills/call-content-model/scripts/llm.py diff --git a/.agent/skills/execute-role-task/SKILL.md b/muse/platform/llm/skills/execute-role-task/SKILL.md similarity index 100% rename from .agent/skills/execute-role-task/SKILL.md rename to muse/platform/llm/skills/execute-role-task/SKILL.md diff --git a/.agent/skills/refresh-runtime-probe/SKILL.md b/muse/platform/llm/skills/refresh-runtime-probe/SKILL.md similarity index 93% rename from .agent/skills/refresh-runtime-probe/SKILL.md rename to muse/platform/llm/skills/refresh-runtime-probe/SKILL.md index 82d5a16..765eba5 100644 --- a/.agent/skills/refresh-runtime-probe/SKILL.md +++ b/muse/platform/llm/skills/refresh-runtime-probe/SKILL.md @@ -15,8 +15,8 @@ disable-model-invocation: true 真实刷新经 `muse_role.run_role` 调用当前 writer 角色;profile 重建复用 `replay-writer-gate.profile_from_mapping`,探针自哈希复用 `adjudicate-quality-gate.canonical_sha256`。 ```bash -.venv/bin/python .agent/skills/refresh-runtime-probe/scripts/refresh_runtime_probe.py \ - --config .agent/skills/replay-writer-gate/configs/writer-gate-a-deep-space-v1.json \ +.venv/bin/python muse/platform/llm/skills/refresh-runtime-probe/scripts/refresh_runtime_probe.py \ + --config muse/lifecycle/quality/skills/replay/replay-writer-gate/configs/writer-gate-a-deep-space-v1.json \ --output /tmp/writer-gate-a.probe-preview.json \ --dry-run ``` diff --git a/.agent/skills/refresh-runtime-probe/scripts/refresh_runtime_probe.py b/muse/platform/llm/skills/refresh-runtime-probe/scripts/refresh_runtime_probe.py similarity index 96% rename from .agent/skills/refresh-runtime-probe/scripts/refresh_runtime_probe.py rename to muse/platform/llm/skills/refresh-runtime-probe/scripts/refresh_runtime_probe.py index a558c90..37d56d1 100644 --- a/.agent/skills/refresh-runtime-probe/scripts/refresh_runtime_probe.py +++ b/muse/platform/llm/skills/refresh-runtime-probe/scripts/refresh_runtime_probe.py @@ -19,11 +19,15 @@ from pathlib import Path from typing import Any, Mapping, Protocol SCRIPT_DIR = Path(__file__).resolve().parent -SKILLS_DIR = SCRIPT_DIR.parents[1] -GATE_ADJUDICATION_DIR = SKILLS_DIR / "adjudicate-quality-gate" / "scripts" -WRITER_REPLAY_DIR = SKILLS_DIR / "replay-writer-gate" / "scripts" -EVIDENCE_DIR = SKILLS_DIR / "record-run-evidence" / "scripts" -for _import_dir in (GATE_ADJUDICATION_DIR, WRITER_REPLAY_DIR, EVIDENCE_DIR): +PROJECT_ROOT = next( + parent + for parent in (SCRIPT_DIR, *SCRIPT_DIR.parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +GATE_ADJUDICATION_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "mechanical" / "adjudicate-quality-gate" / "scripts" +WRITER_REPLAY_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "replay" / "replay-writer-gate" / "scripts" +EVIDENCE_DIR = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" +for _import_dir in (PROJECT_ROOT, GATE_ADJUDICATION_DIR, WRITER_REPLAY_DIR, EVIDENCE_DIR): if str(_import_dir) not in sys.path: sys.path.insert(0, str(_import_dir)) diff --git a/muse-llm/src/muse_llm.py b/muse/platform/llm/src/muse_llm.py similarity index 100% rename from muse-llm/src/muse_llm.py rename to muse/platform/llm/src/muse_llm.py diff --git a/muse-llm/src/muse_role.py b/muse/platform/llm/src/muse_role.py similarity index 100% rename from muse-llm/src/muse_role.py rename to muse/platform/llm/src/muse_role.py diff --git a/muse-llm/src/muse_role_contract.py b/muse/platform/llm/src/muse_role_contract.py similarity index 98% rename from muse-llm/src/muse_role_contract.py rename to muse/platform/llm/src/muse_role_contract.py index b8faa73..46e882c 100644 --- a/muse-llm/src/muse_role_contract.py +++ b/muse/platform/llm/src/muse_role_contract.py @@ -11,7 +11,7 @@ from typing import Any, Mapping import yaml ROLE_CONTRACT_VERSION = "role-contracts-v1" -ROLE_CONTRACT_RELATIVE_PATH = Path(".agent") / "docs" / "architecture" / "角色合同.md" +ROLE_CONTRACT_RELATIVE_PATH = Path("muse") / "sot" / "角色合同.md" ROLE_NAMES = frozenset({"writer", "planner", "extractor", "detector", "judge"}) _ROLE_SECTION = re.compile( r"" diff --git a/.agent/docs/architecture/_index.md b/muse/sot/_index.md similarity index 100% rename from .agent/docs/architecture/_index.md rename to muse/sot/_index.md diff --git a/.agent/docs/architecture/domains/01-作品领域.md b/muse/sot/domains/01-作品领域.md similarity index 98% rename from .agent/docs/architecture/domains/01-作品领域.md rename to muse/sot/domains/01-作品领域.md index e559456..1c4cc41 100644 --- a/.agent/docs/architecture/domains/01-作品领域.md +++ b/muse/sot/domains/01-作品领域.md @@ -123,4 +123,4 @@ draft -> writing -> paused -> writing -> completed - 实体事实:[02-实体领域](02-实体领域.md) - 正向创作与决策语义:[05-创作流程领域](05-创作流程领域.md) - 数据权威、raw 进库、运行回执字段合同与可恢复性:[08-数据权威与可视化领域](08-数据权威与可视化领域.md) -- Shadow/Canonical 上级合同:[架构-02](../../../../../design-docs/架构-02-核心数据结构与双轨模型.md) +- Shadow/Canonical 上级合同:[架构-02](../../../../design-docs/架构-02-核心数据结构与双轨模型.md) diff --git a/.agent/docs/architecture/domains/02-实体领域.md b/muse/sot/domains/02-实体领域.md similarity index 84% rename from .agent/docs/architecture/domains/02-实体领域.md rename to muse/sot/domains/02-实体领域.md index a1420f2..69377f9 100644 --- a/.agent/docs/architecture/domains/02-实体领域.md +++ b/muse/sot/domains/02-实体领域.md @@ -12,10 +12,10 @@ 实体的“长什么样”由两处共同决定,实体领域不另行复制字段: -- **型(有哪些实体类型、各型有哪些字段)**:由 `meta/schemas/` 拥有。本领域承认九个实体型:`character`、`character_relation`、`event`、`location`、`item`、`faction`、`power_system`、`world`、`narrative_state`。 +- **型(有哪些实体类型、各型有哪些字段)**:由 `muse/content/meta/schemas/` 拥有。本领域承认九个实体型:`character`、`character_relation`、`event`、`location`、`item`、`faction`、`power_system`、`world`、`narrative_state`。 - **存放(字段落在哪张库表)**:由库表拥有。草稿落 `muse_knowledge_draft`,已确认落 `muse_knowledge_entity`(关系另有 `muse_knowledge_relation`)。每个实体的可变业务字段放在该行的 JSONB `payload` 里,型决定 payload 里允许有哪些字段。 -一句话:**型看 `meta/schemas/`,字段权威 = `meta/schemas/` 的九型 + 库表**。本文件只描述实体合同,不复制九型的字段清单。 +一句话:**型看 `muse/content/meta/schemas/`,字段权威 = `muse/content/meta/schemas/` 的九型 + 库表**。本文件只描述实体合同,不复制九型的字段清单。 ## 3. 最小实体合同 @@ -41,7 +41,7 @@ 约束: - `id` 在作品内稳定,改名不换 id。 -- `type` 必须是 `meta/schemas/` 已登记的九型之一。 +- `type` 必须是 `muse/content/meta/schemas/` 已登记的九型之一。 - 只有用户确认或正式正文支持的事实才能成为正式内容;草稿不得静默进入后续正式上下文。 - 来源要能回到不可变位置和内容哈希,不能只写“某章某段”。 - 会随剧情变化的事实必须带生效章区间,不能用终态覆盖历史时点。 @@ -76,7 +76,7 @@ - **灾备导出**:正式层可导出,配合数据库备份用于恢复。 - 参考作品的出处与导入信息以 `example_reference_work` / `muse_knowledge_document` 为准(领域索引 §9:不做多租户授权机制,96 授权快照不启用)。 -> 注意区分两个“升格”:本节是**作品面实体升格**——把参考书的人物/关系抽进库的正式层。06 质量与复利领域的“经验升格”是另一件事——把写法经验从写法→范式→Skill 逐级固化。两者只是都叫“升格”,对象和去向完全不同,不要混为一谈。作品面升格对应实现:`extract-work-knowledge`,加维护三件套 `backup-work-extraction` / `reset-work-extraction` / `repair-work-extraction` 与 `db/ddl/94-example作品面升格.sql`。 +> 注意区分两个“升格”:本节是**作品面实体升格**——把参考书的人物/关系抽进库的正式层。06 质量与复利领域的“经验升格”是另一件事——把写法经验从写法→范式→Skill 逐级固化。两者只是都叫“升格”,对象和去向完全不同,不要混为一谈。作品面升格对应实现:`extract-work-knowledge`,加维护三件套 `backup-work-extraction` / `reset-work-extraction` / `repair-work-extraction` 与 `muse/authority/db/ddl/94-example作品面升格.sql`。 ## 7. 关系与状态 @@ -91,12 +91,12 @@ ### 背景 -演变历程 `{章, 台阶, 周期}` 的字段合同在 `meta/schemas/` 与 [专题-06](../../../../../design-docs/专题-06-元数据驱动的智能体架构.md) §4.5,三期消费语义(规划/检测/写作)在 [专题-07](../../../../../design-docs/专题-07-知识消费契约与质量闭环.md) §5。现状合同里它是**只追加的已发生日志**:一条一台阶、只追加不覆写。由此留下两个无主缺口: +演变历程 `{章, 台阶, 周期}` 的字段合同在 `muse/content/meta/schemas/` 与 [专题-06](../../../../design-docs/专题-06-元数据驱动的智能体架构.md) §4.5,三期消费语义(规划/检测/写作)在 [专题-07](../../../../design-docs/专题-07-知识消费契约与质量闭环.md) §5。现状合同里它是**只追加的已发生日志**:一条一台阶、只追加不覆写。由此留下两个无主缺口: - **只记已发生、不约束未来**:台阶只记到 登场/成长/高光/退场,“这条设定最终去哪”没有结构义务。角色有没有结局、力量体系如何退场,全靠作者记忆——升级线崩、线索太监、续写提前收线,都没有机械门禁提前拦。 - **没有全书视角**:哪条设定被哪几章消费过、哪些从没被碰、哪些还没收口,只能靠人判断,不能机械计算。 -检测维度 `canon_compliance`([专题-04](../../../../../design-docs/专题-04-生成质量门控与创作健康度设计方案.md))只查候选是否与已立正式事实矛盾(**一致性**);它不查设定自身是否有始有终、被消费、被收口(**完整性**)。完整性目前无 owner。 +检测维度 `canon_compliance`([专题-04](../../../../design-docs/专题-04-生成质量门控与创作健康度设计方案.md))只查候选是否与已立正式事实矛盾(**一致性**);它不查设定自身是否有始有终、被消费、被收口(**完整性**)。完整性目前无 owner。 ### 选项 @@ -108,11 +108,11 @@ ### 结论 -采 C。实体领域拥有**闭环义务合同**与**台账数据形状**;不重定义 演变历程/成长弧线 的字段语义(归 `meta/schemas/` 与 专题-06 §4.5),不改其三期消费合同(归 专题-07 §5),不重定义 `canon_compliance`(归 专题-04)。 +采 C。实体领域拥有**闭环义务合同**与**台账数据形状**;不重定义 演变历程/成长弧线 的字段语义(归 `muse/content/meta/schemas/` 与 专题-06 §4.5),不改其三期消费合同(归 专题-07 §5),不重定义 `canon_compliance`(归 专题-04)。 **① 闭环义务:从只追加日志升级为闭环** -- 义务对象:`meta/schemas/` 登记了 演变历程 的六个型——`character` / `event` / `faction` / `location` / `item` / `power_system`。未登记 演变历程 的型(如 `narrative_state`、`character_relation`)不受此义务约束。 +- 义务对象:`muse/content/meta/schemas/` 登记了 演变历程 的六个型——`character` / `event` / `faction` / `location` / `item` / `power_system`。未登记 演变历程 的型(如 `narrative_state`、`character_relation`)不受此义务约束。 - 闭环定义:一条设定的“已发生台阶(演变历程)”与“未来计划”合起来必须覆盖 登场 → … → 结局。即有明确的 登场 台阶,并有声明的 结局 方向——未来记在该型的未来计划字段,已发生的结局记在 演变历程(周期=结局)。“有终”指计划明写这条设定如何收场(角色的结局、力量体系的退场或湮灭、物品的归属),不是只有成长台阶。 - 机械执行时点: - **入库硬门禁**:设定草稿首次经 `decide-candidate` 成为正式行时(draft→canonical 确认路径),校验计划弧线有始有终,缺一则确认失败、不落正式行。机械失败不可被 Agent 主观覆判(与 [06-质量与复利领域](06-质量与复利领域.md) 质量链一致)。弧线的合法变更只走用户确认的正式修订(`revision` 加一)或带审计的 `retired`(§3 三态),这两条不是绕过门禁。 @@ -142,7 +142,7 @@ - `canon_compliance`(专题-04)问“是否与已立事实矛盾”,是一致性;闭环与台账问“是否有始有终、被消费、被收口”,是完整性。两者正交:不合并、不互相替代。 - 候选通过一致性检测,不豁免设定的闭环义务;台账报 未收口,也不代表任何候选吃了设定。 -> 现状标注:未来计划字段目前只有 `character` 登记(成长弧线);其余五个义务型只有 演变历程(已发生),无未来计划字段——它们的计划闭环暂不可机械校验。字段合同补齐归 `meta/schemas/`(术语与字段合同见 专题-06 §4.5),本节只定义义务、不定义字段。补齐前,这五型的入库门禁降级为校验已发生部分(须有 登场 台阶),结局方向暂由规划(大纲/细纲)声明、在台账登记为 未收口;字段补齐后升级为完整的计划闭环校验。 +> 现状标注:未来计划字段目前只有 `character` 登记(成长弧线);其余五个义务型只有 演变历程(已发生),无未来计划字段——它们的计划闭环暂不可机械校验。字段合同补齐归 `muse/content/meta/schemas/`(术语与字段合同见 专题-06 §4.5),本节只定义义务、不定义字段。补齐前,这五型的入库门禁降级为校验已发生部分(须有 登场 台阶),结局方向暂由规划(大纲/细纲)声明、在台账登记为 未收口;字段补齐后升级为完整的计划闭环校验。 ### 后果 @@ -175,14 +175,14 @@ ## 11. 关联 SoT -- 类型结构:[`meta/schemas/`](../../../../meta/schemas/README.md) +- 类型结构:[`muse/content/meta/schemas/`](../../content/meta/schemas/README.md) - 数据权威与可恢复性:[08-数据权威与可视化领域](08-数据权威与可视化领域.md) - 作品引用:[01-作品领域](01-作品领域.md) - 上下文冻结:[04-上下文领域](04-上下文领域.md) - 经验升格(与作品面实体升格不同):[06-质量与复利领域](06-质量与复利领域.md) -- 演变历程三期消费语义(owner,本领域 §8 只加完整性义务、不改消费):[专题-07](../../../../../design-docs/专题-07-知识消费契约与质量闭环.md) §5 -- 一致性检测维度 `canon_compliance`(与 §8 闭环完整性正交):[专题-04](../../../../../design-docs/专题-04-生成质量门控与创作健康度设计方案.md) -- 父仓元数据合同:[专题-06](../../../../../design-docs/专题-06-元数据驱动的智能体架构.md) +- 演变历程三期消费语义(owner,本领域 §8 只加完整性义务、不改消费):[专题-07](../../../../design-docs/专题-07-知识消费契约与质量闭环.md) §5 +- 一致性检测维度 `canon_compliance`(与 §8 闭环完整性正交):[专题-04](../../../../design-docs/专题-04-生成质量门控与创作健康度设计方案.md) +- 父仓元数据合同:[专题-06](../../../../design-docs/专题-06-元数据驱动的智能体架构.md) --- @@ -193,7 +193,7 @@ - 拆书与作品面实体入库管线(抽取、别名判重、跨窗留档、覆写审计)。 - review-knowledge-cards 三角色审核(番茄作家 / 起点作家 / 主编)作为拆书常设步骤。 - `aiContext` 字段级用途裁剪(按用途只取需要的字段)。 -- 参考作品授权快照表(`db/ddl/96`):**决定不启用**(领域索引 §9),DDL 留存不 apply。 +- 参考作品授权快照表(`muse/authority/db/ddl/96`):**决定不启用**(领域索引 §9),DDL 留存不 apply。 待建(目标合同,尚未跑通): @@ -201,5 +201,5 @@ - 稳定 `id` 不因改名变化的保证。 - `retired` 退役态。 - 设定全书闭环与台账(§8):`decide-candidate` 计划弧线入库门禁、全书设定台账视图、完本实现收口门禁;建成前闭环不被机械校验。 -- 五个义务型(`event`/`faction`/`location`/`item`/`power_system`)的未来计划字段补齐(字段合同归 `meta/schemas/`,见 §8 现状标注)。 +- 五个义务型(`event`/`faction`/`location`/`item`/`power_system`)的未来计划字段补齐(字段合同归 `muse/content/meta/schemas/`,见 §8 现状标注)。 - 删库可恢复(见 08)。 diff --git a/.agent/docs/architecture/domains/03-范式领域.md b/muse/sot/domains/03-范式领域.md similarity index 93% rename from .agent/docs/architecture/domains/03-范式领域.md rename to muse/sot/domains/03-范式领域.md index 43cacc3..148f492 100644 --- a/.agent/docs/architecture/domains/03-范式领域.md +++ b/muse/sot/domains/03-范式领域.md @@ -12,7 +12,7 @@ 范式不再用“目标文件目录”定义,改用数据合同定义:字段权威 = `meta/schemas` 六个范式型 + 库表。 -- **六个范式型**(由 `meta/schemas` 驱动):`scene_pattern`(通用桥段)、`trope`(套路)、`craft`(技法)、`pacing`(节奏)、`emotion`(情感)、`combat`(打斗)。每型的字段、边界判据和 aiContext 控制项由对应 schema 拥有,本文件不复制字段定义,见 [`meta/schemas/`](../../../../meta/schemas/README.md)。 +- **六个范式型**(由 `meta/schemas` 驱动):`scene_pattern`(通用桥段)、`trope`(套路)、`craft`(技法)、`pacing`(节奏)、`emotion`(情感)、`combat`(打斗)。每型的字段、边界判据和 aiContext 控制项由对应 schema 拥有,本文件不复制字段定义,见 [`muse/content/meta/schemas/`](../../content/meta/schemas/README.md)。 - **库表**:范式卡是 `muse_knowledge_draft` 表里的行。公共范式 `work_id = 0`,作品级范式 `work_id = 8`(当前实验作品)。型别、名称、摘要、写法要点、适用条件、例证出处等放在 `draft_payload`(JSONB)里,结构对齐 `meta/schemas` 对应型。 - **scope(适用范围)用库内字段区分**,不再用目录层级:公共 / 作品两层靠 `work_id` + 目标库区分。`work_id = 0` 是公共范式,非零 `work_id` 是某部作品的作品级范式。 - 范式卡的演进历史靠库内 `revision` 和数据库自身的版本/备份承载,不在卡里另写一份不可校验的历史叙述。 @@ -64,7 +64,7 @@ observation -> draft -> evaluating -> active -> retired ## 6. 设计决策:规划期绑定 -**背景**:范式的正路是“规划期决策、写作期引用”——规划产出显式挂所引范式的引用,写作期只按引用注入、不重新检索范式,上级合同见 [专题-07 §2](../../../../../design-docs/专题-07-知识消费契约与质量闭环.md)。本领域 §5 消费合同的目标态与此一致,但现状是写作期按本章意图实时有界召回,两者未对齐;同时 [01-作品领域 §3](01-作品领域.md) 已在作品行字段合同声明 `pattern_bindings`(绑定的范式范围或明确 ID),真实库表 `muse_content_work` 却无承载列。这两处缺口由本决策一并收口为明确合同。 +**背景**:范式的正路是“规划期决策、写作期引用”——规划产出显式挂所引范式的引用,写作期只按引用注入、不重新检索范式,上级合同见 [专题-07 §2](../../../../design-docs/专题-07-知识消费契约与质量闭环.md)。本领域 §5 消费合同的目标态与此一致,但现状是写作期按本章意图实时有界召回,两者未对齐;同时 [01-作品领域 §3](01-作品领域.md) 已在作品行字段合同声明 `pattern_bindings`(绑定的范式范围或明确 ID),真实库表 `muse_content_work` 却无承载列。这两处缺口由本决策一并收口为明确合同。 **选项**: @@ -81,11 +81,11 @@ observation -> draft -> evaluating -> active -> retired 2. **SoT↔库不一致与补齐方向**:`pattern_bindings` 已是作品行 SoT 合同字段([01-作品领域 §3](01-作品领域.md)),但 `muse_content_work` 尚无承载列——这是 SoT 先于库的债。本领域只定范式侧语义;库表承载位与落库机制归 [01-作品领域](01-作品领域.md) 与 [08-数据权威与可视化领域](08-数据权威与可视化领域.md),不在此写 DDL。补齐方向:在作品行增结构化承载位,存已确认绑定的范式引用集合;承载位建成前,绑定事实必须有临时落库位,不得只活在内存或文件,否则违反“一切落库”横切合同([领域索引 §3](_index.md))。 - **实验仓落地承载**(遵循 `db/ddl` 「主仓表原样不改列、实验扩展进 example_*」口径):承载位 = 最新一条已确认 assembly 规划行(`example_planning_section`,`section_type=assembly`,`state=confirmed`)的 `patternReferences`;确认 assembly 即激活绑定,不另改 `muse_content_work`。消费侧由 assemble-context `load_confirmed_pattern_bindings` 只读该已确认绑定(写作期不临场召回)。作品行 `pattern_bindings` 列仍是主仓生产承载方向(归 01/08),届时实验仓承载收敛回作品行。 -3. **生效时机(Shadow→confirmed)**:规划期 `select_patterns` 从公共范式卡选定本作范式,选择先落 Shadow(规划候选);经用户确认翻 confirmed 后才写入 `pattern_bindings`、才可进生成上下文(横切总闸见 [架构-02](../../../../../design-docs/架构-02-核心数据结构与双轨模型.md))。未经确认的 Shadow 选择不是绑定,不得被写作期消费。 +3. **生效时机(Shadow→confirmed)**:规划期 `select_patterns` 从公共范式卡选定本作范式,选择先落 Shadow(规划候选);经用户确认翻 confirmed 后才写入 `pattern_bindings`、才可进生成上下文(横切总闸见 [架构-02](../../../../design-docs/架构-02-核心数据结构与双轨模型.md))。未经确认的 Shadow 选择不是绑定,不得被写作期消费。 4. **assembly 落点与 knowledgeBindings 填充**:assembly 装配本次写作上下文时,其范式绑定项(`knowledgeBindings` 的范式部分)只从该作品 confirmed 的 `pattern_bindings` 派生——按引用回读冻结范式卡、回读验哈希,再按 §5 尺寸上限裁成注入视图;不从全库临场召回。选择、冻结、裁剪、投影的机制归 [04-上下文领域](04-上下文领域.md),本领域只约束“范式这一路只认已绑定引用”。 -5. **消费合同(写作期只读引用)**:assemble / writer 只消费 `pattern_bindings` 里 confirmed 绑定的范式;写作期对公共范式库做相似度临场海选的链路判违规(对齐 [专题-07 §7 验收 3](../../../../../design-docs/专题-07-知识消费契约与质量闭环.md))。范式冲突仍按 §5 既有规则(作品明确绑定优先、无法确定则省略,不随机拼接)。 +5. **消费合同(写作期只读引用)**:assemble / writer 只消费 `pattern_bindings` 里 confirmed 绑定的范式;写作期对公共范式库做相似度临场海选的链路判违规(对齐 [专题-07 §7 验收 3](../../../../design-docs/专题-07-知识消费契约与质量闭环.md))。范式冲突仍按 §5 既有规则(作品明确绑定优先、无法确定则省略,不随机拼接)。 6. **与评测 A/B/C 臂的关系**:生产绑定走作品行 `pattern_bindings`;评测 A/B/C 臂的分臂规则仍收敛在 writer 合同一处(开发评测边界见 [05-创作流程领域 §7](05-创作流程领域.md)),A 臂恒空、B/C 臂注入评测侧独立冻结的同一组范式卡。两条注入路径分立:评测臂不读作品行 `pattern_bindings`,生产绑定也不改写评测臂的冻结卡集——保证“有无范式卡 / 哪组范式卡”这个单变量不被生产绑定污染。 @@ -138,8 +138,8 @@ observation -> draft -> evaluating -> active -> retired - 实体入库(另一种“升格”):[02-实体领域](02-实体领域.md) - Skill 边界:[07-Agent与Skill领域](07-Agent与Skill领域.md) - 数据权威与可恢复性:[08-数据权威与可视化领域](08-数据权威与可视化领域.md) -- 类型结构:[`meta/schemas/`](../../../../meta/schemas/README.md) +- 类型结构:[`muse/content/meta/schemas/`](../../content/meta/schemas/README.md) - 作品行 `pattern_bindings` 字段合同与库表承载:[01-作品领域](01-作品领域.md) - 装配的选择 / 冻结 / 裁剪 / 投影机制:[04-上下文领域](04-上下文领域.md) - 开发评测边界与 A/B/C 臂:[05-创作流程领域](05-创作流程领域.md) -- 知识消费上级合同(规划期决策、写作期引用):[专题-07](../../../../../design-docs/专题-07-知识消费契约与质量闭环.md) +- 知识消费上级合同(规划期决策、写作期引用):[专题-07](../../../../design-docs/专题-07-知识消费契约与质量闭环.md) diff --git a/.agent/docs/architecture/domains/04-上下文领域.md b/muse/sot/domains/04-上下文领域.md similarity index 94% rename from .agent/docs/architecture/domains/04-上下文领域.md rename to muse/sot/domains/04-上下文领域.md index 63028cb..26ebdd0 100644 --- a/.agent/docs/architecture/domains/04-上下文领域.md +++ b/muse/sot/domains/04-上下文领域.md @@ -44,7 +44,7 @@ ## 4. 数据库读取器(核心实现) -数据库读取器是本领域的核心实现,对齐 [`assemble-context`](../../../../.agent/skills/assemble-context/SKILL.md) 现状:从库读可信来源、冻结、再投影。它必须能够: +数据库读取器是本领域的核心实现,对齐 [`assemble-context`](../../lifecycle/context/skills/assemble-context/SKILL.md) 现状:从库读可信来源、冻结、再投影。它必须能够: 1. 从库中枚举作品、实体和范式,按 ID、类型、名称、别名、scope、scenario 和章号过滤。 2. 解析库内 schema 并确认来源可溯(来源能回到已导入参考书或作品自身正式内容);不做多租户授权快照重验(96 不启用,领域索引 §9),确认每条来源可被本次任务合法读取。 @@ -84,5 +84,5 @@ ReAct Agent 可以调用上下文 Skill 请求补充证据,但不能自行访 - 内容来源:[01-作品领域](01-作品领域.md)、[02-实体领域](02-实体领域.md)、[03-范式领域](03-范式领域.md) - 数据权威与 raw:[08-数据权威与可视化领域](08-数据权威与可视化领域.md) -- 当前 Skill:[`assemble-context`](../../../../.agent/skills/assemble-context/SKILL.md) -- 上级上下文合同:[专题-03](../../../../../design-docs/专题-03-AI编排上下文与质量评测实现规范.md) +- 当前 Skill:[`assemble-context`](../../lifecycle/context/skills/assemble-context/SKILL.md) +- 上级上下文合同:[专题-03](../../../../design-docs/专题-03-AI编排上下文与质量评测实现规范.md) diff --git a/.agent/docs/architecture/domains/05-创作流程领域.md b/muse/sot/domains/05-创作流程领域.md similarity index 83% rename from .agent/docs/architecture/domains/05-创作流程领域.md rename to muse/sot/domains/05-创作流程领域.md index ae62fda..64a60cb 100644 --- a/.agent/docs/architecture/domains/05-创作流程领域.md +++ b/muse/sot/domains/05-创作流程领域.md @@ -12,11 +12,11 @@ 本节拥有正文生成**之前**的五阶段串行流程:定盘 → 大纲/卷纲 → 设定拆条 → 范式与文风选定 → 细纲。它回答"一部书在动笔写正文之前,要依次产出哪些规划事实、每步卡在什么门禁上、满足什么条件才允许进入下一步"。§2 的正向流程从本节阶段 4 产出的细纲往后接续。 -本领域拥有这五阶段的**顺序、进入/退出条件和门禁**,不拥有各阶段产物的字段合同与存储表结构——字段权威在 [`meta/schemas/`](../../../../meta/schemas/README.md),存储与确认链分别在 [01-作品领域](01-作品领域.md)、[02-实体领域](02-实体领域.md)、[03-范式领域](03-范式领域.md),本节只引用、不重复定义。 +本领域拥有这五阶段的**顺序、进入/退出条件和门禁**,不拥有各阶段产物的字段合同与存储表结构——字段权威在 [`muse/content/meta/schemas/`](../../content/meta/schemas/README.md),存储与确认链分别在 [01-作品领域](01-作品领域.md)、[02-实体领域](02-实体领域.md)、[03-范式领域](03-范式领域.md),本节只引用、不重复定义。 两条贯穿五阶段的硬合同(均为既有合同,本节只引用): -- **横切总闸**:一切规划候选先落 Shadow,经用户确认翻 Confirmed 后才进入生成上下文(Shadow/Canonical 双轨,见 [架构-02](../../../../../design-docs/架构-02-核心数据结构与双轨模型.md))。 +- **横切总闸**:一切规划候选先落 Shadow,经用户确认翻 Confirmed 后才进入生成上下文(Shadow/Canonical 双轨,见 [架构-02](../../../../design-docs/架构-02-核心数据结构与双轨模型.md))。 - **上层约束下层**:大纲派生卷纲、卷纲派生细纲;下层规划不得与已确认的上层规划相悖,冲突时以下层退回为准。 ### 阶段定义 @@ -26,23 +26,23 @@ **阶段 0 · 定盘** - 进入条件:作品已创建(作品行存在,见 [01-作品领域](01-作品领域.md))。 -- 产出:`work_core`(题材定位 / 核心卖点 / 主题立意 / 基调 / 禁区 / 核心悬念 / 谜底与真相 / 结局方向 / 目标读者,字段权威见 `meta/schemas/work_core.yaml`)+ `novel_work` 的篇幅目标(目标章数 × 单章字数区间 × 分卷数,见 `meta/schemas/novel_work.yaml`)。落 `section_type='setting'`。 +- 产出:`work_core`(题材定位 / 核心卖点 / 主题立意 / 基调 / 禁区 / 核心悬念 / 谜底与真相 / 结局方向 / 目标读者,字段权威见 `muse/content/meta/schemas/work_core.yaml`)+ `novel_work` 的篇幅目标(目标章数 × 单章字数区间 × 分卷数,见 `muse/content/meta/schemas/novel_work.yaml`)。落 `section_type='setting'`。 - 机械门禁:**篇幅目标三要素齐全**——当前为文档纪律,待升级为落库校验。 - 退出条件:`work_core` 九字段与篇幅目标三要素齐备且用户确认(`confirmed`)。 **阶段 1 · 大纲 / 卷纲** - 进入条件:阶段 0 已确认。 -- 产出:`outline`(`scope=work`,字段权威见 `meta/schemas/outline.yaml`)——主线一句话、分卷粗纲(每卷:卷名 · 卷目标 · 核心冲突 · 情绪终点)、当前卷细纲、未来卷粗纲(防续写提前收线)、弃案记录(防 AI 复活旧方向)。落 `section_type='outline'`。 +- 产出:`outline`(`scope=work`,字段权威见 `muse/content/meta/schemas/outline.yaml`)——主线一句话、分卷粗纲(每卷:卷名 · 卷目标 · 核心冲突 · 情绪终点)、当前卷细纲、未来卷粗纲(防续写提前收线)、弃案记录(防 AI 复活旧方向)。落 `section_type='outline'`。 - 机械门禁:**主线一句话 ≤ 50 字**、**每卷四要素齐**、**卷粗纲 ≈ 卷正文 0.3–0.5%**、**卷数 = 篇幅目标.分卷数**——当前均为文档纪律,待升级为落库机械校验(卷数合同是本次新增的架构空白之一,见本节"现状与待建")。 - 退出条件:大纲 `confirmed`,且卷数与篇幅目标.分卷数一致。 **阶段 2 · 设定拆条** - 进入条件:阶段 1 已确认。 -- 产出:把设定拆成结构本体 23 型条目(`world` / `power_system` / `faction` / `character` / `item` / `location` / `event` / `character_relation` 等,型与字段权威见 [`meta/schemas/`](../../../../meta/schemas/README.md))。主落点是实体入库链:`muse_knowledge_draft` → 用户确认 → `muse_knowledge_entity`(关系另落 `muse_knowledge_relation`),确认链由 [02-实体领域](02-实体领域.md) 拥有。每条实体带「演变历程」(已发生的 `{章, 台阶, 周期}`,周期取 登场/成长/高光/退场/结局)与「成长弧线」(未来计划)。 +- 产出:把设定拆成结构本体 23 型条目(`world` / `power_system` / `faction` / `character` / `item` / `location` / `event` / `character_relation` 等,型与字段权威见 [`muse/content/meta/schemas/`](../../content/meta/schemas/README.md))。主落点是实体入库链:`muse_knowledge_draft` → 用户确认 → `muse_knowledge_entity`(关系另落 `muse_knowledge_relation`),确认链由 [02-实体领域](02-实体领域.md) 拥有。每条实体带「演变历程」(已发生的 `{章, 台阶, 周期}`,周期取 登场/成长/高光/退场/结局)与「成长弧线」(未来计划)。 - 机械门禁: - 1. **payload ↔ schema 字段覆盖**(落库机械校验,带「字段存疑:原因」逃生口)——**已建**:`persist_planning` 落库按 `meta/schemas/<型>.yaml` 校验必填字段,缺必填失败关闭;`fine_outline` 型已标「字段覆盖门禁:强制」,其余型字段(中文键)与 payload 对齐后逐步纳入;推荐字段缺失只报告不拦,确无依据的字段可显式标「字段存疑:原因」放行。 + 1. **payload ↔ schema 字段覆盖**(落库机械校验,带「字段存疑:原因」逃生口)——**已建**:`persist_planning` 落库按 `muse/content/meta/schemas/<型>.yaml` 校验必填字段,缺必填失败关闭;`fine_outline` 型已标「字段覆盖门禁:强制」,其余型字段(中文键)与 payload 对齐后逐步纳入;推荐字段缺失只报告不拦,确无依据的字段可显式标「字段存疑:原因」放行。 2. **设定全书闭环**:每条设定须有 登场 → … → 结局 的计划弧线,有始有终——目标合同,待建(本次新增架构空白之一)。 3. **全书设定台账**:设定 × 章消费矩阵,标记未被碰 / 未收口——目标合同,待建(本次新增架构空白之一)。 - 退出条件:设定条目经用户确认入正式实体表,且字段覆盖、闭环、台账三项校验通过(三项建成前,以用户确认为退出准绳)。 @@ -53,17 +53,17 @@ - 产出: - 规划期 `select_patterns` 从公共范式卡(`work_id=0`)选定本作范式,绑定 `pattern_bindings`;范式内容与消费尺寸合同见 [03-范式领域](03-范式领域.md)。 - 装配 `assembly`:把已选范式与本作事实组织为待装配集合,落 `section_type='assembly'`(装配此前无领域 owner,本节收编,见下"归属收编")。 - - `style` 文风画像八字段(叙事人称视角 / 句式 / 叙述配比 / 用词质感 / AI 味黑名单 / 对话风格 / 章末钩子风格 / 达标样张,字段权威见 `meta/schemas/style.yaml`)。 -- 机械门禁:**`assembly` 经用户确认(`confirmed`)才进正文上下文**、**`assemble` 只消费已绑定范式**(对齐 [专题-07](../../../../../design-docs/专题-07-知识消费契约与质量闭环.md):公共范式只走规划期决策、写作期引用,不作写作期临场海选)、**`style` 真注入 writer**——**取数端与生产接线已建**:assemble-context 三个一等取数端(`load_confirmed_fine_outline` / `load_confirmed_pattern_bindings` / `load_confirmed_style`)已建并由生产编排(`.agent/skills/write-next-chapter/scripts/produce_next_chapter.py`)接线;范式只读已确认 assembly 绑定注入(实验仓承载,见 [03-范式领域 §6](03-范式领域.md)),确认文风投影为 `styleConstraints` 随冻结上下文注入 writer(不再写死为空)。**待建**:当前注入的是设定行的一句话文风(书12 现状),结构化 `style` 八字段画像的书级抽取尚未建;写作期范式须可回指 confirmed 绑定的门禁尚未机械强制。评测 A/B/C 臂走独立冻结注入,不读生产绑定。 + - `style` 文风画像八字段(叙事人称视角 / 句式 / 叙述配比 / 用词质感 / AI 味黑名单 / 对话风格 / 章末钩子风格 / 达标样张,字段权威见 `muse/content/meta/schemas/style.yaml`)。 +- 机械门禁:**`assembly` 经用户确认(`confirmed`)才进正文上下文**、**`assemble` 只消费已绑定范式**(对齐 [专题-07](../../../../design-docs/专题-07-知识消费契约与质量闭环.md):公共范式只走规划期决策、写作期引用,不作写作期临场海选)、**`style` 真注入 writer**——**取数端与生产接线已建**:assemble-context 三个一等取数端(`load_confirmed_fine_outline` / `load_confirmed_pattern_bindings` / `load_confirmed_style`)已建并由生产编排(`muse/content/work/skills/generate/write-next-chapter/scripts/produce_next_chapter.py`)接线;范式只读已确认 assembly 绑定注入(实验仓承载,见 [03-范式领域 §6](03-范式领域.md)),确认文风投影为 `styleConstraints` 随冻结上下文注入 writer(不再写死为空)。**待建**:当前注入的是设定行的一句话文风(书12 现状),结构化 `style` 八字段画像的书级抽取尚未建;写作期范式须可回指 confirmed 绑定的门禁尚未机械强制。评测 A/B/C 臂走独立冻结注入,不读生产绑定。 - 退出条件:`assembly` 已 `confirmed` 并完成 `pattern_bindings` 绑定,`style` 八字段齐备。 **阶段 4 · 细纲** - 进入条件:阶段 3 已确认,且当前卷大纲已确认。 -- 产出:逐章 `fine_outline`(章细纲 ≈ 章正文 3–5%,是结构骨架不是缩写,超比例退回),落 `section_type='fine_outline'` 且必须带 `target_chapter`。细纲字段合同见 [`meta/schemas/`](../../../../meta/schemas/README.md) 与 [细纲合同(plan-chapter)](../../../../.agent/skills/plan-chapter/SKILL.md)。 +- 产出:逐章 `fine_outline`(章细纲 ≈ 章正文 3–5%,是结构骨架不是缩写,超比例退回),落 `section_type='fine_outline'` 且必须带 `target_chapter`。细纲字段合同见 [`muse/content/meta/schemas/`](../../content/meta/schemas/README.md) 与 [细纲合同(plan-chapter)](../../lifecycle/flow/skills/chapter/plan-chapter/SKILL.md)。 - 机械门禁: - **硬门禁(既有,代码失败关闭)**:`section_type='fine_outline'` 必带 `target_chapter`、`payload` 为非空 JSON、细纲须为结构化对象且数组/字符串字段类型稳定(落库即拒)。 - - **内容门禁(文档纪律,待升级)**:硬事件 / 伏笔动作(埋 · 推 · 收)/ 必须出场实体 / 章末钩子齐备;**细纲硬约束覆盖率 100%**(回放评测维度,见 [专题-04](../../../../../design-docs/专题-04-生成质量门控与创作健康度设计方案.md));**细纲产出形与 writer 装配消费形统一——已建**:唯一字段权威 [`meta/schemas/fine_outline.yaml`](../../../../meta/schemas/fine_outline.yaml)(必填集满足装配与机械门、推荐集保留规划表达力),`plan-chapter` 与 writer 装配同指它,结束此前两套字段不相交的漂移。 + - **内容门禁(文档纪律,待升级)**:硬事件 / 伏笔动作(埋 · 推 · 收)/ 必须出场实体 / 章末钩子齐备;**细纲硬约束覆盖率 100%**(回放评测维度,见 [专题-04](../../../../design-docs/专题-04-生成质量门控与创作健康度设计方案.md));**细纲产出形与 writer 装配消费形统一——已建**:唯一字段权威 [`muse/content/meta/schemas/fine_outline.yaml`](../../content/meta/schemas/fine_outline.yaml)(必填集满足装配与机械门、推荐集保留规划表达力),`plan-chapter` 与 writer 装配同指它,结束此前两套字段不相交的漂移。 - 退出条件:该章细纲 `confirmed`,硬约束覆盖率达标,产出形可被 writer 装配直接消费。 ### 五阶段共用的落库机械门禁(既有,代码失败关闭) @@ -88,7 +88,7 @@ ### 现状与待建 -- **已建成(引用即可)**:五阶段顺序与产出落点、`example_planning_section` 的 `section_type` 白名单与 `fine_outline` 必带章号、`shadow → confirmed` 单通道、公共范式卡与 `select_patterns`;以及本轮落地的——细纲唯一字段合同(`meta/schemas/fine_outline.yaml`,产出形与装配消费形统一)、落库字段覆盖门禁(`fine_outline` 型已强制失败关闭)、assemble-context 三个一等取数端(`load_confirmed_fine_outline` / `load_confirmed_pattern_bindings` / `load_confirmed_style`)并由生产编排 `produce_next_chapter.py` 接线(细纲统一消费、范式只读已确认 assembly 绑定、文风投影为 `styleConstraints` 注入 writer)。 +- **已建成(引用即可)**:五阶段顺序与产出落点、`example_planning_section` 的 `section_type` 白名单与 `fine_outline` 必带章号、`shadow → confirmed` 单通道、公共范式卡与 `select_patterns`;以及本轮落地的——细纲唯一字段合同(`muse/content/meta/schemas/fine_outline.yaml`,产出形与装配消费形统一)、落库字段覆盖门禁(`fine_outline` 型已强制失败关闭)、assemble-context 三个一等取数端(`load_confirmed_fine_outline` / `load_confirmed_pattern_bindings` / `load_confirmed_style`)并由生产编排 `produce_next_chapter.py` 接线(细纲统一消费、范式只读已确认 assembly 绑定、文风投影为 `styleConstraints` 注入 writer)。 - **决策已定、机械落地待建(三个架构空白)**:合同见 02/01/03 三域决策记录—— 1. 设定全书闭环校验 + 全书设定台账(把「演变历程」从只追加日志升级为闭环义务,新增设定 × 章消费矩阵视图;见 [02-实体领域 §8](02-实体领域.md))。 2. 卷数合同:`novel_work` 篇幅目标增「分卷数」,`outline` 分卷粗纲卷数须与之一致并机械校验(见 [01-作品领域 §6](01-作品领域.md))。 @@ -287,7 +287,7 @@ Gate A/B、A/B/C 三臂、参考书标准答案和盲评只属于开发期离线 - 所有评测候选固定不可接受(四层机械强制,见 §3)。 - 评测产出不反写作品、实体或范式正式事实。 - 评测产出钉死评测区,只读看板可按区查看但不混入正式内容视图。 -- **访问分离,不是隔离**(harness 改造原则,见 [docs/2026-08-01-评测harness改造设计](../../../../docs/2026-08-01-评测harness改造设计.md)):评测与生产同库,靠逻辑隔离(`run_type` + 状态机 + 访问控制),不是物理隔离。强制须收拢到引擎单点:评测行对生产读默认不可见、`run_type` 插入后不可变(使 `(eval, accepted)` 永不可达),不靠每条查询自觉过滤。 +- **访问分离,不是隔离**(harness 改造原则,见 [docs/2026-08-01-评测harness改造设计](../../../docs/2026-08-01-评测harness改造设计.md)):评测与生产同库,靠逻辑隔离(`run_type` + 状态机 + 访问控制),不是物理隔离。强制须收拢到引擎单点:评测行对生产读默认不可见、`run_type` 插入后不可变(使 `(eval, accepted)` 永不可达),不靠每条查询自觉过滤。 - **oracle 读侧红线**:oracle / 标准答案 / 全文**不进任何模型输入上下文**,只供人走查——可机械验证的硬红线,与冻结合同同级(写侧已有硬强制,读侧不能只靠查询纪律)。 - **从预防迁到发现**:逻辑隔离不能全靠预防,配常设不变量持续抓越界——没有评测派生卡绑定到生产、没有评测质量结果出现在任何生产视图、没有正式正文块的来源能追溯到评测候选,违反即报警。 @@ -308,7 +308,7 @@ Gate A/B、A/B/C 三臂、参考书标准答案和盲评只属于开发期离线 - 上下文输入:[04-上下文领域](04-上下文领域.md)——冻结上下文的选择与裁剪。 - 质量步骤:[06-质量与复利领域](06-质量与复利领域.md)——机械门、语义检测、评分的合同。 - 数据权威与落库:[08-数据权威与可视化领域](08-数据权威与可视化领域.md)——库权威层级、落库机制、只读看板。 -- 结构本体字段权威:[`meta/schemas/`](../../../../meta/schemas/README.md)——前期五阶段各产出(work_core / novel_work / outline / style / 23 型)的字段合同。 -- 接受上级合同:[专题-01](../../../../../design-docs/专题-01-正文建议接受%28Accept%20Suggestion%29实现规范.md)——accept preflight 的产品级规范。 -- 细纲硬约束覆盖率:[专题-04](../../../../../design-docs/专题-04-生成质量门控与创作健康度设计方案.md)——阶段 4 覆盖率门禁的回放评测维度。 -- 范式规划期决策:[专题-07](../../../../../design-docs/专题-07-知识消费契约与质量闭环.md)——公共范式只走规划期决策、写作期引用的上级合同。 +- 结构本体字段权威:[`muse/content/meta/schemas/`](../../content/meta/schemas/README.md)——前期五阶段各产出(work_core / novel_work / outline / style / 23 型)的字段合同。 +- 接受上级合同:[专题-01](../../../../design-docs/专题-01-正文建议接受%28Accept%20Suggestion%29实现规范.md)——accept preflight 的产品级规范。 +- 细纲硬约束覆盖率:[专题-04](../../../../design-docs/专题-04-生成质量门控与创作健康度设计方案.md)——阶段 4 覆盖率门禁的回放评测维度。 +- 范式规划期决策:[专题-07](../../../../design-docs/专题-07-知识消费契约与质量闭环.md)——公共范式只走规划期决策、写作期引用的上级合同。 diff --git a/.agent/docs/architecture/domains/06-质量与复利领域.md b/muse/sot/domains/06-质量与复利领域.md similarity index 83% rename from .agent/docs/architecture/domains/06-质量与复利领域.md rename to muse/sot/domains/06-质量与复利领域.md index d447d15..9eecfe4 100644 --- a/.agent/docs/architecture/domains/06-质量与复利领域.md +++ b/muse/sot/domains/06-质量与复利领域.md @@ -33,7 +33,7 @@ 每章不能自创完全不同的量表,否则失去跨章比较;也不能用一套固定权重覆盖所有场景。量表、场景策略和阈值必须版本化——改了评分口径,要能读出“这次用的是哪一版量表”。 -现有实现承认(各一句,不展开):六类混淆项报告与新角色比例分层裁决由 [`adjudicate-quality-gate`](../../../../.agent/skills/adjudicate-quality-gate/SKILL.md) 承载;评分后的单变量归因建议由 [`optimize-content-quality`](../../../../.agent/skills/optimize-content-quality/SKILL.md) 承载;卡三角色审核与金标准校准由 [`review-knowledge-cards`](../../../../.agent/skills/review-knowledge-cards/SKILL.md) 承载;AI 味案例的来源哈希、Shadow 捕获与来源重验证由 [`capture-ai-flavor-cases`](../../../../.agent/skills/capture-ai-flavor-cases/SKILL.md) 承载,规则升格链由 [`promote-ai-flavor-rule`](../../../../.agent/skills/promote-ai-flavor-rule/SKILL.md) 承载;父仓专题-09 五技能(定基线 `establish-voice-baseline`、前置预防 `prevent-ai-flavor`、诊断 `diagnose-ai-flavor`、修订 `revise-ai-flavor`、采集 `capture-ai-flavor-cases` + 升格 `promote-ai-flavor-rule`)的先行验证链由本领域承载,共享资产层在 [`humanization/`](../../../../humanization/),接力铁律与链路登记见 [`meta/chains/`](../../../../meta/chains/README.md)。v2 进一步把 Canonical 正文画像、载体 scope/mask、regex/handler/density 分层、模态/时间锚点硬门、前置合同的 WriterContext 冻结、案例生命周期和 holdout 激活门落到 agent-example;独立研究到实现的追踪矩阵见 [`humanization/research/20-project-skill-coverage.yaml`](../../../../humanization/research/20-project-skill-coverage.yaml)。 +现有实现承认(各一句,不展开):六类混淆项报告与新角色比例分层裁决由 [`adjudicate-quality-gate`](../../lifecycle/quality/skills/mechanical/adjudicate-quality-gate/SKILL.md) 承载;评分后的单变量归因建议由 [`optimize-content-quality`](../../lifecycle/quality/skills/judge/optimize-content-quality/SKILL.md) 承载;卡三角色审核与金标准校准由 [`review-knowledge-cards`](../../content/entity/skills/review/review-knowledge-cards/SKILL.md) 承载;AI 味案例的来源哈希、Shadow 捕获与来源重验证由 [`capture-ai-flavor-cases`](../../lifecycle/quality/humanization/skills/capture-ai-flavor-cases/SKILL.md) 承载,规则升格链由 [`promote-ai-flavor-rule`](../../lifecycle/quality/humanization/skills/promote-ai-flavor-rule/SKILL.md) 承载;父仓专题-09 五技能(定基线 `establish-voice-baseline`、前置预防 `prevent-ai-flavor`、诊断 `diagnose-ai-flavor`、修订 `revise-ai-flavor`、采集 `capture-ai-flavor-cases` + 升格 `promote-ai-flavor-rule`)的先行验证链由本领域承载,共享资产层在 [`humanization/`](../../lifecycle/quality/humanization),接力铁律与链路登记见 [`muse/lifecycle/flow/chains/`](../../lifecycle/flow/chains/README.md)。v2 进一步把 Canonical 正文画像、载体 scope/mask、regex/handler/density 分层、模态/时间锚点硬门、前置合同的 WriterContext 冻结、案例生命周期和 holdout 激活门落到 agent-example;独立研究到实现的追踪矩阵见 [`muse/lifecycle/quality/humanization/research/20-project-skill-coverage.yaml`](../../lifecycle/quality/humanization/research/20-project-skill-coverage.yaml)。 ## 4. 失败分类 @@ -98,9 +98,9 @@ AI 味案例是“单次观察”的一种证据载体:既有作品反向扫 - 离线 raw、标准答案和候选进库(单独表 + 访问控制),不要求留仓外。 - **COMPLETED 判据(轮次封存)**:一轮评测完成,必须核对“本轮声明要产出的 raw 集合”与“实际落库集合”一致才置完成;“有行落库了”不是判据——一道不可能失败的门不是门。 - **代价明账**:评测证据与生产共享同一数据库信任根,是单用户场景的刻意取舍——换可观测性与防篡改,放弃证据底座独立性 / 外部可审计性。这是明账,不是纯收益。 -- **常设不变量**(从预防迁到发现):没有评测质量结果出现在任何生产视图、没有正式正文来源能追溯到评测候选——持续跑、违反即报警。(harness 改造原则,见 [docs/2026-08-01-评测harness改造设计](../../../../docs/2026-08-01-评测harness改造设计.md)) +- **常设不变量**(从预防迁到发现):没有评测质量结果出现在任何生产视图、没有正式正文来源能追溯到评测候选——持续跑、违反即报警。(harness 改造原则,见 [docs/2026-08-01-评测harness改造设计](../../../docs/2026-08-01-评测harness改造设计.md)) -现有实现承认(各一句,不展开):预算账本合同与运行探针锁定由 [`access-database`](../../../../.agent/skills/access-database/SKILL.md) 与 `record-run-evidence` 承载,Gate B 通过回执的哈希链由 [`decide-candidate`](../../../../.agent/skills/decide-candidate/SKILL.md) 承载。 +现有实现承认(各一句,不展开):预算账本合同与运行探针锁定由 [`access-database`](../../authority/evidence/skills/access-database/SKILL.md) 与 `record-run-evidence` 承载,Gate B 通过回执的哈希链由 [`decide-candidate`](../../content/work/skills/sovereignty/decide-candidate/SKILL.md) 承载。 > 实现现状标注(诚实保留):当前只有一个作品且评测样本已预注册,Gate B 因此恒判 `insufficient_evidence`(跨作品样本不足)——这是目标态下的正确行为,不是 bug。 @@ -128,4 +128,4 @@ AI 味案例是“单次观察”的一种证据载体:既有作品反向扫 - 范式生命周期:[03-范式领域](03-范式领域.md) - 实体入库“升格”(与本文经验升格不同义):[02-实体领域](02-实体领域.md) - Agent/Skill 升格:[07-Agent与Skill领域](07-Agent与Skill领域.md) -- 离线 Gate 上级合同:[专题-04](../../../../../design-docs/专题-04-生成质量门控与创作健康度设计方案.md) +- 离线 Gate 上级合同:[专题-04](../../../../design-docs/专题-04-生成质量门控与创作健康度设计方案.md) diff --git a/.agent/docs/architecture/domains/07-Agent与Skill领域.md b/muse/sot/domains/07-Agent与Skill领域.md similarity index 86% rename from .agent/docs/architecture/domains/07-Agent与Skill领域.md rename to muse/sot/domains/07-Agent与Skill领域.md index ebef1de..8e13fb3 100644 --- a/.agent/docs/architecture/domains/07-Agent与Skill领域.md +++ b/muse/sot/domains/07-Agent与Skill领域.md @@ -29,13 +29,15 @@ Agent 与 Skill 领域拥有角色职责、可调用能力合同、确定性工 5. 输出是结构化 JSON,由派发方按 schema 校验后才可进入下游;校验失败按失败关闭。 6. 派发方负责证据落库(record-run-evidence):事件账本、raw、逐回合模型调用,以及工具读取形成的依赖清单;角色本身不写回执、不推进状态。 -执行底座分三条链:框架派发链(dispatch-agent-task,宿主智能体框架会话)承载生产与评测的角色执行主链,是唯一的创作生成链;受治理直调链(`muse_role -> muse_llm.chat_governed`)只承载内容模型任务(清洗、拆书、抽取、审卡)与对照生成——2026-08-23 同源对照实验裁决其退出创作生成(同一份探索依赖上下文下,直调臂复读细纲原句被机械门拒绝,框架派发臂双门通过并经人采纳);批处理执行链(execute-role-task)承载无工具的直接角色任务。三条链共用角色合同、证据账本与落库合同;合同不绑定任何 CLI 的原生角色装载机制。 +执行底座分三条链:Muse 派发层先解析 `RoleTaskRequest`、角色合同、模型策略和输出 Schema,再通过 `FrameworkExecutionRequest` 交给 `framework/adapters/`;框架派发链承载生产与评测的角色执行主链,是唯一的创作生成链;受治理直调链(`muse_role -> muse_llm.chat_governed`)只承载内容模型任务(清洗、拆书、抽取、审卡)与对照生成——2026-08-23 同源对照实验裁决其退出创作生成(同一份探索依赖上下文下,直调臂复读细纲原句被机械门拒绝,框架派发臂双门通过并经人采纳);批处理执行链(execute-role-task)承载无工具的直接角色任务。三条链共用角色合同、证据账本与落库合同;合同不绑定任何 CLI 的原生角色装载机制。 + +当前生产适配器是 Pi;DSH headless 适配器只作为 opt-in 对照接缝,固定为 fresh、无工具、session flush 后回放,待只读工具闭集与真实业务旅程证据齐备后再评估是否扩大能力。 ## 3. Skill 合同 Skill 按实现性质分两类,合同要求不同。**系统能力 Skill** 执行动作并产生落库的系统事实,须声明下列全部九项;自带 `scripts/` 不是判据——以模型判断为主的 Skill 可以不带 Tool,落库由它调用的 Skill 的 `scripts/` 承担。**参照 Skill** 不执行动作、不产生系统事实,也不进 `meta/chains` 登记,只声明第 1、3 项并写明取用边界与不适用场景,第 2、4 至 9 项不适用。两类都是正式 skill,都可在创作生命周期内被角色取用,分类见 `.agent/skills/_index.md`。 -每个系统能力 Skill 的 `.agent/skills/{name}/SKILL.md` 必须声明: +每个系统能力 Skill 的位置以 `muse/lifecycle/quality/harness/manifests/skills.json` 的 `skill_path` 为准;路径允许嵌套,且其 `SKILL.md` 必须声明: 1. 唯一目的和消费者。 2. 输入、输出及 schema/version。 @@ -45,7 +47,7 @@ Skill 按实现性质分两类,合同要求不同。**系统能力 Skill** 执 6. 输入产出落库:哪些输入和产出必须进库可见,见索引 §3。 7. 稳定错误码和失败恢复。 8. raw、授权、预算和审计边界。 -9. 开发验证与行为评测由 `harness/manifests/` 登记;`SKILL.md` 不承载测试命令、测试文件路径或测试结论。Skill 运行时需要执行的业务 dry-run/评测操作仍属于运行合同。 +9. 开发验证与行为评测由 `muse/lifecycle/quality/harness/manifests/` 登记;`SKILL.md` 不承载测试命令、测试文件路径或测试结论。Skill 运行时需要执行的业务 dry-run/评测操作仍属于运行合同。 数据库是权威:系统能力 Skill 对自己读写哪些表负责,声明失败时如何关闭,并确保经手的输入和产出都落库。没落库的输入产出,在系统视角里等于不存在。只读看板只查库渲染,不替 Skill 写任何数据。参照 Skill 不读写库,也不产生需要落库的输入产出。 @@ -65,7 +67,7 @@ Skill 按实现性质分两类,合同要求不同。**系统能力 Skill** 执 - 默认从仓库任意工作目录调用,必须自行解析项目根和输入绝对路径,不能依赖调用者先 `cd` 到特定目录。 - 机械事实必须结构化输出稳定状态和错误码;人读日志是补充,不是唯一接口。 - Tool 不调用模型,除非所属 Skill 明确声明该步骤本质需要模型。 -- Tool 变更必须有登记在 `harness/manifests/` 的相关实现测试、`py_compile` 和 `git diff --check` 证据;测试结果只证明机械合同,不升级为 Skill 行为或内容质量结论。 +- Tool 变更必须有登记在 `muse/lifecycle/quality/harness/manifests/` 的相关实现测试、`py_compile` 和 `git diff --check` 证据;测试结果只证明机械合同,不升级为 Skill 行为或内容质量结论。 ## 5. 目标工作链与授权管控 @@ -120,4 +122,4 @@ Skill 按实现性质分两类,合同要求不同。**系统能力 Skill** 执 - 创作编排:[05-创作流程领域](05-创作流程领域.md)。 - 质量升格:[06-质量与复利领域](06-质量与复利领域.md)。 - 实体入库(另一种“升格”):[02-实体领域](02-实体领域.md)。 -- Agent 上级合同:[专题-06](../../../../../design-docs/专题-06-元数据驱动的智能体架构.md)。 +- Agent 上级合同:[专题-06](../../../../design-docs/专题-06-元数据驱动的智能体架构.md)。 diff --git a/.agent/docs/architecture/domains/08-数据权威与可视化领域.md b/muse/sot/domains/08-数据权威与可视化领域.md similarity index 95% rename from .agent/docs/architecture/domains/08-数据权威与可视化领域.md rename to muse/sot/domains/08-数据权威与可视化领域.md index c24863e..e11b057 100644 --- a/.agent/docs/architecture/domains/08-数据权威与可视化领域.md +++ b/muse/sot/domains/08-数据权威与可视化领域.md @@ -116,7 +116,7 @@ raw 指不适合直接当正文、但需要留存可查的完整材料:完整 数据库是权威,所以可恢复性围绕数据库建立: - **库结构与数据**:靠数据库备份、快照或 dump 恢复。 -- **从零重建**:用 Git 里的代码与 DDL(`db/ddl/` 审计文件)重建库结构,再恢复数据。 +- **从零重建**:用 Git 里的代码与 DDL(`muse/authority/db/ddl/` 审计文件)重建库结构,再恢复数据。 - **向量索引**:可从库里的正文与知识重建,不单独备份也不算丢。 - **代码与文档**:靠 Git 历史恢复。 @@ -127,15 +127,15 @@ raw 指不适合直接当正文、但需要留存可查的完整材料:完整 - Git 保存代码、Skill、Agent 提示词、`meta/`(schema 与 chains)、文档、DDL 的版本历史,提供差异审查、回滚依据和备份。 - Git 不是正式内容权威,也不是实时消息总线。它可以对作品信息与作品文本留痕(历史、备份),但留痕不等于权威;正式内容以库为准,看板只读库,冲突时以库为准。 - 一次 `git commit` **不等于**用户接受。接受语义由创作流程和库内状态决定,见 [05-创作流程领域](05-创作流程领域.md)。 -- 数据库写入、DDL 应用走 `access-database` Skill 单一通道;DDL 先落 `db/ddl/` 审计文件再应用,不绕过。 +- 数据库写入、DDL 应用走 `access-database` Skill 单一通道;DDL 先落 `muse/authority/db/ddl/` 审计文件再应用,不绕过。 可承认的现有实现(引用即可,细节以各自载体为准): - `access-database`:单一数据库通道。 - `record-run-evidence`:不可改回执(内容寻址账本)与租约 raw 保险库(当前服务评测)。 -- 额度账本:`db/ddl/95-example额度账本.sql`。 -- 清洗日志:`db/ddl/92-example清洗日志.sql`。 -- 参考作品授权快照:`db/ddl/96-example参考作品授权快照.sql`(**决定不启用**,领域索引 §9;DDL 留存不 apply)。 +- 额度账本:`muse/authority/db/ddl/95-example额度账本.sql`。 +- 清洗日志:`muse/authority/db/ddl/92-example清洗日志.sql`。 +- 参考作品授权快照:`muse/authority/db/ddl/96-example参考作品授权快照.sql`(**决定不启用**,领域索引 §9;DDL 留存不 apply)。 - `import-book`:参考书 / 旧稿导入落库。 ## 10. 待建(目标合同) @@ -167,4 +167,4 @@ raw 指不适合直接当正文、但需要留存可查的完整材料:完整 - 候选、用户决策与接受语义:[05-创作流程领域](05-创作流程领域.md) - 检测 / 审核 / 实验结果消费回执:[06-质量与复利领域](06-质量与复利领域.md) - 数据库通道与 Skill 边界:[07-Agent与Skill领域](07-Agent与Skill领域.md) -- 外部交互上级合同:[专题-05](../../../../../design-docs/专题-05-AI统一交互协议与外部AgentAdapter设计.md) +- 外部交互上级合同:[专题-05](../../../../design-docs/专题-05-AI统一交互协议与外部AgentAdapter设计.md) diff --git a/.agent/docs/architecture/domains/_index.md b/muse/sot/domains/_index.md similarity index 86% rename from .agent/docs/architecture/domains/_index.md rename to muse/sot/domains/_index.md index d8cea30..e17840a 100644 --- a/.agent/docs/architecture/domains/_index.md +++ b/muse/sot/domains/_index.md @@ -28,7 +28,7 @@ - **每个产出都要落库**:AI 候选正文、检测与评分结果、用户的接受/合并/丢弃决策、每次运行的回执、补证与重写记录、实体与范式草稿、完整原文与完整问答。 - **没落库的,等于系统视角里不存在**。只读看板看不到,就是没记录。 - **落库由现有管线和 Skill 负责**;只读可视化模块只查库、只渲染,不写任何数据。 -- **单一基底、分层权威、分区治理**:库是唯一存放处(基底统一),但正式内容与评测区是**不同治理区**。评测的独立性由 `run_type` + 四层隔离 + oracle + 盲评 + 人审承载,**不由物料位置承载**。“一切落库”是基底主张,不是“库是无差别统一体”。(harness 改造原则,见 [docs/2026-08-01-评测harness改造设计](../../../../docs/2026-08-01-评测harness改造设计.md)) +- **单一基底、分层权威、分区治理**:库是唯一存放处(基底统一),但正式内容与评测区是**不同治理区**。评测的独立性由 `run_type` + 四层隔离 + oracle + 盲评 + 人审承载,**不由物料位置承载**。“一切落库”是基底主张,不是“库是无差别统一体”。(harness 改造原则,见 [docs/2026-08-01-评测harness改造设计](../../../docs/2026-08-01-评测harness改造设计.md)) ## 4. 只读可视化模块 @@ -90,14 +90,14 @@ - 不实现管理员控制台、租户、角色权限、市场、计费、资产交易或多用户协作。 - 不复制父仓完整业务有界上下文。 - 可视化模块不写库。 -- 不做多租户参考书授权机制:`db/ddl/96` 授权快照表**不启用**(单用户本地,授权人/使用者/机器是同一人,重型授权合规是从父仓过度继承);参考书出处与导入信息用 `example_reference_work` / `muse_knowledge_document` 即可(2026-07-30 拍板)。 +- 不做多租户参考书授权机制:`muse/authority/db/ddl/96` 授权快照表**不启用**(单用户本地,授权人/使用者/机器是同一人,重型授权合规是从父仓过度继承);参考书出处与导入信息用 `example_reference_work` / `muse_knowledge_document` 即可(2026-07-30 拍板)。 - 不再声称 Git 是正式内容权威,也不再承诺“删库零丢失”或“本地文件模式必选”。 ## 10. 上级 SoT -- 完整 Muse 产品边界:[产品-01](../../../../../design-docs/产品-01-产品定位与核心价值.md) -- Shadow/Canonical 双轨:[架构-02](../../../../../design-docs/架构-02-核心数据结构与双轨模型.md) -- 上下文与评测合同:[专题-03](../../../../../design-docs/专题-03-AI编排上下文与质量评测实现规范.md) -- 外部 Agent Adapter:[专题-05](../../../../../design-docs/专题-05-AI统一交互协议与外部AgentAdapter设计.md) -- 元数据与智能体结构:[专题-06](../../../../../design-docs/专题-06-元数据驱动的智能体架构.md) -- 知识消费与回放:[专题-07](../../../../../design-docs/专题-07-知识消费契约与质量闭环.md) +- 完整 Muse 产品边界:[产品-01](../../../../design-docs/产品-01-产品定位与核心价值.md) +- Shadow/Canonical 双轨:[架构-02](../../../../design-docs/架构-02-核心数据结构与双轨模型.md) +- 上下文与评测合同:[专题-03](../../../../design-docs/专题-03-AI编排上下文与质量评测实现规范.md) +- 外部 Agent Adapter:[专题-05](../../../../design-docs/专题-05-AI统一交互协议与外部AgentAdapter设计.md) +- 元数据与智能体结构:[专题-06](../../../../design-docs/专题-06-元数据驱动的智能体架构.md) +- 知识消费与回放:[专题-07](../../../../design-docs/专题-07-知识消费契约与质量闭环.md) diff --git a/.agent/docs/architecture/创作周期与Skill导读.md b/muse/sot/创作周期与Skill导读.md similarity index 56% rename from .agent/docs/architecture/创作周期与Skill导读.md rename to muse/sot/创作周期与Skill导读.md index 27e2aec..a3f4b4b 100644 --- a/.agent/docs/architecture/创作周期与Skill导读.md +++ b/muse/sot/创作周期与Skill导读.md @@ -1,9 +1,9 @@ # 创作周期与 Skill 导读 > 这篇是**教学地图**,方便在编辑器里点目录、点链接往下读。 -> 它**不是**合同权威。阶段顺序、门禁、人机分界以 [05-创作流程领域](domains/05-创作流程领域.md) 为准;某只 Skill 此刻允许做什么,以对应 [`SKILL.md`](../../../.agent/skills/_index.md) 为准。两边若有出入,以那两处为准,回改本文。 +> 它**不是**合同权威。阶段顺序、门禁、人机分界以 [05-创作流程领域](domains/05-创作流程领域.md) 为准;某只 Skill 此刻允许做什么,以对应 [`SKILL.md`](../../.agent/skills/_index.md) 为准。两边若有出入,以那两处为准,回改本文。 -磁盘上现有 **58** 只 Skill([`skills.json`](../../../harness/manifests/skills.json) 与 `.agent/skills/` 一致)。分类索引进度可能滞后,以 58 为准。 +磁盘上现有 **58** 只 Skill([`skills.json`](../lifecycle/quality/harness/manifests/skills.json) 为位置事实源)。其中 15 只方法 Skill 挂在 `.agent/skills/{planning,writing,diagnosis}/` 并进入运行期 catalog;编排 Skill 的业务索引见 [`muse/_skills_index.md`](../_skills_index.md)。 --- @@ -25,15 +25,15 @@ ### 1. 分类不是加载 -[Skill 分类索引](../../../.agent/skills/_index.md) 回答:**这只 Skill 主用在创作周期哪一段**。 +[Skill 方法索引](../../.agent/skills/_index.md) 回答:**这只方法 Skill 主用在创作周期哪一段**;全量位置与分类以 [`skills.json`](../lifecycle/quality/harness/manifests/skills.json) 为准。 -[功能链登记](../../../meta/chains/README.md) 回答:**这一回合角色 prompt 里真正塞进哪一份合同**。 +[功能链登记](../lifecycle/flow/chains/README.md) 回答:**这一回合角色 prompt 里真正塞进哪一份合同**。 -一次派发只带**一只功能 Skill**。其余功能合同不进这次上下文。 +一次派发只带**一只功能 Skill**。其余功能合同不进这次上下文。宿主发现所需方法 Skill 时读取 framework 生成的扁平 catalog;源合同仍在 Muse 的嵌套目录。 ### 2. 角色文件不写「这次做什么」 -五种角色身份在 [`.agent/agents/`](../../../.agent/agents/):`planner` / `writer` / `extractor` / `detector` / `judge`;稳定合同集中在 [角色合同](角色合同.md),角色文件写身份、Skill 路由与探索方法。五个角色都是创作智能体:经授权的只读工具自主探索(评委是圈定授权,见角色合同),探索轨迹进依赖清单。 +五种角色身份在 [`.agent/agents/`](../../.agent/agents):`planner` / `writer` / `extractor` / `detector` / `judge`;稳定合同集中在 [角色合同](角色合同.md),角色文件写身份、Skill 路由与探索方法。五个角色都是创作智能体:经授权的只读工具自主探索(评委是圈定授权,见角色合同),探索轨迹进依赖清单。 这次做什么、按什么步骤、输出什么,写在功能 Skill 里。换功能不换角色;换角色不换功能指令。 @@ -56,11 +56,11 @@ | 角色 | 文件 | 默认接哪些功能 | 产出 | |---|---|---|---| -| 规划师 planner | [planner.md](../../../.agent/agents/planner.md) | 设定初始化、书级规划、章级细纲 | 全是草稿 | -| 写手 writer | [writer.md](../../../.agent/agents/writer.md) | 续写、改写、扩写、润色 | 只回候选正文,不写文件、不提交 | -| 抽取员 extractor | [extractor.md](../../../.agent/agents/extractor.md) | 拆书、章后抽卡 | 全是草稿 | -| 检测员 detector | [detector.md](../../../.agent/agents/detector.md) | 语义一致性检查 | 只出检测报告,不改候选 | -| 评委 judge | [judge.md](../../../.agent/agents/judge.md) | 按量表匿名打分 | 只评分,不裁决过不过 | +| 规划师 planner | [planner.md](../../.agent/agents/planner.md) | 设定初始化、书级规划、章级细纲 | 全是草稿 | +| 写手 writer | [writer.md](../../.agent/agents/writer.md) | 续写、改写、扩写、润色 | 只回候选正文,不写文件、不提交 | +| 抽取员 extractor | [extractor.md](../../.agent/agents/extractor.md) | 拆书、章后抽卡 | 全是草稿 | +| 检测员 detector | [detector.md](../../.agent/agents/detector.md) | 语义一致性检查 | 只出检测报告,不改候选 | +| 评委 judge | [judge.md](../../.agent/agents/judge.md) | 按量表匿名打分 | 只评分,不裁决过不过 | 主代理负责理解并润色你的创作意图、选 Skill、转述智能体报告、请你决策。它不能代替这些角色创作,也不能替你制定创作约束、跳过保护步骤。 @@ -79,7 +79,7 @@ L0 任务段 ← assemble-context 组装 本回合参数 ``` -`scenario` 是这条功能链的名字,例如续写 `continuation`、细纲 `fine_outline`。它映射到哪只 Skill,看 [meta/chains/README.md](../../../meta/chains/README.md)。 +`scenario` 是这条功能链的名字,例如续写 `continuation`、细纲 `fine_outline`。它映射到哪只 Skill,看 [meta/chains/README.md](../lifecycle/flow/chains/README.md)。 三次装载,互不替代: @@ -98,7 +98,7 @@ Skill 还有两个实现形态: 方法 Skill **不进** 功能链登记。目标是在规划节点和正文节点自动装载、只出检查报告;按报告改内容仍要你点头。自动检查这一层**尚未建成**。 -调用开关(写在 [`skills.json`](../../../harness/manifests/skills.json)): +调用开关(写在 [`skills.json`](../lifecycle/quality/harness/manifests/skills.json)): - `orchestrated`:必须主会话或上游显式调用。frontmatter 带 `disable-model-invocation: true`。模型自己喊没有用。 - `model_routed`:模型可以按描述自行选用。方法 Skill 大多是这种。 @@ -166,18 +166,18 @@ flowchart TD 只在喂参考书或用户旧稿时走。不写你的新书。 -功能链:`full_parse` → [deconstruct-book](../../../.agent/skills/deconstruct-book/SKILL.md) → 抽取员。 +功能链:`full_parse` → [deconstruct-book](../content/entity/skills/ingest/deconstruct-book/SKILL.md) → 抽取员。 | Skill | 意图 | 规则 | 工具 | |---|---|---|---| -| [import-book](../../../.agent/skills/import-book/SKILL.md) | txt 分章写入作品、章、正文块 | 不调模型、不改写正文 | `import_novel.py` | -| [clean-book-text](../../../.agent/skills/clean-book-text/SKILL.md) | 删广告、水印、拉票、乱码 | 模型只提候选,脚本守卫才删 | `clean_detect.py` / `clean_apply.py` | -| [deconstruct-book](../../../.agent/skills/deconstruct-book/SKILL.md) | 逆向拆细纲、阶段大纲、实体线索、脱敏写法 | 自底向上,和创作规划方向相反;细纲约正文 3–5%,卷纲约 0.3–0.5%;系统级拆书必须脱敏 | `parse_ingest.py` 等;模型走 [call-content-model](../../../.agent/skills/call-content-model/SKILL.md)(MiniMax-M3) | -| [extract-work-knowledge](../../../.agent/skills/extract-work-knowledge/SKILL.md) | 按窗口抽作品面实体、关系草稿 | 与既有知识冲突不覆盖,双版本待你裁决 | `upgrade.py` | -| [review-knowledge-cards](../../../.agent/skills/review-knowledge-cards/SKILL.md) | 三种编辑视角审公共卡 | 不生成卡,不确认作品私有知识 | `review_cards.py` | -| [backup-work-extraction](../../../.agent/skills/backup-work-extraction/SKILL.md) / [reset-work-extraction](../../../.agent/skills/reset-work-extraction/SKILL.md) / [repair-work-extraction](../../../.agent/skills/repair-work-extraction/SKILL.md) / [inspect-parse-health](../../../.agent/skills/inspect-parse-health/SKILL.md) | 备份、重抽、修单窗、只读体检 | 四职互不代劳 | 各自 `scripts/` | +| [import-book](../content/entity/skills/ingest/import-book/SKILL.md) | txt 分章写入作品、章、正文块 | 不调模型、不改写正文 | `import_novel.py` | +| [clean-book-text](../content/entity/skills/ingest/clean-book-text/SKILL.md) | 删广告、水印、拉票、乱码 | 模型只提候选,脚本守卫才删 | `clean_detect.py` / `clean_apply.py` | +| [deconstruct-book](../content/entity/skills/ingest/deconstruct-book/SKILL.md) | 逆向拆细纲、阶段大纲、实体线索、脱敏写法 | 自底向上,和创作规划方向相反;细纲约正文 3–5%,卷纲约 0.3–0.5%;系统级拆书必须脱敏 | `parse_ingest.py` 等;模型走 [call-content-model](../platform/llm/skills/call-content-model/SKILL.md)(MiniMax-M3) | +| [extract-work-knowledge](../content/entity/skills/ingest/extract-work-knowledge/SKILL.md) | 按窗口抽作品面实体、关系草稿 | 与既有知识冲突不覆盖,双版本待你裁决 | `upgrade.py` | +| [review-knowledge-cards](../content/entity/skills/review/review-knowledge-cards/SKILL.md) | 三种编辑视角审公共卡 | 不生成卡,不确认作品私有知识 | `review_cards.py` | +| [backup-work-extraction](../content/entity/skills/ingest/backup-work-extraction/SKILL.md) / [reset-work-extraction](../content/entity/skills/ingest/reset-work-extraction/SKILL.md) / [repair-work-extraction](../content/entity/skills/ingest/repair-work-extraction/SKILL.md) / [inspect-parse-health](../content/entity/skills/ingest/inspect-parse-health/SKILL.md) | 备份、重抽、修单窗、只读体检 | 四职互不代劳 | 各自 `scripts/` | -知识要进检索,再走 [embed-knowledge](../../../.agent/skills/embed-knowledge/SKILL.md)(写入向量)和 [search-knowledge](../../../.agent/skills/search-knowledge/SKILL.md)(按绑定和权限召回)。向量只是加速,命中后必须回读库行。 +知识要进检索,再走 [embed-knowledge](../lifecycle/context/skills/embed-knowledge/SKILL.md)(写入向量)和 [search-knowledge](../lifecycle/context/skills/search-knowledge/SKILL.md)(按绑定和权限召回)。向量只是加速,命中后必须回读库行。 --- @@ -185,23 +185,23 @@ flowchart TD **要完成**:这本书是什么、写给谁、禁区在哪、篇幅目标(目标章数 × 单章字数 × 分卷数)。九个核心字段齐,你确认后才能往下。 -功能链:`setting_init` → [design-story-foundation](../../../.agent/skills/design-story-foundation/SKILL.md) → 规划师。 +功能链:`setting_init` → [design-story-foundation](../lifecycle/flow/skills/book/design-story-foundation/SKILL.md) → 规划师。 | Skill | 意图 | 规则 | 工具 / 方法 | |---|---|---|---| -| [design-story-foundation](../../../.agent/skills/design-story-foundation/SKILL.md) | 固化根设定,按固定三级章节树出可比较候选 | 候选不落库、不进 Canonical;你选完才交给规划 | `validate_candidates.py`、`assert_selection_handoff.py`;合同在 `references/candidate-contract.md` | -| [merge-story-candidates](../../../.agent/skills/merge-story-candidates/SKILL.md) | 多案逐章合成一案 | 一级章节一个新代理;根设定优先 | `serial_merge.py` | -| [concept-design](../../../.agent/skills/concept-design/SKILL.md) | 把「我想写 X」升级成能撑长篇的疑问 | idea 是陈述,concept 是疑问;四问(新鲜 / 角度 / 冲突 / 可撑长),可撑长必须过 | 无脚本。见 [方法:概念设计](#concept-design-概念设计) | +| [design-story-foundation](../lifecycle/flow/skills/book/design-story-foundation/SKILL.md) | 固化根设定,按固定三级章节树出可比较候选 | 候选不落库、不进 Canonical;你选完才交给规划 | `validate_candidates.py`、`assert_selection_handoff.py`;合同在 `references/candidate-contract.md` | +| [merge-story-candidates](../lifecycle/flow/skills/book/merge-story-candidates/SKILL.md) | 多案逐章合成一案 | 一级章节一个新代理;根设定优先 | `serial_merge.py` | +| [concept-design](../../.agent/skills/planning/concept-design/SKILL.md) | 把「我想写 X」升级成能撑长篇的疑问 | idea 是陈述,concept 是疑问;四问(新鲜 / 角度 / 冲突 / 可撑长),可撑长必须过 | 无脚本。见 [方法:概念设计](#concept-design-概念设计) | --- ### 阶段 1 · 大纲 / 卷纲(节点 P) -功能链:`planning` → [plan-story](../../../.agent/skills/plan-story/SKILL.md) → 规划师。 +功能链:`planning` → [plan-story](../lifecycle/flow/skills/book/plan-story/SKILL.md) → 规划师。 **意图**:按结构清单逐字段产设定包、大纲、叙事状态、装配草稿。清单上有字段就必须写;写不出标「字段存疑:原因」,不许跳过。 -**本 Skill 不写细纲。** 单章细纲只归 [plan-chapter](../../../.agent/skills/plan-chapter/SKILL.md)。 +**本 Skill 不写细纲。** 单章细纲只归 [plan-chapter](../lifecycle/flow/skills/chapter/plan-chapter/SKILL.md)。 规划规则四条: @@ -222,9 +222,9 @@ flowchart TD ### 阶段 2 · 设定拆条(节点 P) -仍由 [plan-story](../../../.agent/skills/plan-story/SKILL.md) 产出知识卡草稿。转正走另一条轨:[confirm-knowledge-draft](../../../.agent/skills/confirm-knowledge-draft/SKILL.md)。 +仍由 [plan-story](../lifecycle/flow/skills/book/plan-story/SKILL.md) 产出知识卡草稿。转正走另一条轨:[confirm-knowledge-draft](../content/entity/skills/sovereignty/confirm-knowledge-draft/SKILL.md)。 -**意图**:把设定拆成 23 型结构本体(人物、势力、地点、力量体系等)。型与字段在 [`meta/schemas/`](../../../meta/schemas/)。每条带演变历程和成长弧。 +**意图**:把设定拆成 23 型结构本体(人物、势力、地点、力量体系等)。型与字段在 [`meta/schemas/`](../content/meta/schemas)。每条带演变历程和成长弧。 **规则**:落库按对应 schema 校验必填,缺必填整单失败,不写半成品。全书闭环台账还是目标合同,目前以你确认为退出准绳。 @@ -236,8 +236,8 @@ flowchart TD 两件事: -1. [plan-story](../../../.agent/skills/plan-story/SKILL.md) 的 `select_patterns`:规划期选定本作范式,绑定进装配。写作期只引用已绑定的,不作临场海选。 -2. 功能链 `voice_baseline` → [establish-voice-baseline](../../../.agent/skills/establish-voice-baseline/SKILL.md):作品建立或新角色登场时,把已确认正文和作者样张做成声音账,版本化落库。平时不动。它是后面预防和修订的对照物。 +1. [plan-story](../lifecycle/flow/skills/book/plan-story/SKILL.md) 的 `select_patterns`:规划期选定本作范式,绑定进装配。写作期只引用已绑定的,不作临场海选。 +2. 功能链 `voice_baseline` → [establish-voice-baseline](../lifecycle/quality/humanization/skills/establish-voice-baseline/SKILL.md):作品建立或新角色登场时,把已确认正文和作者样张做成声音账,版本化落库。平时不动。它是后面预防和修订的对照物。 文风八字段(人称视角、句式、叙述配比、用词、AI 味黑名单、对话、章末钩子、达标样张)目标是真注入写手。当前生产注入的是设定行的一句话文风,结构化八字段抽取尚未建成。 @@ -245,13 +245,13 @@ flowchart TD ### 阶段 4 · 细纲(节点 P) -功能链:`fine_outline` → [plan-chapter](../../../.agent/skills/plan-chapter/SKILL.md) → 规划师。 +功能链:`fine_outline` → [plan-chapter](../lifecycle/flow/skills/chapter/plan-chapter/SKILL.md) → 规划师。 -前置:[assemble-context](../../../.agent/skills/assemble-context/SKILL.md) 先组装规划视图。回放时所有来源章号必须早于冻结点;目标章正文和目标章答案细纲一律禁读。 +前置:[assemble-context](../lifecycle/context/skills/assemble-context/SKILL.md) 先组装规划视图。回放时所有来源章号必须早于冻结点;目标章正文和目标章答案细纲一律禁读。 **意图**:把已确认大纲变成结构骨架,不是缩写。篇幅大约是章正文的 3–5%。 -必填(缺一不得落库、不得给写手),字段权威 [`fine_outline.yaml`](../../../meta/schemas/fine_outline.yaml): +必填(缺一不得落库、不得给写手),字段权威 [`fine_outline.yaml`](../content/meta/schemas/fine_outline.yaml): | 字段 | 白话 | |---|---| @@ -266,7 +266,7 @@ flowchart TD 落库必须带 `--owner-skill plan-chapter`。用 plan-story 默认身份写细纲会失败关闭。 -可选检测:[check-content-consistency](../../../.agent/skills/check-content-consistency/SKILL.md)(细纲分支)、[score-content-quality](../../../.agent/skills/score-content-quality/SKILL.md)(只评结构,不评文笔)。 +可选检测:[check-content-consistency](../lifecycle/quality/skills/semantic/check-content-consistency/SKILL.md)(细纲分支)、[score-content-quality](../lifecycle/quality/skills/judge/score-content-quality/SKILL.md)(只评结构,不评文笔)。 细纲里派场景任务,可装载 [scene-craft](#scene-craft-场景执行)。 @@ -298,12 +298,12 @@ flowchart TD | Skill | 意图 | 规则 | 工具 | |---|---|---|---| -| [prevent-ai-flavor](../../../.agent/skills/prevent-ai-flavor/SKILL.md) | 生成前把现行规则负约束和声音账正样例冻进上下文 | 不碰正文;不承诺零 AI 味;声音账缺失就诚实留空,不许拿「真人文风」冒充 | `prevent_ai_flavor.py` | -| [assemble-context](../../../.agent/skills/assemble-context/SKILL.md) | 从库读可信来源,冻成完整上下文,再按角色裁最小投影 | 卡只是索引,必须按指针回读原文;历史必须早于冻结点;写手看不见运行号、哈希、实验臂、标准答案 | `assemble_writer_context.py`、`persist_context_freeze.py`、`writer_contract.py` | -| [freeze-context](../../../.agent/skills/freeze-context/SKILL.md) | 被组装器向下调用:冻结清单、泄漏审计、只读装载 | 不调模型、不写正式数据 | `build_snapshot.py`、`check_snapshot.py`、`audit_leakage.py` | -| [write-next-chapter](../../../.agent/skills/write-next-chapter/SKILL.md) | 按已确认细纲写整章候选 | 硬事件、伏笔动作、出场、钩子不可删、反转、提前收;可设计新设定,但不得冒充已确认事实;写手看到 4000–7000 字,机械门大于 3000 且不超过 10000 | `run_writer.py`、`run_writer_pipeline.py`、`candidate_cas.py` | -| [check-content-consistency](../../../.agent/skills/check-content-consistency/SKILL.md) | 语义核查 | 证据不足必须标未知,不许猜成通过;新设定进候选清单,不因此禁写 | `run_writer_semantic_detector.py` | -| [diagnose-ai-flavor](../../../.agent/skills/diagnose-ai-flavor/SKILL.md) | 用现行规则库扫出精确片段 | 没有这份产物,修订 Skill 拒绝启动 | `diagnose_ai_flavor.py` | +| [prevent-ai-flavor](../lifecycle/quality/humanization/skills/prevent-ai-flavor/SKILL.md) | 生成前把现行规则负约束和声音账正样例冻进上下文 | 不碰正文;不承诺零 AI 味;声音账缺失就诚实留空,不许拿「真人文风」冒充 | `prevent_ai_flavor.py` | +| [assemble-context](../lifecycle/context/skills/assemble-context/SKILL.md) | 从库读可信来源,冻成完整上下文,再按角色裁最小投影 | 卡只是索引,必须按指针回读原文;历史必须早于冻结点;写手看不见运行号、哈希、实验臂、标准答案 | `assemble_writer_context.py`、`persist_context_freeze.py`、`writer_contract.py` | +| [freeze-context](../lifecycle/context/skills/freeze-context/SKILL.md) | 被组装器向下调用:冻结清单、泄漏审计、只读装载 | 不调模型、不写正式数据 | `build_snapshot.py`、`check_snapshot.py`、`audit_leakage.py` | +| [write-next-chapter](../content/work/skills/generate/write-next-chapter/SKILL.md) | 按已确认细纲写整章候选 | 硬事件、伏笔动作、出场、钩子不可删、反转、提前收;可设计新设定,但不得冒充已确认事实;写手看到 4000–7000 字,机械门大于 3000 且不超过 10000 | `run_writer.py`、`run_writer_pipeline.py`、`candidate_cas.py` | +| [check-content-consistency](../lifecycle/quality/skills/semantic/check-content-consistency/SKILL.md) | 语义核查 | 证据不足必须标未知,不许猜成通过;新设定进候选清单,不因此禁写 | `run_writer_semantic_detector.py` | +| [diagnose-ai-flavor](../lifecycle/quality/humanization/skills/diagnose-ai-flavor/SKILL.md) | 用现行规则库扫出精确片段 | 没有这份产物,修订 Skill 拒绝启动 | `diagnose_ai_flavor.py` | 写手只返回: @@ -317,15 +317,15 @@ flowchart TD | 你说什么 | 加载 | 边界 | |---|---|---| -| 改指定范围 | [rewrite-selection](../../../.agent/skills/rewrite-selection/SKILL.md) | 范围外原文不动;先核对期望版本号 | -| 场景太薄 | [expand-scene](../../../.agent/skills/expand-scene/SKILL.md) | 只加厚动作链、潜台词、感官;不新开场景、不改落点 | -| 只修表达 | [polish-prose](../../../.agent/skills/polish-prose/SKILL.md) | 不改情节事实。**不是**去 AI 味入口 | -| 去 AI 味 | 必须先诊断,再 [revise-ai-flavor](../../../.agent/skills/revise-ai-flavor/SKILL.md) | 最小改动;没诊断不启动;你不点头永远是候选 | -| 采纳 / 丢弃 | [decide-candidate](../../../.agent/skills/decide-candidate/SKILL.md) | Canonical 的唯一入口 | +| 改指定范围 | [rewrite-selection](../content/work/skills/generate/rewrite-selection/SKILL.md) | 范围外原文不动;先核对期望版本号 | +| 场景太薄 | [expand-scene](../content/work/skills/generate/expand-scene/SKILL.md) | 只加厚动作链、潜台词、感官;不新开场景、不改落点 | +| 只修表达 | [polish-prose](../content/work/skills/generate/polish-prose/SKILL.md) | 不改情节事实。**不是**去 AI 味入口 | +| 去 AI 味 | 必须先诊断,再 [revise-ai-flavor](../lifecycle/quality/humanization/skills/revise-ai-flavor/SKILL.md) | 最小改动;没诊断不启动;你不点头永远是候选 | +| 采纳 / 丢弃 | [decide-candidate](../content/work/skills/sovereignty/decide-candidate/SKILL.md) | Canonical 的唯一入口 | -[decide-candidate](../../../.agent/skills/decide-candidate/SKILL.md) 两步不可颠倒:先 `check_writer_acceptance.py`(纯检查、不写库),过了再 `write_canonical.py` 单事务写入。语义未过不得接受。评测候选任何情况下不得成为正式正文。 +[decide-candidate](../content/work/skills/sovereignty/decide-candidate/SKILL.md) 两步不可颠倒:先 `check_writer_acceptance.py`(纯检查、不写库),过了再 `write_canonical.py` 单事务写入。语义未过不得接受。评测候选任何情况下不得成为正式正文。 -采纳正文 ≠ 确认知识。知识转正走 [confirm-knowledge-draft](../../../.agent/skills/confirm-knowledge-draft/SKILL.md)。规划确认走 `persist_planning.py confirm`。 +采纳正文 ≠ 确认知识。知识转正走 [confirm-knowledge-draft](../content/entity/skills/sovereignty/confirm-knowledge-draft/SKILL.md)。规划确认走 `persist_planning.py confirm`。 #### 方法装载(目标:自动只读检查;现状待建) @@ -343,21 +343,21 @@ flowchart TD | [narrative-momentum](#narrative-momentum-叙事动力) | 章末为什么翻得下去 | | [foreshadow-payoff](#foreshadow-payoff-伏笔与回收) | 这一章是埋、推还是收 | -质量评分 [score-content-quality](../../../.agent/skills/score-content-quality/SKILL.md) 在生产链上**尚未接线**。盲评目前主要用于离线回放。 +质量评分 [score-content-quality](../lifecycle/quality/skills/judge/score-content-quality/SKILL.md) 在生产链上**尚未接线**。盲评目前主要用于离线回放。 --- ### 节点 A · 你采纳之后 -[decide-candidate](../../../.agent/skills/decide-candidate/SKILL.md) 把当前候选写成库内正式正文,并**授权**下游草稿自动生成。草稿转正式仍要你点头。 +[decide-candidate](../content/work/skills/sovereignty/decide-candidate/SKILL.md) 把当前候选写成库内正式正文,并**授权**下游草稿自动生成。草稿转正式仍要你点头。 | Skill | 意图 | 现状 | |---|---|---| -| [extract-chapter-knowledge](../../../.agent/skills/extract-chapter-knowledge/SKILL.md) | 从已接受章抽实体、关系、事件草稿 | 合同已建;异步执行未建,接受时只登记待办投影 | -| [capture-ai-flavor-cases](../../../.agent/skills/capture-ai-flavor-cases/SKILL.md) | 从正文或反馈抽 AI 味案例卡 | 已建,默认写库 | -| [promote-ai-flavor-rule](../../../.agent/skills/promote-ai-flavor-rule/SKILL.md) | 案例 → 样例 → 规则候选 → 评测 → 你激活 | 不碰本次正文 | -| [confirm-knowledge-draft](../../../.agent/skills/confirm-knowledge-draft/SKILL.md) | 你确认后草稿变正式实体,并迁移向量归属 | 已建;与正文轨表集不交 | -| [establish-voice-baseline](../../../.agent/skills/establish-voice-baseline/SKILL.md) | 新角色登场或声音定版 | 偶尔跑 | +| [extract-chapter-knowledge](../content/entity/skills/extract/extract-chapter-knowledge/SKILL.md) | 从已接受章抽实体、关系、事件草稿 | 合同已建;异步执行未建,接受时只登记待办投影 | +| [capture-ai-flavor-cases](../lifecycle/quality/humanization/skills/capture-ai-flavor-cases/SKILL.md) | 从正文或反馈抽 AI 味案例卡 | 已建,默认写库 | +| [promote-ai-flavor-rule](../lifecycle/quality/humanization/skills/promote-ai-flavor-rule/SKILL.md) | 案例 → 样例 → 规则候选 → 评测 → 你激活 | 不碰本次正文 | +| [confirm-knowledge-draft](../content/entity/skills/sovereignty/confirm-knowledge-draft/SKILL.md) | 你确认后草稿变正式实体,并迁移向量归属 | 已建;与正文轨表集不交 | +| [establish-voice-baseline](../lifecycle/quality/humanization/skills/establish-voice-baseline/SKILL.md) | 新角色登场或声音定版 | 偶尔跑 | 去 AI 味五步不可跳级: @@ -371,13 +371,13 @@ flowchart TD 背后挖掘规则(promote),不进这次正文 ``` -共享运行时在 [`humanization/`](../../../humanization/)。规则权威是库表,读库失败就关闭,不静默退回 Git 里的文件。 +共享运行时在 [`humanization/`](../lifecycle/quality/humanization)。规则权威是库表,读库失败就关闭,不静默退回 Git 里的文件。 --- ## 写手看见的四层上下文 -合同:[assemble-context](../../../.agent/skills/assemble-context/SKILL.md),设计 SoT 在父仓专题-03。完整上下文留在可信边界,模型只收到角色投影。 +合同:[assemble-context](../lifecycle/context/skills/assemble-context/SKILL.md),设计 SoT 在父仓专题-03。完整上下文留在可信边界,模型只收到角色投影。 | 层 | 是什么 | 裁剪纪律 | |---|---|---| @@ -405,7 +405,7 @@ flowchart TD ### concept-design 概念设计 -[SKILL.md](../../../.agent/skills/concept-design/SKILL.md) +[SKILL.md](../../.agent/skills/planning/concept-design/SKILL.md) 把「我想写 X」变成能撑长篇的疑问。 @@ -419,7 +419,7 @@ flowchart TD ### story-structure 故事结构 -[SKILL.md](../../../.agent/skills/story-structure/SKILL.md) +[SKILL.md](../../.agent/skills/planning/story-structure/SKILL.md) 先选短/中/长篇尺子,再搭骨架。短篇看瞬间,中篇看转折,长篇看命运。 @@ -438,7 +438,7 @@ flowchart TD ### story-planning 规划工作流 -[SKILL.md](../../../.agent/skills/story-planning/SKILL.md) +[SKILL.md](../../.agent/skills/planning/story-planning/SKILL.md) 把「找故事」挪到动笔前,用廉价规划稿替换昂贵重写。 @@ -452,7 +452,7 @@ flowchart TD ### narrative-momentum 叙事动力 -[SKILL.md](../../../.agent/skills/narrative-momentum/SKILL.md) +[SKILL.md](../../.agent/skills/planning/narrative-momentum/SKILL.md) 读者翻页的三个来源。 @@ -466,7 +466,7 @@ flowchart TD ### foreshadow-payoff 伏笔与回收 -[SKILL.md](../../../.agent/skills/foreshadow-payoff/SKILL.md) +[SKILL.md](../../.agent/skills/planning/foreshadow-payoff/SKILL.md) | 动作 | 规则 | 细节 | |---|---|---| @@ -478,7 +478,7 @@ flowchart TD ### story-ending 结尾 -[SKILL.md](../../../.agent/skills/story-ending/SKILL.md) +[SKILL.md](../../.agent/skills/planning/story-ending/SKILL.md) 先写下终局画面,再倒推前文该埋伏什么。终局管两问:终局在哪,终局把读者关起来还是打开。 @@ -486,7 +486,7 @@ flowchart TD ### scene-craft 场景执行 -[SKILL.md](../../../.agent/skills/scene-craft/SKILL.md) +[SKILL.md](../../.agent/skills/writing/scene-craft/SKILL.md) 细纲派场景任务、正文写一场戏,都用它。 @@ -501,7 +501,7 @@ flowchart TD ### dialogue-craft 对话 -[SKILL.md](../../../.agent/skills/dialogue-craft/SKILL.md) +[SKILL.md](../../.agent/skills/writing/dialogue-craft/SKILL.md) 对话是事件,不是装饰。 @@ -515,7 +515,7 @@ flowchart TD ### character-design 人物设计 -[SKILL.md](../../../.agent/skills/character-design/SKILL.md) +[SKILL.md](../../.agent/skills/writing/character-design/SKILL.md) 建人,不管怎么写进正文。 @@ -529,7 +529,7 @@ flowchart TD ### character-presentation 人物呈现 -[SKILL.md](../../../.agent/skills/character-presentation/SKILL.md) +[SKILL.md](../../.agent/skills/writing/character-presentation/SKILL.md) 让读者自己看见,而不是听你宣布「他很冷酷」。 @@ -543,7 +543,7 @@ flowchart TD ### show-and-omission 展示与留白 -[SKILL.md](../../../.agent/skills/show-and-omission/SKILL.md) +[SKILL.md](../../.agent/skills/writing/show-and-omission/SKILL.md) 写出来的是抓手,没写的是分量。 @@ -556,7 +556,7 @@ flowchart TD ### narration-pov 视角与叙述 -[SKILL.md](../../../.agent/skills/narration-pov/SKILL.md) +[SKILL.md](../../.agent/skills/writing/narration-pov/SKILL.md) 三件事:用谁的眼睛看,站什么立场讲,讲的过程怎么走。 @@ -570,7 +570,7 @@ flowchart TD ### prose-craft 语言修辞 -[SKILL.md](../../../.agent/skills/prose-craft/SKILL.md) +[SKILL.md](../../.agent/skills/writing/prose-craft/SKILL.md) | 旋钮 | 规则 | 细节 | |---|---|---| @@ -582,7 +582,7 @@ flowchart TD ### theme-and-stance 主题与立场 -[SKILL.md](../../../.agent/skills/theme-and-stance/SKILL.md) +[SKILL.md](../../.agent/skills/writing/theme-and-stance/SKILL.md) 主题让读者自己看出来。立场不先行安排情节。人物该受的苦,作者不能因为心软放过。 @@ -595,7 +595,7 @@ flowchart TD ### novel-diagnosis 作品诊断 -[SKILL.md](../../../.agent/skills/novel-diagnosis/SKILL.md) +[SKILL.md](../../.agent/skills/diagnosis/novel-diagnosis/SKILL.md) 感觉不对劲但说不清时,先整体体检,再把症状交给上面的专精 Skill。 @@ -614,11 +614,11 @@ Gate A/B、A/B/C 三臂、参考书标准答案,只属于离线验收。评测 | 链 | Skill | 做什么 | |---|---|---| -| 细纲回放 | [evaluate-frozen-replay](../../../.agent/skills/evaluate-frozen-replay/SKILL.md) | 冻到指定章号,三臂规划师 + 盲检测 + 双盲评委 | -| 正文回放 | [load-replay-reference-work](../../../.agent/skills/load-replay-reference-work/SKILL.md) → [replay-writer-gate](../../../.agent/skills/replay-writer-gate/SKILL.md) | 只读装配真实书;三臂写手 + 盲评 | -| 裁决 | [adjudicate-quality-gate](../../../.agent/skills/adjudicate-quality-gate/SKILL.md) | 从不可变回执出通过/不通过,评分层不得改写 | -| 归因建议 | [optimize-content-quality](../../../.agent/skills/optimize-content-quality/SKILL.md) | 锁定最低分维度,只出单变量建议,不重生成 | -| 探针 | [refresh-runtime-probe](../../../.agent/skills/refresh-runtime-probe/SKILL.md) | 写手合同升级后重签能力探针 | +| 细纲回放 | [evaluate-frozen-replay](../lifecycle/quality/skills/replay/evaluate-frozen-replay/SKILL.md) | 冻到指定章号,三臂规划师 + 盲检测 + 双盲评委 | +| 正文回放 | [load-replay-reference-work](../lifecycle/quality/skills/replay/load-replay-reference-work/SKILL.md) → [replay-writer-gate](../lifecycle/quality/skills/replay/replay-writer-gate/SKILL.md) | 只读装配真实书;三臂写手 + 盲评 | +| 裁决 | [adjudicate-quality-gate](../lifecycle/quality/skills/mechanical/adjudicate-quality-gate/SKILL.md) | 从不可变回执出通过/不通过,评分层不得改写 | +| 归因建议 | [optimize-content-quality](../lifecycle/quality/skills/judge/optimize-content-quality/SKILL.md) | 锁定最低分维度,只出单变量建议,不重生成 | +| 探针 | [refresh-runtime-probe](../platform/llm/skills/refresh-runtime-probe/SKILL.md) | 写手合同升级后重签能力探针 | --- @@ -626,18 +626,18 @@ Gate A/B、A/B/C 三臂、参考书标准答案,只属于离线验收。评测 | Skill | 作用 | |---|---| -| [access-database](../../../.agent/skills/access-database/SKILL.md) | 唯一通用数据库入口。专用导入、嵌入、检索仍走各自 Skill | -| [call-content-model](../../../.agent/skills/call-content-model/SKILL.md) | 内容模型统一入口:额度窗、降级、重试、JSON 提取 | -| [execute-role-task](../../../.agent/skills/execute-role-task/SKILL.md) | 冻结 prompt/schema/profile 下的受治理角色调用 | -| [record-run-evidence](../../../.agent/skills/record-run-evidence/SKILL.md) | 运行登记、不可变回执、原文证据、经验待审记录 | +| [access-database](../authority/evidence/skills/access-database/SKILL.md) | 唯一通用数据库入口。专用导入、嵌入、检索仍走各自 Skill | +| [call-content-model](../platform/llm/skills/call-content-model/SKILL.md) | 内容模型统一入口:额度窗、降级、重试、JSON 提取 | +| [execute-role-task](../platform/llm/skills/execute-role-task/SKILL.md) | 冻结 prompt/schema/profile 下的受治理角色调用 | +| [record-run-evidence](../authority/evidence/skills/record-run-evidence/SKILL.md) | 运行登记、不可变回执、原文证据、经验待审记录 | 角色模型合同见 [角色合同](角色合同.md):规划师、写手和评委固定 Opus,不得降级到内容模型;抽取员、检测员只有在 profile 明确登记时才可走内容治理链。每次框架调用显式指定 provider、model、thinking。内容链按 5 小时窗治理:MiniMax 累计花费上限 24 美元,全模型成功调用上限 6000 次。交互式角色由宿主子代理承载同一身份提示、角色合同与输入输出合同。 --- -## 58 只 Skill 总表 +## Skill 总表 -分类取值对应 [索引九域](../../../.agent/skills/_index.md)。这是**主用阶段**,不是每次全加载。跨阶段取用见索引文末表。 +方法 Skill 的分类取值对应 [方法索引九域](../../.agent/skills/_index.md);编排 Skill 的位置与调用分类见 [`skills.json`](../lifecycle/quality/harness/manifests/skills.json)。这是**主用阶段**,不是每次全加载。跨阶段取用见索引文末表。 `编排` = 只能被主会话或上游显式调用。`自路由` = 模型可读描述自行选用。 @@ -645,104 +645,104 @@ Gate A/B、A/B/C 三臂、参考书标准答案,只属于离线验收。评测 | Skill | 调用 | 一句话 | |---|---|---| -| [access-database](../../../.agent/skills/access-database/SKILL.md) | 自路由 | 受控查库、改库、跑可审计 DDL | -| [call-content-model](../../../.agent/skills/call-content-model/SKILL.md) | 自路由 | New-API 治理入口 | -| [dispatch-agent-task](../../../.agent/skills/dispatch-agent-task/SKILL.md) | 编排 | 显式模型策略下派发框架子代理并留痕 | -| [execute-role-task](../../../.agent/skills/execute-role-task/SKILL.md) | 编排 | 跑一次受治理角色任务 | -| [record-run-evidence](../../../.agent/skills/record-run-evidence/SKILL.md) | 编排 | 运行、回执、原文证据 | -| [refresh-runtime-probe](../../../.agent/skills/refresh-runtime-probe/SKILL.md) | 编排 | 重签写手能力探针 | +| [access-database](../authority/evidence/skills/access-database/SKILL.md) | 自路由 | 受控查库、改库、跑可审计 DDL | +| [call-content-model](../platform/llm/skills/call-content-model/SKILL.md) | 自路由 | New-API 治理入口 | +| [dispatch-agent-task](../lifecycle/dispatch/skills/dispatch-agent-task/SKILL.md) | 编排 | 显式模型策略下派发框架子代理并留痕 | +| [execute-role-task](../platform/llm/skills/execute-role-task/SKILL.md) | 编排 | 跑一次受治理角色任务 | +| [record-run-evidence](../authority/evidence/skills/record-run-evidence/SKILL.md) | 编排 | 运行、回执、原文证据 | +| [refresh-runtime-probe](../platform/llm/skills/refresh-runtime-probe/SKILL.md) | 编排 | 重签写手能力探针 | ### 素材导入与拆解 · 8 | Skill | 调用 | 一句话 | |---|---|---| -| [import-book](../../../.agent/skills/import-book/SKILL.md) | 自路由 | txt 分章落库 | -| [clean-book-text](../../../.agent/skills/clean-book-text/SKILL.md) | 自路由 | 删语义垃圾,不改写 | -| [deconstruct-book](../../../.agent/skills/deconstruct-book/SKILL.md) | 编排 | 全书拆细纲、大纲、范式 | -| [extract-work-knowledge](../../../.agent/skills/extract-work-knowledge/SKILL.md) | 编排 | 按窗抽作品面知识草稿 | -| [backup-work-extraction](../../../.agent/skills/backup-work-extraction/SKILL.md) | 编排 | 抽取状态备份与恢复 | -| [reset-work-extraction](../../../.agent/skills/reset-work-extraction/SKILL.md) | 编排 | 全量重抽前清空派生状态 | -| [repair-work-extraction](../../../.agent/skills/repair-work-extraction/SKILL.md) | 编排 | 修单窗、去重、迁移 | -| [inspect-parse-health](../../../.agent/skills/inspect-parse-health/SKILL.md) | 编排 | 只读体检拆书与升格终态 | +| [import-book](../content/entity/skills/ingest/import-book/SKILL.md) | 自路由 | txt 分章落库 | +| [clean-book-text](../content/entity/skills/ingest/clean-book-text/SKILL.md) | 自路由 | 删语义垃圾,不改写 | +| [deconstruct-book](../content/entity/skills/ingest/deconstruct-book/SKILL.md) | 编排 | 全书拆细纲、大纲、范式 | +| [extract-work-knowledge](../content/entity/skills/ingest/extract-work-knowledge/SKILL.md) | 编排 | 按窗抽作品面知识草稿 | +| [backup-work-extraction](../content/entity/skills/ingest/backup-work-extraction/SKILL.md) | 编排 | 抽取状态备份与恢复 | +| [reset-work-extraction](../content/entity/skills/ingest/reset-work-extraction/SKILL.md) | 编排 | 全量重抽前清空派生状态 | +| [repair-work-extraction](../content/entity/skills/ingest/repair-work-extraction/SKILL.md) | 编排 | 修单窗、去重、迁移 | +| [inspect-parse-health](../content/entity/skills/ingest/inspect-parse-health/SKILL.md) | 编排 | 只读体检拆书与升格终态 | ### 知识与上下文 · 6 | Skill | 调用 | 一句话 | |---|---|---| -| [embed-knowledge](../../../.agent/skills/embed-knowledge/SKILL.md) | 自路由 | 知识写入向量索引 | -| [search-knowledge](../../../.agent/skills/search-knowledge/SKILL.md) | 自路由 | 按意图召回并裁权限 | -| [freeze-context](../../../.agent/skills/freeze-context/SKILL.md) | 编排 | 冻到来源清单,查泄漏 | -| [assemble-context](../../../.agent/skills/assemble-context/SKILL.md) | 编排 | 组装并按角色投影 | -| [extract-chapter-knowledge](../../../.agent/skills/extract-chapter-knowledge/SKILL.md) | 编排 | 章后抽卡草稿 | -| [review-knowledge-cards](../../../.agent/skills/review-knowledge-cards/SKILL.md) | 自路由 | 审公共卡 pass / revise / reject | +| [embed-knowledge](../lifecycle/context/skills/embed-knowledge/SKILL.md) | 自路由 | 知识写入向量索引 | +| [search-knowledge](../lifecycle/context/skills/search-knowledge/SKILL.md) | 自路由 | 按意图召回并裁权限 | +| [freeze-context](../lifecycle/context/skills/freeze-context/SKILL.md) | 编排 | 冻到来源清单,查泄漏 | +| [assemble-context](../lifecycle/context/skills/assemble-context/SKILL.md) | 编排 | 组装并按角色投影 | +| [extract-chapter-knowledge](../content/entity/skills/extract/extract-chapter-knowledge/SKILL.md) | 编排 | 章后抽卡草稿 | +| [review-knowledge-cards](../content/entity/skills/review/review-knowledge-cards/SKILL.md) | 自路由 | 审公共卡 pass / revise / reject | ### 概念与前期 · 3 | Skill | 调用 | 一句话 | |---|---|---| -| [concept-design](../../../.agent/skills/concept-design/SKILL.md) | 自路由 | 点子升级为长篇概念 | -| [design-story-foundation](../../../.agent/skills/design-story-foundation/SKILL.md) | 编排 | 根设定 + 三级章节树候选 | -| [merge-story-candidates](../../../.agent/skills/merge-story-candidates/SKILL.md) | 编排 | 多案串行统合 | +| [concept-design](../../.agent/skills/planning/concept-design/SKILL.md) | 自路由 | 点子升级为长篇概念 | +| [design-story-foundation](../lifecycle/flow/skills/book/design-story-foundation/SKILL.md) | 编排 | 根设定 + 三级章节树候选 | +| [merge-story-candidates](../lifecycle/flow/skills/book/merge-story-candidates/SKILL.md) | 编排 | 多案串行统合 | ### 结构与规划 · 7 | Skill | 调用 | 一句话 | |---|---|---| -| [plan-story](../../../.agent/skills/plan-story/SKILL.md) | 编排 | 书级设定、大纲、装配草稿 | -| [plan-chapter](../../../.agent/skills/plan-chapter/SKILL.md) | 编排 | 单章细纲,唯一写入方 | -| [story-structure](../../../.agent/skills/story-structure/SKILL.md) | 自路由 | 四箱 + 六里程碑 | -| [story-planning](../../../.agent/skills/story-planning/SKILL.md) | 自路由 | 节拍表与工作流 | -| [narrative-momentum](../../../.agent/skills/narrative-momentum/SKILL.md) | 自路由 | 势、金币、钩子 | -| [foreshadow-payoff](../../../.agent/skills/foreshadow-payoff/SKILL.md) | 自路由 | 埋、铺台阶、兑现 | -| [story-ending](../../../.agent/skills/story-ending/SKILL.md) | 自路由 | 终局倒推与收尾姿态 | +| [plan-story](../lifecycle/flow/skills/book/plan-story/SKILL.md) | 编排 | 书级设定、大纲、装配草稿 | +| [plan-chapter](../lifecycle/flow/skills/chapter/plan-chapter/SKILL.md) | 编排 | 单章细纲,唯一写入方 | +| [story-structure](../../.agent/skills/planning/story-structure/SKILL.md) | 自路由 | 四箱 + 六里程碑 | +| [story-planning](../../.agent/skills/planning/story-planning/SKILL.md) | 自路由 | 节拍表与工作流 | +| [narrative-momentum](../../.agent/skills/planning/narrative-momentum/SKILL.md) | 自路由 | 势、金币、钩子 | +| [foreshadow-payoff](../../.agent/skills/planning/foreshadow-payoff/SKILL.md) | 自路由 | 埋、铺台阶、兑现 | +| [story-ending](../../.agent/skills/planning/story-ending/SKILL.md) | 自路由 | 终局倒推与收尾姿态 | ### 正文写作与呈现 · 12 | Skill | 调用 | 一句话 | |---|---|---| -| [write-next-chapter](../../../.agent/skills/write-next-chapter/SKILL.md) | 编排 | 按细纲写整章候选 | -| [expand-scene](../../../.agent/skills/expand-scene/SKILL.md) | 编排 | 场景内加厚 | -| [rewrite-selection](../../../.agent/skills/rewrite-selection/SKILL.md) | 编排 | 按你点名的范围重写 | -| [polish-prose](../../../.agent/skills/polish-prose/SKILL.md) | 编排 | 只修表达层 | -| [scene-craft](../../../.agent/skills/scene-craft/SKILL.md) | 自路由 | 场景六问 | -| [dialogue-craft](../../../.agent/skills/dialogue-craft/SKILL.md) | 自路由 | 对话当事件写 | -| [character-design](../../../.agent/skills/character-design/SKILL.md) | 自路由 | 建人五动作 | -| [character-presentation](../../../.agent/skills/character-presentation/SKILL.md) | 自路由 | 让读者自己看见人 | -| [show-and-omission](../../../.agent/skills/show-and-omission/SKILL.md) | 自路由 | 展示与留白 | -| [narration-pov](../../../.agent/skills/narration-pov/SKILL.md) | 自路由 | 视角、立场、叙述模式 | -| [prose-craft](../../../.agent/skills/prose-craft/SKILL.md) | 自路由 | 句子与段落旋钮 | -| [theme-and-stance](../../../.agent/skills/theme-and-stance/SKILL.md) | 自路由 | 主题演示与作家立场 | +| [write-next-chapter](../content/work/skills/generate/write-next-chapter/SKILL.md) | 编排 | 按细纲写整章候选 | +| [expand-scene](../content/work/skills/generate/expand-scene/SKILL.md) | 编排 | 场景内加厚 | +| [rewrite-selection](../content/work/skills/generate/rewrite-selection/SKILL.md) | 编排 | 按你点名的范围重写 | +| [polish-prose](../content/work/skills/generate/polish-prose/SKILL.md) | 编排 | 只修表达层 | +| [scene-craft](../../.agent/skills/writing/scene-craft/SKILL.md) | 自路由 | 场景六问 | +| [dialogue-craft](../../.agent/skills/writing/dialogue-craft/SKILL.md) | 自路由 | 对话当事件写 | +| [character-design](../../.agent/skills/writing/character-design/SKILL.md) | 自路由 | 建人五动作 | +| [character-presentation](../../.agent/skills/writing/character-presentation/SKILL.md) | 自路由 | 让读者自己看见人 | +| [show-and-omission](../../.agent/skills/writing/show-and-omission/SKILL.md) | 自路由 | 展示与留白 | +| [narration-pov](../../.agent/skills/writing/narration-pov/SKILL.md) | 自路由 | 视角、立场、叙述模式 | +| [prose-craft](../../.agent/skills/writing/prose-craft/SKILL.md) | 自路由 | 句子与段落旋钮 | +| [theme-and-stance](../../.agent/skills/writing/theme-and-stance/SKILL.md) | 自路由 | 主题演示与作家立场 | ### 检测、评分与诊断 · 8 | Skill | 调用 | 一句话 | |---|---|---| -| [check-content-consistency](../../../.agent/skills/check-content-consistency/SKILL.md) | 编排 | 结构、事实、伏笔、证据缺口 | -| [score-content-quality](../../../.agent/skills/score-content-quality/SKILL.md) | 编排 | 按量表打分,不裁决 | -| [adjudicate-quality-gate](../../../.agent/skills/adjudicate-quality-gate/SKILL.md) | 编排 | Gate 终态唯一来源 | -| [optimize-content-quality](../../../.agent/skills/optimize-content-quality/SKILL.md) | 自路由 | 最低维归因,只出建议 | -| [evaluate-frozen-replay](../../../.agent/skills/evaluate-frozen-replay/SKILL.md) | 编排 | 细纲隔离回放 | -| [replay-writer-gate](../../../.agent/skills/replay-writer-gate/SKILL.md) | 编排 | 正文三臂回放 | -| [load-replay-reference-work](../../../.agent/skills/load-replay-reference-work/SKILL.md) | 编排 | 只读装配回放用书 | -| [novel-diagnosis](../../../.agent/skills/novel-diagnosis/SKILL.md) | 自路由 | 整本体检后分流 | +| [check-content-consistency](../lifecycle/quality/skills/semantic/check-content-consistency/SKILL.md) | 编排 | 结构、事实、伏笔、证据缺口 | +| [score-content-quality](../lifecycle/quality/skills/judge/score-content-quality/SKILL.md) | 编排 | 按量表打分,不裁决 | +| [adjudicate-quality-gate](../lifecycle/quality/skills/mechanical/adjudicate-quality-gate/SKILL.md) | 编排 | Gate 终态唯一来源 | +| [optimize-content-quality](../lifecycle/quality/skills/judge/optimize-content-quality/SKILL.md) | 自路由 | 最低维归因,只出建议 | +| [evaluate-frozen-replay](../lifecycle/quality/skills/replay/evaluate-frozen-replay/SKILL.md) | 编排 | 细纲隔离回放 | +| [replay-writer-gate](../lifecycle/quality/skills/replay/replay-writer-gate/SKILL.md) | 编排 | 正文三臂回放 | +| [load-replay-reference-work](../lifecycle/quality/skills/replay/load-replay-reference-work/SKILL.md) | 编排 | 只读装配回放用书 | +| [novel-diagnosis](../../.agent/skills/diagnosis/novel-diagnosis/SKILL.md) | 自路由 | 整本体检后分流 | ### 去 AI 味与人感 · 6 | Skill | 调用 | 一句话 | |---|---|---| -| [establish-voice-baseline](../../../.agent/skills/establish-voice-baseline/SKILL.md) | 编排 | 声音账定版 | -| [prevent-ai-flavor](../../../.agent/skills/prevent-ai-flavor/SKILL.md) | 编排 | 生成前约束投影 | -| [diagnose-ai-flavor](../../../.agent/skills/diagnose-ai-flavor/SKILL.md) | 编排 | 只查不改 | -| [revise-ai-flavor](../../../.agent/skills/revise-ai-flavor/SKILL.md) | 编排 | 诊断之后的最小修订 | -| [capture-ai-flavor-cases](../../../.agent/skills/capture-ai-flavor-cases/SKILL.md) | 编排 | 抽取案例卡 | -| [promote-ai-flavor-rule](../../../.agent/skills/promote-ai-flavor-rule/SKILL.md) | 编排 | 案例升格为现行规则 | +| [establish-voice-baseline](../lifecycle/quality/humanization/skills/establish-voice-baseline/SKILL.md) | 编排 | 声音账定版 | +| [prevent-ai-flavor](../lifecycle/quality/humanization/skills/prevent-ai-flavor/SKILL.md) | 编排 | 生成前约束投影 | +| [diagnose-ai-flavor](../lifecycle/quality/humanization/skills/diagnose-ai-flavor/SKILL.md) | 编排 | 只查不改 | +| [revise-ai-flavor](../lifecycle/quality/humanization/skills/revise-ai-flavor/SKILL.md) | 编排 | 诊断之后的最小修订 | +| [capture-ai-flavor-cases](../lifecycle/quality/humanization/skills/capture-ai-flavor-cases/SKILL.md) | 编排 | 抽取案例卡 | +| [promote-ai-flavor-rule](../lifecycle/quality/humanization/skills/promote-ai-flavor-rule/SKILL.md) | 编排 | 案例升格为现行规则 | ### 候选主权 · 2 | Skill | 调用 | 一句话 | |---|---|---| -| [decide-candidate](../../../.agent/skills/decide-candidate/SKILL.md) | 编排 | 正文草稿变正式正文的唯一闸口 | -| [confirm-knowledge-draft](../../../.agent/skills/confirm-knowledge-draft/SKILL.md) | 自路由 | 知识草稿变正式实体 | +| [decide-candidate](../content/work/skills/sovereignty/decide-candidate/SKILL.md) | 编排 | 正文草稿变正式正文的唯一闸口 | +| [confirm-knowledge-draft](../content/entity/skills/sovereignty/confirm-knowledge-draft/SKILL.md) | 自路由 | 知识草稿变正式实体 | --- @@ -776,14 +776,14 @@ Gate A/B、A/B/C 三臂、参考书标准答案,只属于离线验收。评测 | 你想确认 | 打开 | |---|---| | 阶段顺序、人机分界、节点菜单 | [05-创作流程领域](domains/05-创作流程领域.md) | -| 这次该加载哪只功能 Skill | [meta/chains/README.md](../../../meta/chains/README.md) | -| 58 只 Skill 挂在哪一段 | [.agent/skills/_index.md](../../../.agent/skills/_index.md) | +| 这次该加载哪只功能 Skill | [meta/chains/README.md](../lifecycle/flow/chains/README.md) | +| 15 只方法 Skill 挂在哪一段 | [.agent/skills/_index.md](../../.agent/skills/_index.md);全量 Skill 位置见 [`skills.json`](../lifecycle/quality/harness/manifests/skills.json) | | 某只 Skill 的输入、红线、工具 | `.agent/skills/<名字>/SKILL.md` | | 方法细节、案例、清单 | 同目录 `references/` | -| 细纲字段 | [meta/schemas/fine_outline.yaml](../../../meta/schemas/fine_outline.yaml) | -| 角色不做什么与探索方法 | [.agent/agents/](../../../.agent/agents/) | +| 细纲字段 | [meta/schemas/fine_outline.yaml](../content/meta/schemas/fine_outline.yaml) | +| 角色不做什么与探索方法 | [.agent/agents/](../../.agent/agents) | | 组件职责边界与约束归属 | [边界合同](边界合同.md) | -| Skill 分类字段含义 | [skill-quality-rubric.md](../../../harness/specs/skill-quality-rubric.md) | +| Skill 分类字段含义 | [skill-quality-rubric.md](../lifecycle/quality/harness/specs/skill-quality-rubric.md) | | 谁拥有作品、实体、范式、上下文 | [领域索引](domains/_index.md) | 领域 SoT 不复制进本文。点过去读,不要在两处同时改同一条规则。 diff --git a/.agent/docs/architecture/可视化模块合同.md b/muse/sot/可视化模块合同.md similarity index 91% rename from .agent/docs/architecture/可视化模块合同.md rename to muse/sot/可视化模块合同.md index d921a30..cab31e8 100644 --- a/.agent/docs/architecture/可视化模块合同.md +++ b/muse/sot/可视化模块合同.md @@ -1,6 +1,6 @@ # 只读可视化模块合同 -> 本文件是只读可视化模块(下称“看板”)的设计 SoT。数据权威、落库原则和可恢复性见 [领域索引](domains/_index.md) §2/§3 与 [08-数据权威与可视化领域](domains/08-数据权威与可视化领域.md);本文件只定义看板这个**只读**模块本身。库内有哪些表、各表现状以 [`db/表映射.md`](../../../db/表映射.md) 为准。 +> 本文件是只读可视化模块(下称“看板”)的设计 SoT。数据权威、落库原则和可恢复性见 [领域索引](domains/_index.md) §2/§3 与 [08-数据权威与可视化领域](domains/08-数据权威与可视化领域.md);本文件只定义看板这个**只读**模块本身。库内有哪些表、各表现状以 [`muse/authority/db/表映射.md`](../authority/db/表映射.md) 为准。 ## 1. 它是什么,不做什么 @@ -8,11 +8,11 @@ - 它只干两件事:对库做**只读查询**,把结果渲染成人能读的页面。 - 它**绝不触发任何写操作**。接受、合并、丢弃、确认这些写,走独立可写通道: - - 候选采纳/丢弃:`dashboard/decision_channel.py`(默认 `:8767`)→ `decide-candidate` / `write_canonical` - - 经验升格人审:`dashboard/lesson_confirm.py`(默认 `:8766`) + - 候选采纳/丢弃:`muse/authority/studio/write/decision/decision_channel.py`(默认 `:8767`)→ `decide-candidate` / `write_canonical` + - 经验升格人审:`muse/authority/studio/write/lesson/lesson_confirm.py`(默认 `:8766`) - **不得**把写操作做进只读看板进程(`:8765`) - 它看到的 = 库里的。看板上空白的地方,就是落库的缺口——所以看板天然是“一切输入产出必须落库”这条纪律的验收面。 -- `/ai-flavor` 也是数据库视图:默认读取 AI 味案例卡与重验证账本表,页面明确标注“候选命中,不是确认结论”;只有数据库不可用时才显示 `dashboard/fixtures/` 中的离线 JSON 回退及原因。其余视图同样以数据库为权威。 +- `/ai-flavor` 也是数据库视图:默认读取 AI 味案例卡与重验证账本表,页面明确标注“候选命中,不是确认结论”;只有数据库不可用时才显示 `muse/authority/studio/read/fixtures/` 中的离线 JSON 回退及原因。其余视图同样以数据库为权威。 - 它服务本机单用户,不做多用户、权限管理、对外分享。 ## 2. 只读硬约束(怎么保证它绝不写) @@ -28,9 +28,9 @@ | 通道 | 端口 | 进程 | 能力 | |---|---|---|---| -| 只读看板 | `:8765` | `dashboard/server.py` | 仅 SELECT 渲染;展示决策菜单文案与命令,不执行 | -| 经验确认 | `:8766` | `dashboard/lesson_confirm.py` | lesson `review` / `promote` / `reject` | -| 候选决策 | `:8767` | `dashboard/decision_channel.py` | 候选 `accept` / `discard` → `write_canonical` | +| 只读看板 | `:8765` | `muse/authority/studio/read/server.py` | 仅 SELECT 渲染;展示决策菜单文案与命令,不执行 | +| 经验确认 | `:8766` | `muse/authority/studio/write/lesson/lesson_confirm.py` | lesson `review` / `promote` / `reject` | +| 候选决策 | `:8767` | `muse/authority/studio/write/decision/decision_channel.py` | 候选 `accept` / `discard` → `write_canonical` | 三条进程物理隔离:可写进程挂了不影响看板;看板进程永不 import 写路径。人在只读页看到「可采纳」后,跳到 `:8767` 点按钮落库。 @@ -51,7 +51,7 @@ | 知识卡(实体与范式) | 草稿卡、已确认卡、按型别与公共/作品分布 | `muse_knowledge_draft`(草稿)/ `muse_knowledge_entity`(已确认)/ `muse_knowledge_base`(库)/ `muse_knowledge_binding`(绑定) | | 参考书与拆书 | 参考书档案、拆书任务状态、逐章脚手架、窗级大纲 | `example_reference_work` / `example_parse_task` / `example_parse_scaffold` / `example_parse_outline` / `muse_knowledge_document`(原文档案指针) | | 清洗审计 | 每次删了哪段原文、为什么、哪个模型、哪一批,可回放 | `example_clean_log` | -| 额度账本 | 5 小时额度窗、花费与调用次数水位 | 额度账本表(`db/ddl/95-example额度账本.sql`) | +| 额度账本 | 5 小时额度窗、花费与调用次数水位 | 额度账本表(`muse/authority/db/ddl/95-example额度账本.sql`) | | 结构本体(框架视图,可选) | 23 型合同、字段、aiContext 控制项、保护节点、功能链 | `muse_meta_schema` / `muse_meta_field` / `muse_meta_visibility_policy` / `muse_meta_protection_node` / `muse_meta_function_chain` | | 写命令审计 | 写命令的幂等审计记录 | `muse_content_command_log` | | AI 味案例回填 | 作品扫描的候选命中、来源哈希/位置、Shadow 状态和复核详情 | `example_ai_flavor_case`(检测命令自动写入) | @@ -66,7 +66,7 @@ | 事实增量 | 候选提出的类型化增量(proposed/accepted/rejected)与已进账本的变更流 | `example_fact_delta` / `example_fact_ledger`(106,接受候选同事务写入) | | 投影登记 | 摘要/抽取/embedding 等投影的 pending/completed/failed/stale 与重试 | `example_projection_run`(107,接受候选同事务登记) | | 经验升格 | lesson/win 证据与 proposed→reviewing→promoted/rejected 流转 | `example_lesson`(108,`lesson_registry` 写);看板只读 `/lessons`;人审写库走确认通道 `:8766` | -| 候选人审决策(可写通道) | 采纳 / 丢弃按钮 → `write_canonical` | `dashboard/decision_channel.py`(默认 `:8767`);**不进**只读看板进程 | +| 候选人审决策(可写通道) | 采纳 / 丢弃按钮 → `write_canonical` | `muse/authority/studio/write/decision/decision_channel.py`(默认 `:8767`);**不进**只读看板进程 | ### 4.2 待落库 / 待建视图 @@ -113,7 +113,7 @@ ## 9. 待建(实现期,按依赖排序) 1. 落库表分两类:**运行注册 / 运行回执 / 质量评判(98)与模型调用(97)已建**,但写路径未接通,视图暂空;候选 / 用户决策 / raw 全文 / 规划冻结(99/100/101)尚未建。没有它们 §4.2 的视图就是空的。 -2. `db/ddl/96` 授权快照表**决定不启用**(领域索引 §9,单用户本地不做多租户授权),DDL 留存不 apply。 +2. `muse/authority/db/ddl/96` 授权快照表**决定不启用**(领域索引 §9,单用户本地不做多租户授权),DDL 留存不 apply。 3. 看板首版已建成(总览 / 作品 / 知识库 / 质量证据 / 智能体 / 运行记录六空间,只读 HTTP + §4.1 部分视图 + 待落库占位格;AI 味案例查 104 三表;智能体空间读 102 登记表;运行记录含按作品/按角色双维 + 运行详情下钻);待建 = 作品/章工作区标签、沿来源下钻链(raw 下钻依赖 101)。页面与信息架构见 §10。 ## 10. 页面与信息架构(产品形态 SoT) @@ -226,7 +226,7 @@ AI 味案例的固定入口是 `/ai-flavor`。列表按作品、模式分页, **智能体页的 ⚠ 来源(A 方案,2026-07-30 拍板)**:角色画像 / 可配置项 / 技能合同在 Git 侧(`.agent/agents/`、`.agent/skills/`),库里没有。看板只读库,故新增**智能体/技能登记表**(`example_agent_role` + `example_skill`,设计见落库设计稿),把角色、模型归属、可配置项、技能读写合同**登记入库**——智能体配置也纳入留痕,看板只读这张表。 -**分阶段点亮(认)**:首版实现为六空间(总览 / 作品 / 知识库 / 质量证据 / 智能体 / 运行记录,见 §9.3;智能体空间读 102 登记表 `example_agent_role`/`example_skill`,登记表由 `.agent/skills/access-database/scripts/sync_agent_registry.py` 从 Git 侧同步,Git 仍是配置权威)。作品工作区**先上 [章节]**(正文已有),其余标签(大纲/细纲/设定/叙事状态、章工作区的细纲与出场卡)随对应表落库(规划表、候选表,落库设计稿第 3/2 步)逐格点亮;点亮前显示"待落库"占位,不假装已有。 +**分阶段点亮(认)**:首版实现为六空间(总览 / 作品 / 知识库 / 质量证据 / 智能体 / 运行记录,见 §9.3;智能体空间读 102 登记表 `example_agent_role`/`example_skill`,登记表由 `muse/authority/evidence/skills/access-database/scripts/sync_agent_registry.py` 从 Git 侧同步,Git 仍是配置权威)。作品工作区**先上 [章节]**(正文已有),其余标签(大纲/细纲/设定/叙事状态、章工作区的细纲与出场卡)随对应表落库(规划表、候选表,落库设计稿第 3/2 步)逐格点亮;点亮前显示"待落库"占位,不假装已有。 ### 10.2 UI 形态 @@ -245,11 +245,11 @@ AI 味案例的固定入口是 `/ai-flavor`。列表按作品、模式分页, ### 10.4 其他可视化场景(已纳入 / 暂缓) - 已纳入:输入侧(参考书·拆书·清洗)、运营侧(额度水位)、落库健康(首页账本)、结构本体(知识库空间次级)、智能体/技能登记(智能体空间,读登记表)。 -- 次要、暂不上树:升级审计(`db/ddl/94` 五表)、导入审计(`muse_content_import_task`)——属审计面,需要时再给入口。 +- 次要、暂不上树:升级审计(`muse/authority/db/ddl/94` 五表)、导入审计(`muse_content_import_task`)——属审计面,需要时再给入口。 - 暂缓(二期,依赖待落库表):质量与复利的跨运行聚合(评分趋势 / 经验升格观察,是视图层)。 ## 11. 关联 SoT - 数据权威、落库合同、可恢复性:[领域索引](domains/_index.md) §2/§3、[08-数据权威与可视化领域](domains/08-数据权威与可视化领域.md) -- 库内表清单与现状:[`db/表映射.md`](../../../db/表映射.md) +- 库内表清单与现状:[`muse/authority/db/表映射.md`](../authority/db/表映射.md) - 形态参照:open-wenmo(纯标准库 hub + 门禁) diff --git a/.agent/docs/architecture/角色合同.md b/muse/sot/角色合同.md similarity index 100% rename from .agent/docs/architecture/角色合同.md rename to muse/sot/角色合同.md diff --git a/.agent/docs/architecture/边界合同.md b/muse/sot/边界合同.md similarity index 97% rename from .agent/docs/architecture/边界合同.md rename to muse/sot/边界合同.md index 85515cf..5e7fae3 100644 --- a/.agent/docs/architecture/边界合同.md +++ b/muse/sot/边界合同.md @@ -26,6 +26,7 @@ | 输入输出格式 | 静态层(schema 校验) | 模型调用前后拒绝 | | 状态推进、数据库写 | 脚本层 + 数据库约束 | CAS、触发器、事务 | | 模块依赖、目录纪律 | 架构门禁(测试) | 失败关闭 | +| Agent 宿主调用、任务包与事件归一 | `framework/` | 业务 Skill 不直接碰宿主二进制;适配器只消费可移植任务包 | | 业务继续/停止(补证、重写次数) | 主代理向人请求授权 | 授权终态;脚本只保留技术保护(超时、预算、取消) | 判定原则:**模型能被说服的用提示词;模型不能碰的用工具白名单;不允许出错的用脚本与静态校验。** 主代理不承载任何创作约束,只传递人的意图。 diff --git a/requirements.txt b/requirements.txt index 952aa5a..f1c0d31 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,7 +7,7 @@ pyyaml click json-repair jsonschema>=4.23,<5 --e ./muse-db --e ./muse-llm --e ./muse-embed --e ./humanization +-e ./muse/platform/db +-e ./muse/platform/llm +-e ./muse/platform/embed +-e ./muse/lifecycle/quality/humanization diff --git a/tests/architecture/test_dsh_adapter.py b/tests/architecture/test_dsh_adapter.py new file mode 100644 index 0000000..206ff21 --- /dev/null +++ b/tests/architecture/test_dsh_adapter.py @@ -0,0 +1,230 @@ +"""DSH headless 适配器的离线合同测试。""" + +from __future__ import annotations + +import json +import pathlib +import tempfile +import unittest + +from jsonschema import Draft202012Validator + +ROOT = next( + parent + for parent in (pathlib.Path(__file__).resolve().parent, *pathlib.Path(__file__).resolve().parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +if str(ROOT) not in __import__("sys").path: + __import__("sys").path.insert(0, str(ROOT)) + +from framework.adapters.dsh.normalization import ( # noqa: E402 + DshNormalizationError, + normalize_dsh_session, +) +from framework.adapters.dsh.runner import ( # noqa: E402 + DshError, + DshExecutionPolicy, + DshHeadlessRunner, + DshProcessResult, + build_dsh_argv, + build_dsh_patch, +) +from framework.primitives.artifacts import read_jsonl # noqa: E402 +from framework.primitives.execution import FrameworkExecutionRequest # noqa: E402 + + +SESSION_LINES = [ + { + "type": "session", + "version": 0, + "id": "session-test-1", + "createdAt": 1, + "cwd": "/tmp/work", + "delegationDepth": 0, + }, + { + "type": "request/header", + "data": { + "header": {"config": {"provider": "probe", "model": "probe-model"}}, + "reason": "initial", + }, + }, + {"type": "request/context", "data": {"provider": "probe", "model": "probe-model"}}, + {"type": "turn/start", "data": {"turn": 1}}, + {"type": "step/start", "data": {"turn": 1, "step": 1}}, + { + "type": "user/message", + "data": { + "content": [{"type": "text", "text": "task"}], + "source": {"kind": "user"}, + "role": "user", + }, + }, + { + "type": "assistant/chunk", + "data": { + "turn": 1, + "step": 1, + "chunk": {"type": "finish", "reason": {"kind": "stop"}}, + }, + }, + { + "type": "assistant/message", + "data": { + "turn": 1, + "step": 1, + "message": { + "role": "assistant", + "content": [{"type": "text", "text": '{"ok":true}'}], + "source": {"kind": "model", "provider": "probe", "model": "probe-model"}, + }, + "usage": {"inputTokens": 4, "outputTokens": 2, "costUsd": 0.01}, + }, + }, + {"type": "tool/call", "data": {"turn": 1, "step": 1, "callId": "c1", "name": "read", "arguments": '{"path":"x"}'}}, + { + "type": "tool/result", + "data": { + "turn": 1, + "step": 1, + "message": { + "source": {"kind": "tool", "callId": "c1"}, + "content": [{"type": "tool-result", "content": [{"type": "text", "text": "ok"}], "isError": False}], + }, + }, + }, + {"type": "step/end", "data": {"turn": 1, "step": 1}}, + {"type": "turn/end", "data": {"turn": 1, "reason": {"kind": "completed"}}}, + {"type": "future/new-event", "data": {"opaque": True}}, +] + + +class RecordingSink: + def __init__(self) -> None: + self.rows: list[tuple[str, dict]] = [] + + def emit(self, event_type: str, **kwargs): + self.rows.append((event_type, kwargs)) + return len(self.rows) + + +class DshAdapterTest(unittest.TestCase): + def request(self, *, tools: tuple[str, ...] = (), session_mode: str = "fresh") -> FrameworkExecutionRequest: + return FrameworkExecutionRequest( + system_prompt="system", + user_content="task", + tool_allowlist=tools, + session_mode=session_mode, + ) + + def write_session(self, root: pathlib.Path) -> pathlib.Path: + path = root / "--tmp-work--" / "session-test-1" / "session.jsonl" + path.parent.mkdir(parents=True) + path.write_text( + "".join(json.dumps(line, ensure_ascii=False) + "\n" for line in SESSION_LINES), + encoding="utf-8", + ) + return path + + def test_normalize_session_preserves_unknown_and_builds_artifact(self): + with tempfile.TemporaryDirectory() as directory: + root = pathlib.Path(directory) + source = self.write_session(root / "source") + artifact = root / "framework-events.jsonl" + outcome = normalize_dsh_session(source, artifact, run_id="run-1", framework_version="0.1.1-rc.2") + self.assertEqual(outcome.session_id, "session-test-1") + self.assertEqual(outcome.final_text, '{"ok":true}') + self.assertEqual(outcome.model_calls[0].actual_model_id, "probe/probe-model") + self.assertEqual(outcome.model_calls[0].cost_usd, 0.01) + self.assertEqual(outcome.tool_calls[0].args, {"path": "x"}) + self.assertEqual(outcome.turns, 1) + self.assertEqual(outcome.unknown_event_types, ("future/new-event",)) + events = read_jsonl(artifact) + self.assertEqual(len(events), len(SESSION_LINES)) + self.assertEqual(events[-1]["kind"], "unknown") + self.assertEqual(events[-1]["runId"], "run-1") + self.assertTrue(outcome.artifact_sha256.startswith("sha256:")) + + def test_compressed_session_fails_closed(self): + with tempfile.TemporaryDirectory() as directory: + root = pathlib.Path(directory) + source = root / "session.jsonl.zstd" + source.write_bytes(b"not used") + with self.assertRaisesRegex(DshNormalizationError, "COMPRESSED_ARTIFACT_UNSUPPORTED"): + normalize_dsh_session(source, root / "events.jsonl") + + def test_patch_and_argv_are_explicit_and_toolless(self): + policy = DshExecutionPolicy(provider="probe", model="probe-model", cwd="/tmp/work") + patch = build_dsh_patch(self.request(), policy, session_root="/tmp/session-root") + rows = {row["id"]: row for row in patch} + self.assertEqual(rows["agent-default-model"]["config"], {"provider": "probe", "model": "probe-model"}) + self.assertEqual(rows["session-persistence-jsonl"]["config"]["compression"], "none") + self.assertTrue(rows["tool-fs"]["disabled"]) + argv = build_dsh_argv(self.request(), policy, "/tmp/patch.json") + self.assertEqual(argv[:4], ["dsh", "--profile", "headless", "--patch"]) + self.assertEqual(pathlib.Path(argv[4]).name, "patch.json") + self.assertEqual(argv[-2], "--") + self.assertEqual(argv[-1], "task") + + def test_nonempty_tools_and_continue_fail_before_launch(self): + policy = DshExecutionPolicy(provider="p", model="m") + with self.assertRaises(DshError) as tool_error: + build_dsh_argv(self.request(tools=("read",)), policy, "/tmp/p.json") + self.assertEqual(tool_error.exception.error_code, "DSH_TOOL_POLICY_UNSUPPORTED") + with self.assertRaises(DshError) as session_error: + build_dsh_argv(self.request(session_mode="continue"), policy, "/tmp/p.json") + self.assertEqual(session_error.exception.error_code, "DSH_SESSION_CONTINUE_UNSUPPORTED") + + def test_runner_uses_flushed_session_as_result(self): + with tempfile.TemporaryDirectory() as directory: + root = pathlib.Path(directory) + + def launcher(argv, _timeout, _cwd, _env): + patch_path = pathlib.Path(argv[argv.index("--patch") + 1]) + patch = json.loads(patch_path.read_text(encoding="utf-8")) + session_root = pathlib.Path( + next(row for row in patch if row["id"] == "session-persistence-jsonl")["config"]["root"] + ) + self.write_session(session_root) + return DshProcessResult(returncode=0, stdout=b"ignored stdout\n") + + sink = RecordingSink() + outcome = DshHeadlessRunner(launcher=launcher, framework_version="0.1.1-rc.2").run( + self.request(), + DshExecutionPolicy(provider="probe", model="probe-model", cwd="/tmp/work"), + sink, + artifact_dir=root / "run", + run_id="run-1", + ) + self.assertEqual(outcome.final_text, '{"ok":true}') + self.assertEqual(outcome.session_id, "session-test-1") + self.assertEqual([row[0] for row in sink.rows], [ + "agent.started", "model.completed", "tool.completed", "agent.completed" + ]) + result = outcome.as_framework_result().as_dict() + schema = json.loads((ROOT / "framework/primitives/schemas/framework_execution_result.schema.json").read_text(encoding="utf-8")) + Draft202012Validator(schema).validate(result) + self.assertEqual(result["status"], "completed") + self.assertEqual(result["requestedModel"], "probe/probe-model") + self.assertTrue((root / "run/framework-events.jsonl").is_file()) + + def test_runner_propagates_process_failure(self): + with tempfile.TemporaryDirectory() as directory: + sink = RecordingSink() + + def launcher(_argv, _timeout, _cwd, _env): + return DshProcessResult(returncode=1, stderr=b"MISSING_CREDENTIAL: sk-secret-token-123456") + + with self.assertRaises(DshError) as context: + DshHeadlessRunner(launcher=launcher).run( + self.request(), + DshExecutionPolicy(provider="probe", model="probe-model"), + sink, + artifact_dir=directory, + ) + self.assertEqual(context.exception.error_code, "DSH_EXIT_NONZERO") + self.assertNotIn("sk-secret", str(context.exception)) + + +if __name__ == "__main__": + unittest.main(verbosity=2) diff --git a/tests/architecture/test_framework_port_purity.py b/tests/architecture/test_framework_port_purity.py new file mode 100644 index 0000000..92f01f5 --- /dev/null +++ b/tests/architecture/test_framework_port_purity.py @@ -0,0 +1,43 @@ +"""框架端口纯度门:framework 不得反向依赖 Muse 业务实现。""" + +from __future__ import annotations + +import pathlib +import re +import unittest + + +ROOT = next( + parent + for parent in (pathlib.Path(__file__).resolve().parent, *pathlib.Path(__file__).resolve().parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +FORBIDDEN_IMPORTS = ( + "agent_trace", + "muse_role", + "muse_role_contract", + "muse_db", + "psycopg", + "fixed-opus", +) + + +class FrameworkPortPurityTest(unittest.TestCase): + def test_framework_does_not_import_muse_runtime_contracts(self) -> None: + offenders: list[str] = [] + pattern = re.compile( + r"(?:from|import)\s+(?:" + "|".join(map(re.escape, FORBIDDEN_IMPORTS)) + r")\b" + ) + for path in (ROOT / "framework").rglob("*"): + if not path.is_file() or "__pycache__" in path.parts: + continue + if path.suffix not in {".py", ".ts", ".md"}: + continue + text = path.read_text(encoding="utf-8") + if pattern.search(text): + offenders.append(path.relative_to(ROOT).as_posix()) + self.assertEqual(offenders, [], "framework 反向依赖 Muse 业务合同或运行时:\n" + "\n".join(offenders)) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/architecture/test_framework_protocol.py b/tests/architecture/test_framework_protocol.py new file mode 100644 index 0000000..09b64aa --- /dev/null +++ b/tests/architecture/test_framework_protocol.py @@ -0,0 +1,122 @@ +"""框架协议与运行工件的离线合同测试。""" + +from __future__ import annotations + +import json +import pathlib +import tempfile +import sys +import unittest + +from jsonschema import Draft202012Validator + +ROOT = next( + parent + for parent in (pathlib.Path(__file__).resolve().parent, *pathlib.Path(__file__).resolve().parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +if str(ROOT) not in sys.path: + sys.path.insert(0, str(ROOT)) + +from framework.adapters.pi.normalization import normalize_pi_transcript +from framework.primitives.artifacts import ( + ArtifactError, + detect_seq_gaps, + read_jsonl, + write_jsonl_atomic, +) +from framework.primitives.execution import ( + FrameworkEvent, + FrameworkExecutionRequest, + FrameworkExecutionResult, +) + + +SCHEMA_DIR = ROOT / "framework" / "primitives" / "schemas" + + +class FrameworkProtocolTest(unittest.TestCase): + def test_schemas_are_valid_draft_2020_documents(self) -> None: + for path in sorted(SCHEMA_DIR.glob("*.schema.json")): + with self.subTest(path=path.name): + document = json.loads(path.read_text(encoding="utf-8")) + Draft202012Validator.check_schema(document) + + def test_request_has_no_business_state_fields(self) -> None: + request = FrameworkExecutionRequest( + system_prompt="system", + user_content="user", + tool_allowlist=("read",), + ) + self.assertEqual(request.session_mode, "fresh") + self.assertFalse(hasattr(request, "work_id")) + self.assertFalse(hasattr(request, "candidate_status")) + request_schema = json.loads((SCHEMA_DIR / "framework_execution_request.schema.json").read_text(encoding="utf-8")) + Draft202012Validator(request_schema).validate(request.as_dict()) + + event = FrameworkEvent( + framework="pi", + framework_version="test", + session_id="s1", + source_seq=1, + kind="agent", + phase="completed", + observed_at="2026-08-24T00:00:00Z", + ) + event_schema = json.loads((SCHEMA_DIR / "framework_event.schema.json").read_text(encoding="utf-8")) + Draft202012Validator(event_schema).validate(event.as_dict()) + result = FrameworkExecutionResult( + status="completed", final_text="{}", requested_model="p/m" + ) + result_schema = json.loads((SCHEMA_DIR / "framework_execution_result.schema.json").read_text(encoding="utf-8")) + Draft202012Validator(result_schema).validate(result.as_dict()) + + def test_pi_transcript_produces_common_events_and_preserves_unknown_type(self) -> None: + with tempfile.TemporaryDirectory() as directory: + source = pathlib.Path(directory) / "pi.jsonl" + target = pathlib.Path(directory) / "framework-events.jsonl" + source.write_text( + json.dumps({"type": "session", "id": "s1"}) + "\n" + + json.dumps({"type": "future_event", "payload": "not copied"}) + "\n", + encoding="utf-8", + ) + result = normalize_pi_transcript(source, target, run_id="run-1", framework_version="test") + self.assertEqual(result["unknownEventTypes"], ["future_event"]) + normalized = read_jsonl(target) + self.assertEqual([event["sourceSeq"] for event in normalized], [1, 2]) + self.assertEqual(normalized[1]["kind"], "unknown") + self.assertNotIn("payload", normalized[1]["safeDetails"]) + + def test_artifact_flush_replay_and_gap_detection(self) -> None: + events = [ + { + "framework": "pi", + "frameworkVersion": "test", + "sessionId": "s1", + "sourceSeq": 1, + "kind": "session", + "phase": "started", + "safeDetails": {}, + }, + { + "framework": "pi", + "frameworkVersion": "test", + "sessionId": "s1", + "sourceSeq": 2, + "kind": "agent", + "phase": "completed", + "safeDetails": {}, + }, + ] + with tempfile.TemporaryDirectory() as directory: + path = pathlib.Path(directory) / "transcript.jsonl" + digest = write_jsonl_atomic(path, events) + self.assertTrue(digest.startswith("sha256:")) + self.assertEqual(read_jsonl(path), events) + self.assertEqual(detect_seq_gaps([events[0], {**events[1], "sourceSeq": 4}]), [(2, 3)]) + with self.assertRaises(ArtifactError): + write_jsonl_atomic(path, [{**events[0], "sourceSeq": 2}]) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/architecture/test_import_boundaries.py b/tests/architecture/test_import_boundaries.py index 095d0aa..c05f7df 100644 --- a/tests/architecture/test_import_boundaries.py +++ b/tests/architecture/test_import_boundaries.py @@ -5,7 +5,7 @@ muse-deai),调用方 import 已安装的包。角色执行模块 muse_role 随 muse-llm 安装。 拥有该实现的 Skill 自己的 scripts/ 不受限(CLI 与库同属一个能力域)。 -扫描范围只含 .agent/skills 与 dashboard;测试、humanization/tests/tools/eval 不在范围内。 +扫描范围包含 `.agent/skills`、`framework`、`muse` 和当前运行时入口;测试、humanization/tests/tools/eval 不在范围内。 """ from __future__ import annotations @@ -13,21 +13,30 @@ import pathlib import re import unittest -ROOT = pathlib.Path(__file__).resolve().parents[2] -SKILLS = ROOT / ".agent" / "skills" -DASHBOARD = ROOT / "dashboard" -ACTIVE_RUNTIME_ROOTS = ( - ROOT / ".agent" / "skills", - ROOT / "dashboard", - ROOT / "harness", - ROOT / "muse-llm", - ROOT / "muse-embed", - ROOT / "docs" / "write-chapter", +def _find_project_root(start: pathlib.Path) -> pathlib.Path: + resolved = start.resolve() + for directory in (resolved, *resolved.parents): + if (directory / "AGENTS.md").is_file() and (directory / ".git").exists(): + return directory + raise RuntimeError(f"无法从 {start} 向上找到项目根") + + +ROOT = _find_project_root(pathlib.Path(__file__)) +SKILL_SCAN_ROOTS = (pathlib.Path(".agent") / "skills", pathlib.Path("muse")) +DASHBOARD_ROOTS = (pathlib.Path("muse") / "authority" / "studio" / "read",) +ACTIVE_RUNTIME_RELATIVE_ROOTS = ( + pathlib.Path(".agent") / "skills", + pathlib.Path("framework"), + pathlib.Path("muse"), + pathlib.Path("muse") / "lifecycle" / "quality" / "harness", + pathlib.Path("muse") / "platform" / "llm", + pathlib.Path("muse") / "platform" / "embed", + pathlib.Path("docs") / "write-chapter", ) -# 框架派发接缝:唯一允许直接调用 Agent 框架二进制的适配器文件(dispatch-agent-task)。 -# 新增框架适配器(codex/opencode…)必须挂在本 Skill scripts/ 下并在此登记。 +# 框架派发接缝:允许直接调用 Agent 框架二进制的适配器文件。 +# 新增框架适配器(codex/opencode…)必须在此登记,并保持独立于 Muse 业务。 FRAMEWORK_ADAPTER_ALLOWLIST = frozenset( - {".agent/skills/dispatch-agent-task/scripts/pi_runner.py"} + {"framework/adapters/pi/runner.py", "framework/adapters/dsh/runner.py"} ) FORBIDDEN_CLAUDE_RUNTIME_TOKENS = ( "claude_runtime", @@ -63,10 +72,9 @@ class ImportBoundaryTest(unittest.TestCase): for path, replacement, owner in FORBIDDEN_PATHS: with self.subTest(path=path): pattern = _path_pattern(path) - prefix = f".agent/skills/{owner}/" if owner else None offenders = [ rel for rel in self._skill_files() - if not (prefix and rel.startswith(prefix)) + if not (owner and owner in pathlib.Path(rel).parts) and pattern.search((ROOT / rel).read_text(encoding="utf-8")) ] self.assertEqual( @@ -78,17 +86,18 @@ class ImportBoundaryTest(unittest.TestCase): def test_dashboard_does_not_import_skills(self): offenders: list[str] = [] - for path in DASHBOARD.rglob("*.py"): - if path.name.startswith("test_"): - continue - text = path.read_text(encoding="utf-8") - rel = str(path.relative_to(ROOT)) - if re.search(r"sys\.path", text) and ".agent/skills" in text: - offenders.append(rel) - if re.search(r"^from db import|^import db\b", text, re.M): - offenders.append(rel) - if re.search(r"\b(muse_llm|muse_role|deai)\b", text): - offenders.append(rel) + for relative_root in DASHBOARD_ROOTS: + for path in (ROOT / relative_root).rglob("*.py"): + if path.name.startswith("test_"): + continue + text = path.read_text(encoding="utf-8") + rel = str(path.relative_to(ROOT)) + if re.search(r"sys\.path", text) and ".agent/skills" in text: + offenders.append(rel) + if re.search(r"^from db import|^import db\b", text, re.M): + offenders.append(rel) + if re.search(r"\b(muse_llm|muse_role|deai)\b", text): + offenders.append(rel) self.assertEqual( offenders, [], @@ -98,7 +107,8 @@ class ImportBoundaryTest(unittest.TestCase): def test_active_runtime_has_no_claude_cli_dependency(self): offenders: list[str] = [] suffixes = {".py", ".json", ".yaml", ".yml", ".toml", ".md"} - for root in ACTIVE_RUNTIME_ROOTS: + for relative_root in ACTIVE_RUNTIME_RELATIVE_ROOTS: + root = ROOT / relative_root for path in root.rglob("*"): if ( not path.is_file() @@ -116,9 +126,10 @@ class ImportBoundaryTest(unittest.TestCase): # 其余任何位置 shell 调模型/框架 CLI 仍被阻断。 if rel in FRAMEWORK_ADAPTER_ALLOWLIST: continue - if re.search( + if path.suffix == ".py" and re.search( r"(?:/bin/claude|[\"']claude[\"']\s*,\s*[\"']--version|" - r"[\"']pi[\"']\s*,|\bpi\s+--model)", + r"[\"'](?:pi|dsh)[\"']\s*,\s*[\"']--(?:model|profile|version)|" + r"\b(?:pi|dsh)\s+--(?:model|profile|version))", text, ): offenders.append(rel) @@ -132,7 +143,8 @@ class ImportBoundaryTest(unittest.TestCase): def test_active_runtime_has_no_embedded_api_token(self): offenders: list[str] = [] token_pattern = re.compile(r"sk-[A-Za-z0-9]{20,}") - for root in ACTIVE_RUNTIME_ROOTS: + for relative_root in ACTIVE_RUNTIME_RELATIVE_ROOTS: + root = ROOT / relative_root for path in root.rglob("*"): if not path.is_file() or "__pycache__" in path.parts or "artifacts" in path.parts: continue @@ -149,7 +161,13 @@ class ImportBoundaryTest(unittest.TestCase): ) def _skill_files(self) -> list[str]: - return sorted(p.relative_to(ROOT).as_posix() for p in SKILLS.rglob("*.py")) + files: set[str] = set() + for relative_root in SKILL_SCAN_ROOTS: + scan_root = ROOT / relative_root + for skill_md in scan_root.rglob("SKILL.md"): + for path in skill_md.parent.rglob("*.py"): + files.add(path.relative_to(ROOT).as_posix()) + return sorted(files) if __name__ == "__main__": diff --git a/tests/architecture/test_markdown_links.py b/tests/architecture/test_markdown_links.py new file mode 100644 index 0000000..fb83f59 --- /dev/null +++ b/tests/architecture/test_markdown_links.py @@ -0,0 +1,48 @@ +"""活入口、SoT 与框架文档的 Markdown 链接死链门。""" + +from __future__ import annotations + +import pathlib +import re +import unittest +import urllib.parse + + +ROOT = next( + parent + for parent in (pathlib.Path(__file__).resolve().parent, *pathlib.Path(__file__).resolve().parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +LINK = re.compile(r"\[[^\]\n]*\]\(([^)\s]+)") + + +class MarkdownLinkTest(unittest.TestCase): + def test_active_markdown_links_resolve(self) -> None: + roots = [ + ROOT / "AGENTS.md", + ROOT / "README.md", + ROOT / ".agent", + ROOT / "framework", + ROOT / "muse", + ROOT / "docs", + ] + missing: list[str] = [] + for root in roots: + files = [root] if root.is_file() else list(root.rglob("*.md")) + for source in files: + relative = source.relative_to(ROOT).as_posix() + if relative.startswith("docs/plans/") or "/artifacts/" in relative: + continue + if relative.startswith("framework/catalog/"): + continue + for raw_target in LINK.findall(source.read_text(encoding="utf-8")): + target = urllib.parse.unquote(raw_target.strip("<>").split("#", 1)[0]) + if not target or target.startswith(("#", "http://", "https://", "mailto:", "/")): + continue + if not (source.parent / target).resolve().exists(): + missing.append(f"{relative}: {raw_target}") + self.assertEqual(missing, [], "Markdown 链接目标不存在:\n" + "\n".join(missing)) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/architecture/test_skill_projections.py b/tests/architecture/test_skill_projections.py new file mode 100644 index 0000000..3b981a0 --- /dev/null +++ b/tests/architecture/test_skill_projections.py @@ -0,0 +1,77 @@ +"""Pi/DSH 扁平 Skill 投影与 Muse manifest 对账门。""" + +from __future__ import annotations + +import hashlib +import json +import pathlib +import re +import unittest +import urllib.parse + + +ROOT = next( + parent + for parent in (pathlib.Path(__file__).resolve().parent, *pathlib.Path(__file__).resolve().parents) + if (parent / "AGENTS.md").is_file() and (parent / ".git").exists() +) +MANIFEST = ROOT / "muse" / "lifecycle" / "quality" / "harness" / "manifests" / "skills.json" +CATALOG = ROOT / "framework" / "catalog" +MARKDOWN_LINK = re.compile(r"\[[^\]\n]*\]\(([^)\s]+)") + + +class SkillProjectionTest(unittest.TestCase): + def test_projection_is_flat_and_same_source(self) -> None: + manifest = json.loads(MANIFEST.read_text(encoding="utf-8")) + expected = { + entry["name"]: entry["skill_path"] + for entry in manifest["skills"] + if entry.get("invocation") == "model_routed" + } + catalog = json.loads((CATALOG / "catalog.json").read_text(encoding="utf-8")) + self.assertEqual(set(catalog["skills"]), set(expected)) + for name, metadata in catalog["skills"].items(): + source = ROOT / expected[name] + source_text = source.read_text(encoding="utf-8") + digest = "sha256:" + hashlib.sha256(source_text.encode("utf-8")).hexdigest() + self.assertEqual(metadata["sha256"], digest) + for target in ("dsh", "pi"): + projected = ROOT / metadata[target] + self.assertEqual(projected.parent.parent.name, "skills") + self.assertEqual(projected.read_text(encoding="utf-8"), source_text) + source_references = source.parent / "references" + projected_references = projected.parent / "references" + if source_references.is_dir(): + self.assertEqual( + sorted(path.relative_to(source_references).as_posix() for path in source_references.rglob("*")), + sorted(path.relative_to(projected_references).as_posix() for path in projected_references.rglob("*")), + ) + + def test_projected_reference_links_resolve(self) -> None: + missing: list[str] = [] + for target in ("dsh", "pi"): + for source in (CATALOG / target / "skills").rglob("*.md"): + for raw_target in MARKDOWN_LINK.findall(source.read_text(encoding="utf-8")): + target_path = urllib.parse.unquote( + raw_target.strip("<>").split("#", 1)[0] + ) + if not target_path or target_path.startswith( + ("#", "http://", "https://", "mailto:", "/") + ): + continue + if not (source.parent / target_path).resolve().exists(): + missing.append(f"{source.relative_to(ROOT)}: {raw_target}") + self.assertEqual(missing, [], "Skill 投影存在死链:\n" + "\n".join(missing)) + + def test_orchestrated_skill_is_not_projected(self) -> None: + projected_names = { + path.parent.name + for target in ("dsh", "pi") + for path in (ROOT / "framework" / "catalog" / target / "skills").glob("*/SKILL.md") + } + self.assertNotIn("decide-candidate", projected_names) + self.assertNotIn("record-run-evidence", projected_names) + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/architecture/test_skills_index.py b/tests/architecture/test_skills_index.py index 4e268e1..8c19df4 100644 --- a/tests/architecture/test_skills_index.py +++ b/tests/architecture/test_skills_index.py @@ -1,10 +1,10 @@ #!/usr/bin/env python3 """门禁:`.agent/skills/_index.md` 必须与磁盘 skills、frontmatter、skills.json 一致。 -总索引是生成物(`harness/skills_index.py`):skill_name / skill_file 来自磁盘与 -`harness/manifests/skills.json`,skill_description 来自 SKILL.md frontmatter(SoT)。 +总索引是生成物(`muse/lifecycle/quality/harness/skills_index.py`):skill_name / skill_file 来自磁盘与 +`muse/lifecycle/quality/harness/manifests/skills.json`,skill_description 来自 SKILL.md frontmatter(SoT)。 skill 增删改名漏同步、手改索引造成的漂移都会被本测试拒绝;修复方式是 -`.venv/bin/python harness/skills_index.py --write`。 +`.venv/bin/python muse/lifecycle/quality/harness/skills_index.py --write`。 """ from __future__ import annotations @@ -21,7 +21,7 @@ class SkillsIndexConsistencyTest(unittest.TestCase): result = subprocess.run( [ sys.executable, - str(ROOT / "harness" / "skills_index.py"), + str(ROOT / "muse" / "lifecycle" / "quality" / "harness" / "skills_index.py"), "--root", str(ROOT), "--check", @@ -32,7 +32,7 @@ class SkillsIndexConsistencyTest(unittest.TestCase): self.assertEqual( result.returncode, 0, - "Skill 总索引与事实漂移,请运行 harness/skills_index.py --write 重新生成:\n" + "Skill 总索引与事实漂移,请运行 muse/lifecycle/quality/harness/skills_index.py --write 重新生成:\n" + result.stdout + result.stderr, ) diff --git a/tests/skills/access-database/test_authorization_snapshot_ddl.py b/tests/skills/access-database/test_authorization_snapshot_ddl.py index 9554592..33d9a16 100644 --- a/tests/skills/access-database/test_authorization_snapshot_ddl.py +++ b/tests/skills/access-database/test_authorization_snapshot_ddl.py @@ -7,7 +7,7 @@ import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -DDL_PATH = PROJECT_ROOT / "db" / "ddl" / "96-example参考作品授权快照.sql" +DDL_PATH = PROJECT_ROOT / "muse" / "authority" / "db" / "ddl" / "96-example参考作品授权快照.sql" class AuthorizationSnapshotDdlTest(unittest.TestCase): diff --git a/tests/skills/access-database/test_db_params.py b/tests/skills/access-database/test_db_params.py index 9aca767..ab44b7d 100644 --- a/tests/skills/access-database/test_db_params.py +++ b/tests/skills/access-database/test_db_params.py @@ -9,7 +9,7 @@ import sys from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parents[3] -SCRIPTS_DIR = PROJECT_ROOT / ".agent" / "skills" / "access-database" / "scripts" +SCRIPTS_DIR = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "access-database" / "scripts" sys.path.insert(0, str(SCRIPTS_DIR)) import click # noqa: E402 diff --git a/tests/skills/access-database/test_skill_catalog.py b/tests/skills/access-database/test_skill_catalog.py index 1bf183f..084b0f1 100644 --- a/tests/skills/access-database/test_skill_catalog.py +++ b/tests/skills/access-database/test_skill_catalog.py @@ -7,7 +7,7 @@ import tempfile import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPTS_DIR = PROJECT_ROOT / ".agent" / "skills" / "access-database" / "scripts" +SCRIPTS_DIR = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "access-database" / "scripts" sys.path.insert(0, str(SCRIPTS_DIR)) from muse_role_contract import load_role_contract_catalog diff --git a/tests/skills/adjudicate-quality-gate/test_gate_input_builder.py b/tests/skills/adjudicate-quality-gate/test_gate_input_builder.py index 1b34650..df057f5 100644 --- a/tests/skills/adjudicate-quality-gate/test_gate_input_builder.py +++ b/tests/skills/adjudicate-quality-gate/test_gate_input_builder.py @@ -10,9 +10,9 @@ import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" -SCRIPT_DIR = SKILLS_DIR / "adjudicate-quality-gate" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "mechanical" / "adjudicate-quality-gate" / "scripts" TEST_DIR = PROJECT_ROOT / "tests" / "skills" / "adjudicate-quality-gate" -QUALITY_GATE_DIR = SKILLS_DIR / "score-content-quality" / "scripts" +QUALITY_GATE_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "judge" / "score-content-quality" / "scripts" for _import_dir in (SCRIPT_DIR, TEST_DIR, QUALITY_GATE_DIR): if str(_import_dir) not in sys.path: sys.path.insert(0, str(_import_dir)) diff --git a/tests/skills/adjudicate-quality-gate/test_writer_gate.py b/tests/skills/adjudicate-quality-gate/test_writer_gate.py index c720406..66692c2 100644 --- a/tests/skills/adjudicate-quality-gate/test_writer_gate.py +++ b/tests/skills/adjudicate-quality-gate/test_writer_gate.py @@ -12,10 +12,10 @@ import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" -SCRIPT_DIR = SKILLS_DIR / "adjudicate-quality-gate" / "scripts" -WRITER_REPLAY_DIR = SKILLS_DIR / "replay-writer-gate" / "scripts" -QUALITY_GATE_DIR = SKILLS_DIR / "score-content-quality" / "scripts" -EVIDENCE_DIR = SKILLS_DIR / "record-run-evidence" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "mechanical" / "adjudicate-quality-gate" / "scripts" +WRITER_REPLAY_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "replay" / "replay-writer-gate" / "scripts" +QUALITY_GATE_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "judge" / "score-content-quality" / "scripts" +EVIDENCE_DIR = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" for _import_dir in (SCRIPT_DIR, WRITER_REPLAY_DIR, QUALITY_GATE_DIR, EVIDENCE_DIR): if str(_import_dir) not in sys.path: sys.path.insert(0, str(_import_dir)) diff --git a/tests/skills/assemble-context/test_assemble_writer_context.py b/tests/skills/assemble-context/test_assemble_writer_context.py index 22ffc7a..c015804 100644 --- a/tests/skills/assemble-context/test_assemble_writer_context.py +++ b/tests/skills/assemble-context/test_assemble_writer_context.py @@ -10,7 +10,7 @@ import sys import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "assemble-context" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) from assemble_writer_context import ( # noqa: E402 diff --git a/tests/skills/assemble-context/test_fine_outline_reader.py b/tests/skills/assemble-context/test_fine_outline_reader.py index ce9697a..e457cbe 100644 --- a/tests/skills/assemble-context/test_fine_outline_reader.py +++ b/tests/skills/assemble-context/test_fine_outline_reader.py @@ -6,7 +6,7 @@ import sys import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "assemble-context" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) from retrieve_writer_sources import RetrievalError, load_confirmed_fine_outline # noqa: E402 diff --git a/tests/skills/assemble-context/test_fine_outline_unification.py b/tests/skills/assemble-context/test_fine_outline_unification.py index c5de0d0..f762f23 100644 --- a/tests/skills/assemble-context/test_fine_outline_unification.py +++ b/tests/skills/assemble-context/test_fine_outline_unification.py @@ -15,7 +15,7 @@ import sys import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "assemble-context" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) from assemble_writer_context import AssemblyError, _outline_contract # noqa: E402 diff --git a/tests/skills/assemble-context/test_freeze_lesson_offline.py b/tests/skills/assemble-context/test_freeze_lesson_offline.py index 2526515..a488e99 100644 --- a/tests/skills/assemble-context/test_freeze_lesson_offline.py +++ b/tests/skills/assemble-context/test_freeze_lesson_offline.py @@ -9,8 +9,8 @@ import unittest from unittest.mock import patch ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT = ROOT / ".agent" / "skills" / "assemble-context" / "scripts" -EVIDENCE = ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +SCRIPT = ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" +EVIDENCE = ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" for path in (SCRIPT, EVIDENCE): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/assemble-context/test_pattern_binding_reader.py b/tests/skills/assemble-context/test_pattern_binding_reader.py index 9204d50..763154c 100644 --- a/tests/skills/assemble-context/test_pattern_binding_reader.py +++ b/tests/skills/assemble-context/test_pattern_binding_reader.py @@ -10,7 +10,7 @@ import sys import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "assemble-context" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) from retrieve_writer_sources import load_confirmed_pattern_bindings # noqa: E402 diff --git a/tests/skills/assemble-context/test_persist_freeze_db.py b/tests/skills/assemble-context/test_persist_freeze_db.py index b68b97c..2d4a946 100644 --- a/tests/skills/assemble-context/test_persist_freeze_db.py +++ b/tests/skills/assemble-context/test_persist_freeze_db.py @@ -20,7 +20,7 @@ import sys import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "assemble-context" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" for path in (SCRIPT_DIR,): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/assemble-context/test_retrieve_writer_sources.py b/tests/skills/assemble-context/test_retrieve_writer_sources.py index 7b71ddb..7b976df 100644 --- a/tests/skills/assemble-context/test_retrieve_writer_sources.py +++ b/tests/skills/assemble-context/test_retrieve_writer_sources.py @@ -9,9 +9,9 @@ import sys import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -ASSEMBLE_CONTEXT_SCRIPTS = PROJECT_ROOT / ".agent" / "skills" / "assemble-context" / "scripts" -FREEZE_CONTEXT_SCRIPTS = PROJECT_ROOT / ".agent" / "skills" / "freeze-context" / "scripts" -SEARCH_KNOWLEDGE_SCRIPTS = PROJECT_ROOT / ".agent" / "skills" / "search-knowledge" / "scripts" +ASSEMBLE_CONTEXT_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" +FREEZE_CONTEXT_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "freeze-context" / "scripts" +SEARCH_KNOWLEDGE_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "search-knowledge" / "scripts" for script_dir in ( ASSEMBLE_CONTEXT_SCRIPTS, FREEZE_CONTEXT_SCRIPTS, diff --git a/tests/skills/assemble-context/test_style_loader.py b/tests/skills/assemble-context/test_style_loader.py index dde6ea6..a42073c 100644 --- a/tests/skills/assemble-context/test_style_loader.py +++ b/tests/skills/assemble-context/test_style_loader.py @@ -10,7 +10,7 @@ import sys import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "assemble-context" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) from retrieve_writer_sources import derive_style_constraints, load_confirmed_style # noqa: E402 diff --git a/tests/skills/assemble-context/test_writer_contract.py b/tests/skills/assemble-context/test_writer_contract.py index 295a055..e10cfd6 100644 --- a/tests/skills/assemble-context/test_writer_contract.py +++ b/tests/skills/assemble-context/test_writer_contract.py @@ -10,7 +10,7 @@ import sys import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "assemble-context" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) from writer_contract import ( # noqa: E402 diff --git a/tests/skills/backup-work-extraction/test_backup_upgrade_work_offline.py b/tests/skills/backup-work-extraction/test_backup_upgrade_work_offline.py index e91b627..c37db06 100644 --- a/tests/skills/backup-work-extraction/test_backup_upgrade_work_offline.py +++ b/tests/skills/backup-work-extraction/test_backup_upgrade_work_offline.py @@ -13,7 +13,7 @@ from unittest import mock PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "backup-work-extraction" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "ingest" / "backup-work-extraction" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import backup_upgrade_work as backup # noqa: E402 diff --git a/tests/skills/call-content-model/test_call_persistence.py b/tests/skills/call-content-model/test_call_persistence.py index 6a2ba6c..6b76be7 100644 --- a/tests/skills/call-content-model/test_call_persistence.py +++ b/tests/skills/call-content-model/test_call_persistence.py @@ -15,7 +15,7 @@ import muse_llm as llm llm.TOKEN = "test-token" PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -EVIDENCE_SCRIPTS = PROJECT_ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +EVIDENCE_SCRIPTS = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" sys.path.insert(0, str(EVIDENCE_SCRIPTS)) from persist_llm_call import ( # noqa: E402 _event_model_match, diff --git a/tests/skills/capture-ai-flavor-cases/test_capture_cases.py b/tests/skills/capture-ai-flavor-cases/test_capture_cases.py index 56d3af6..2be23e8 100644 --- a/tests/skills/capture-ai-flavor-cases/test_capture_cases.py +++ b/tests/skills/capture-ai-flavor-cases/test_capture_cases.py @@ -10,7 +10,7 @@ from pathlib import Path from unittest.mock import patch PROJECT_ROOT = Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "capture-ai-flavor-cases" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "humanization" / "skills" / "capture-ai-flavor-cases" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import yaml diff --git a/tests/skills/capture-ai-flavor-cases/test_capture_lesson_offline.py b/tests/skills/capture-ai-flavor-cases/test_capture_lesson_offline.py index 0839675..2bf0adb 100644 --- a/tests/skills/capture-ai-flavor-cases/test_capture_lesson_offline.py +++ b/tests/skills/capture-ai-flavor-cases/test_capture_lesson_offline.py @@ -9,8 +9,8 @@ import unittest from unittest.mock import patch ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT = ROOT / ".agent" / "skills" / "capture-ai-flavor-cases" / "scripts" -EVIDENCE = ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +SCRIPT = ROOT / "muse" / "lifecycle" / "quality" / "humanization" / "skills" / "capture-ai-flavor-cases" / "scripts" +EVIDENCE = ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" for path in (SCRIPT, EVIDENCE): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/check-content-consistency/test_build_semantic_input.py b/tests/skills/check-content-consistency/test_build_semantic_input.py index 2c4bd0b..68765c5 100644 --- a/tests/skills/check-content-consistency/test_build_semantic_input.py +++ b/tests/skills/check-content-consistency/test_build_semantic_input.py @@ -17,9 +17,9 @@ import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" TEST_DIR = PROJECT_ROOT / "tests" / "skills" / "check-content-consistency" -SCRIPT_DIR = SKILLS_DIR / "check-content-consistency" / "scripts" -CONTINUATION_DIR = SKILLS_DIR / "write-next-chapter" / "scripts" -READ_CONTEXT_DIR = SKILLS_DIR / "assemble-context" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "semantic" / "check-content-consistency" / "scripts" +CONTINUATION_DIR = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "generate" / "write-next-chapter" / "scripts" +READ_CONTEXT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" for path in (TEST_DIR, SCRIPT_DIR, CONTINUATION_DIR, READ_CONTEXT_DIR): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/check-content-consistency/test_check_writer_candidate.py b/tests/skills/check-content-consistency/test_check_writer_candidate.py index 7b4dfd2..10cf3ce 100644 --- a/tests/skills/check-content-consistency/test_check_writer_candidate.py +++ b/tests/skills/check-content-consistency/test_check_writer_candidate.py @@ -11,9 +11,9 @@ import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" -SCRIPT_DIR = SKILLS_DIR / "check-content-consistency" / "scripts" -CONTINUATION_DIR = SKILLS_DIR / "write-next-chapter" / "scripts" -READ_CONTEXT_DIR = SKILLS_DIR / "assemble-context" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "semantic" / "check-content-consistency" / "scripts" +CONTINUATION_DIR = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "generate" / "write-next-chapter" / "scripts" +READ_CONTEXT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" WRITER_TEST_DIR = PROJECT_ROOT / "tests" / "skills" / "write-next-chapter" for path in (SCRIPT_DIR, CONTINUATION_DIR, READ_CONTEXT_DIR, WRITER_TEST_DIR): if str(path) not in sys.path: diff --git a/tests/skills/check-content-consistency/test_run_writer_semantic_detector.py b/tests/skills/check-content-consistency/test_run_writer_semantic_detector.py index e19b24e..e4e6aa1 100644 --- a/tests/skills/check-content-consistency/test_run_writer_semantic_detector.py +++ b/tests/skills/check-content-consistency/test_run_writer_semantic_detector.py @@ -11,7 +11,7 @@ import unittest from typing import Any, Mapping, Sequence PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "check-content-consistency" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "semantic" / "check-content-consistency" / "scripts" if str(SCRIPT_DIR) not in sys.path: sys.path.insert(0, str(SCRIPT_DIR)) diff --git a/tests/skills/clean-book-text/test_clean_detect_offline.py b/tests/skills/clean-book-text/test_clean_detect_offline.py index 0fe6da1..570b767 100644 --- a/tests/skills/clean-book-text/test_clean_detect_offline.py +++ b/tests/skills/clean-book-text/test_clean_detect_offline.py @@ -17,7 +17,7 @@ from unittest.mock import patch from click.testing import CliRunner PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "clean-book-text" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "ingest" / "clean-book-text" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import clean_detect # noqa: E402 diff --git a/tests/skills/confirm-knowledge-draft/test_confirm_knowledge_offline.py b/tests/skills/confirm-knowledge-draft/test_confirm_knowledge_offline.py index e350349..2e184d4 100644 --- a/tests/skills/confirm-knowledge-draft/test_confirm_knowledge_offline.py +++ b/tests/skills/confirm-knowledge-draft/test_confirm_knowledge_offline.py @@ -6,7 +6,7 @@ import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "confirm-knowledge-draft" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "sovereignty" / "confirm-knowledge-draft" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import confirm_knowledge as confirm # noqa: E402 diff --git a/tests/skills/decide-candidate/test_decision_lesson_offline.py b/tests/skills/decide-candidate/test_decision_lesson_offline.py index 0f10865..55ec7ee 100644 --- a/tests/skills/decide-candidate/test_decision_lesson_offline.py +++ b/tests/skills/decide-candidate/test_decision_lesson_offline.py @@ -9,8 +9,8 @@ import unittest from unittest.mock import patch PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "decide-candidate" / "scripts" -EVIDENCE_SCRIPTS = PROJECT_ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "sovereignty" / "decide-candidate" / "scripts" +EVIDENCE_SCRIPTS = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" for path in (SCRIPT_DIR, EVIDENCE_SCRIPTS): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/decide-candidate/test_fact_delta.py b/tests/skills/decide-candidate/test_fact_delta.py index e6ab03b..1859e5a 100644 --- a/tests/skills/decide-candidate/test_fact_delta.py +++ b/tests/skills/decide-candidate/test_fact_delta.py @@ -16,8 +16,8 @@ import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" -SCRIPT_DIR = SKILLS_DIR / "decide-candidate" / "scripts" -for path in (SCRIPT_DIR, SKILLS_DIR / "assemble-context" / "scripts"): +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "sovereignty" / "decide-candidate" / "scripts" +for path in (SCRIPT_DIR, PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts"): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/decide-candidate/test_fact_delta_db.py b/tests/skills/decide-candidate/test_fact_delta_db.py index 9e3aeac..d320f07 100644 --- a/tests/skills/decide-candidate/test_fact_delta_db.py +++ b/tests/skills/decide-candidate/test_fact_delta_db.py @@ -25,7 +25,7 @@ from psycopg.errors import RaiseException PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" -SCRIPT_DIR = SKILLS_DIR / "decide-candidate" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "sovereignty" / "decide-candidate" / "scripts" for path in (SCRIPT_DIR,): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/decide-candidate/test_next_steps_offline.py b/tests/skills/decide-candidate/test_next_steps_offline.py index bde7dea..72544f6 100644 --- a/tests/skills/decide-candidate/test_next_steps_offline.py +++ b/tests/skills/decide-candidate/test_next_steps_offline.py @@ -9,7 +9,7 @@ import sys import unittest ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT = ROOT / ".agent" / "skills" / "decide-candidate" / "scripts" +SCRIPT = ROOT / "muse" / "content" / "work" / "skills" / "sovereignty" / "decide-candidate" / "scripts" if str(SCRIPT) not in sys.path: sys.path.insert(0, str(SCRIPT)) @@ -43,7 +43,7 @@ class NextStepsOfflineTest(unittest.TestCase): self.assertTrue(all(s.get("auto") is False for s in steps)) def test_generation_entry_cannot_call_accept(self): - source = (ROOT / ".agent" / "skills" / "write-next-chapter" / "scripts" / "produce_next_chapter.py").read_text( + source = (ROOT / "muse" / "content" / "work" / "skills" / "generate" / "write-next-chapter" / "scripts" / "produce_next_chapter.py").read_text( encoding="utf-8" ) tree = ast.parse(source) diff --git a/tests/skills/decide-candidate/test_projection_db.py b/tests/skills/decide-candidate/test_projection_db.py index 53347df..08acec1 100644 --- a/tests/skills/decide-candidate/test_projection_db.py +++ b/tests/skills/decide-candidate/test_projection_db.py @@ -24,7 +24,7 @@ from psycopg.errors import RaiseException PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" -SCRIPT_DIR = SKILLS_DIR / "decide-candidate" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "sovereignty" / "decide-candidate" / "scripts" for path in (SCRIPT_DIR,): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/decide-candidate/test_write_canonical_db.py b/tests/skills/decide-candidate/test_write_canonical_db.py index 949c39c..da03a52 100644 --- a/tests/skills/decide-candidate/test_write_canonical_db.py +++ b/tests/skills/decide-candidate/test_write_canonical_db.py @@ -26,7 +26,7 @@ from unittest import mock PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" -SCRIPT_DIR = SKILLS_DIR / "decide-candidate" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "sovereignty" / "decide-candidate" / "scripts" for path in (SCRIPT_DIR,): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/decide-candidate/test_writer_acceptance.py b/tests/skills/decide-candidate/test_writer_acceptance.py index d8383b1..d6a7de4 100644 --- a/tests/skills/decide-candidate/test_writer_acceptance.py +++ b/tests/skills/decide-candidate/test_writer_acceptance.py @@ -16,9 +16,9 @@ import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" -SCRIPT_DIR = SKILLS_DIR / "decide-candidate" / "scripts" -CONTINUATION_DIR = SKILLS_DIR / "write-next-chapter" / "scripts" -READ_CONTEXT_DIR = SKILLS_DIR / "assemble-context" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "sovereignty" / "decide-candidate" / "scripts" +CONTINUATION_DIR = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "generate" / "write-next-chapter" / "scripts" +READ_CONTEXT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" for path in (SCRIPT_DIR, CONTINUATION_DIR, READ_CONTEXT_DIR): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/deconstruct-book/test_deconstruct_lesson_offline.py b/tests/skills/deconstruct-book/test_deconstruct_lesson_offline.py index 2ba6b04..ef3caa8 100644 --- a/tests/skills/deconstruct-book/test_deconstruct_lesson_offline.py +++ b/tests/skills/deconstruct-book/test_deconstruct_lesson_offline.py @@ -9,8 +9,8 @@ import unittest from unittest.mock import patch ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT = ROOT / ".agent" / "skills" / "deconstruct-book" / "scripts" -EVIDENCE = ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +SCRIPT = ROOT / "muse" / "content" / "entity" / "skills" / "ingest" / "deconstruct-book" / "scripts" +EVIDENCE = ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" for path in (SCRIPT, EVIDENCE): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/deconstruct-book/test_parse_llm_offline.py b/tests/skills/deconstruct-book/test_parse_llm_offline.py index 4f320ed..60298a8 100644 --- a/tests/skills/deconstruct-book/test_parse_llm_offline.py +++ b/tests/skills/deconstruct-book/test_parse_llm_offline.py @@ -12,7 +12,7 @@ from unittest.mock import Mock, patch PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "deconstruct-book" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "ingest" / "deconstruct-book" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import parse_llm as pll # noqa: E402 diff --git a/tests/skills/deconstruct-book/test_parse_outline_offline.py b/tests/skills/deconstruct-book/test_parse_outline_offline.py index 9d06a23..e4e2022 100644 --- a/tests/skills/deconstruct-book/test_parse_outline_offline.py +++ b/tests/skills/deconstruct-book/test_parse_outline_offline.py @@ -7,7 +7,7 @@ import sys import click PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "deconstruct-book" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "ingest" / "deconstruct-book" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import parse_outline as po # noqa: E402 diff --git a/tests/skills/design-story-foundation/test_assert_selection_handoff.py b/tests/skills/design-story-foundation/test_assert_selection_handoff.py index c6546dd..0e95361 100644 --- a/tests/skills/design-story-foundation/test_assert_selection_handoff.py +++ b/tests/skills/design-story-foundation/test_assert_selection_handoff.py @@ -6,7 +6,7 @@ from pathlib import Path import click PROJECT_ROOT = Path(__file__).resolve().parents[3] -SCRIPTS = PROJECT_ROOT / ".agent" / "skills" / "design-story-foundation" / "scripts" +SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "flow" / "skills" / "book" / "design-story-foundation" / "scripts" sys.path.insert(0, str(SCRIPTS)) from assert_selection_handoff import HandoffError, assert_selection_handoff # noqa: E402 diff --git a/tests/skills/design-story-foundation/test_validate_candidates.py b/tests/skills/design-story-foundation/test_validate_candidates.py index 6fe417d..f9fcb5d 100644 --- a/tests/skills/design-story-foundation/test_validate_candidates.py +++ b/tests/skills/design-story-foundation/test_validate_candidates.py @@ -9,7 +9,7 @@ import unittest PROJECT_ROOT = Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "design-story-foundation" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "flow" / "skills" / "book" / "design-story-foundation" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) from validate_candidates import ValidationConfig, validate_candidates, validate_root # noqa: E402 diff --git a/tests/skills/diagnose-ai-flavor/test_diagnose_ai_flavor.py b/tests/skills/diagnose-ai-flavor/test_diagnose_ai_flavor.py index a6551c4..f777508 100644 --- a/tests/skills/diagnose-ai-flavor/test_diagnose_ai_flavor.py +++ b/tests/skills/diagnose-ai-flavor/test_diagnose_ai_flavor.py @@ -8,7 +8,7 @@ import unittest from unittest.mock import patch PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "diagnose-ai-flavor" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "humanization" / "skills" / "diagnose-ai-flavor" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import diagnose_ai_flavor as diag # noqa: E402 diff --git a/tests/skills/dispatch-agent-task/test_dispatch_agent_task.py b/tests/skills/dispatch-agent-task/test_dispatch_agent_task.py index 338ba91..f478c83 100644 --- a/tests/skills/dispatch-agent-task/test_dispatch_agent_task.py +++ b/tests/skills/dispatch-agent-task/test_dispatch_agent_task.py @@ -15,21 +15,21 @@ import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SKILL_DIR = PROJECT_ROOT / ".agent" / "skills" / "dispatch-agent-task" / "scripts" -EVIDENCE_DIR = PROJECT_ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" -for path in (SKILL_DIR, EVIDENCE_DIR): +SKILL_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "dispatch" / "skills" / "dispatch-agent-task" / "scripts" +EVIDENCE_DIR = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" +for path in (PROJECT_ROOT, SKILL_DIR, EVIDENCE_DIR): if str(path) not in sys.path: sys.path.insert(0, str(path)) -import agent_task # noqa: E402 -from agent_task import ( # noqa: E402 +import role_task as agent_task # noqa: E402 +from role_task import ( # noqa: E402 OutputInvalidError, TaskSpecError, build_task_package, load_spec, validate_structured_output, ) -from pi_runner import ( # noqa: E402 +from framework.adapters.pi.runner import ( # noqa: E402 ExecutionPolicy, FrameworkError, PiAgentRunner, @@ -268,7 +268,7 @@ class PackageTest(unittest.TestCase): identity = package.as_identity() self.assertEqual(identity["toolAllowlist"], []) self.assertEqual(identity["roleContractVersion"], "role-contracts-v1") - self.assertEqual(identity["roleContractSource"], ".agent/docs/architecture/角色合同.md") + self.assertEqual(identity["roleContractSource"], "muse/sot/角色合同.md") self.assertTrue(all(len(v) == 71 and v.startswith("sha256:") for k, v in identity.items() if k.endswith("Sha256"))) @@ -290,7 +290,7 @@ class ArgvTest(unittest.TestCase): def test_argv_injects_prompt_tools_and_isolation(self): package = build_task_package(load_spec(make_spec(self.tmp)), REPO_ROOT) - argv = build_pi_argv(package, ExecutionPolicy(provider="p", model="m", thinking="low")) + argv = build_pi_argv(package.as_framework_request(), ExecutionPolicy(provider="p", model="m", thinking="low")) joined = " ".join(argv) self.assertIn("--system-prompt", argv) self.assertEqual(argv[argv.index("--system-prompt") + 1], package.system_prompt) @@ -306,7 +306,7 @@ class ArgvTest(unittest.TestCase): def test_tool_allowlist_maps_to_tools_flag(self): spec_path = make_spec(pathlib.Path(tempfile.mkdtemp()), toolAllowlist=["read", "bash"]) package = build_task_package(load_spec(spec_path), REPO_ROOT) - argv = build_pi_argv(package, ExecutionPolicy(provider="p", model="m")) + argv = build_pi_argv(package.as_framework_request(), ExecutionPolicy(provider="p", model="m")) self.assertIn("--tools", argv) self.assertEqual(argv[argv.index("--tools") + 1], "read,bash") @@ -342,7 +342,7 @@ class RunnerParseTest(unittest.TestCase): ) sink = self._sink() outcome = PiAgentRunner(launcher=fake_launcher(pi_stream_lines('{"title":"t","beats":["a"]}', with_tool=True))).run( - package, ExecutionPolicy(provider="p", model="m"), sink, timeout_seconds=10 + package.as_framework_request(), ExecutionPolicy(provider="p", model="m"), sink, timeout_seconds=10 ) self.assertEqual(outcome.final_text, '{"title":"t","beats":["a"]}') self.assertEqual(len(outcome.model_calls), 2) @@ -387,7 +387,7 @@ class RunnerParseTest(unittest.TestCase): ): with self.assertRaises(FrameworkError) as ctx: PiAgentRunner(launcher=launcher).run( - package, + package.as_framework_request(), ExecutionPolicy(provider="p", model="m"), self._sink(), timeout_seconds=5, @@ -422,6 +422,7 @@ class RunDispatchTest(unittest.TestCase): self.assertEqual(receipt["usage"], {"inputTokens": 110, "outputTokens": 40, "cachedTokens": 10, "reasoningTokens": 0}) self.assertEqual(receipt["totalCostUsd"], 0.012) self.assertTrue(receipt["costComplete"]) + self.assertEqual(receipt["frameworkArtifact"]["eventCount"], 8) self.assertEqual( [p[2] for p in connect.event_rows()], ["run.started", "agent.started", "model.completed", "agent.completed", "run.completed"], @@ -433,7 +434,7 @@ class RunDispatchTest(unittest.TestCase): # 运行目录审计件齐全且只对当前用户开放。 run_dir = self.tmp / "run" self.assertEqual(stat.S_IMODE(run_dir.stat().st_mode), 0o700) - for name in ("task-spec.json", "system-prompt.txt", "user-message.txt", "transcript.jsonl", "output.json", "receipt.json"): + for name in ("task-spec.json", "system-prompt.txt", "user-message.txt", "transcript.jsonl", "framework-events.jsonl", "output.json", "receipt.json"): path = run_dir / name self.assertTrue(path.exists(), name) self.assertEqual(stat.S_IMODE(path.stat().st_mode), 0o600, name) @@ -532,7 +533,7 @@ class RunDispatchTest(unittest.TestCase): class ValidateOutputTest(unittest.TestCase): def test_extract_and_validate(self): - from agent_task import AgentTaskSpec + from role_task import AgentTaskSpec spec = AgentTaskSpec( role="planner", @@ -561,7 +562,7 @@ class SessionAndReadToolsTest(unittest.TestCase): ExecutionPolicy(provider="p", model="m", session_id="s1") package = build_task_package(load_spec(make_spec(self.tmp)), REPO_ROOT) argv = build_pi_argv( - package, + package.as_framework_request(), ExecutionPolicy(provider="p", model="m", session_id="s1", session_dir="/tmp/sd"), ) self.assertIn("--session-id", argv) @@ -572,7 +573,7 @@ class SessionAndReadToolsTest(unittest.TestCase): def test_extension_path_maps_to_e_flag_with_isolation(self): package = build_task_package(load_spec(make_spec(self.tmp)), REPO_ROOT) argv = build_pi_argv( - package, + package.as_framework_request(), ExecutionPolicy(provider="p", model="m", extension_path="/x/ext.ts"), ) self.assertIn("-e", argv) @@ -610,7 +611,7 @@ class SessionAndReadToolsTest(unittest.TestCase): ) runner = PiAgentRunner(launcher=fake_launcher(patched)) outcome = runner.run( - package, + package.as_framework_request(), ExecutionPolicy(provider="p", model="m"), sink, timeout_seconds=30, diff --git a/tests/skills/dispatch-agent-task/test_read_tools.py b/tests/skills/dispatch-agent-task/test_read_tools.py index 2e15075..28306b8 100644 --- a/tests/skills/dispatch-agent-task/test_read_tools.py +++ b/tests/skills/dispatch-agent-task/test_read_tools.py @@ -15,9 +15,11 @@ import tempfile import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SKILL_DIR = PROJECT_ROOT / ".agent" / "skills" / "dispatch-agent-task" / "scripts" -if str(SKILL_DIR) not in sys.path: - sys.path.insert(0, str(SKILL_DIR)) +SKILL_DIR = PROJECT_ROOT / "muse" / "authority" / "tools" / "read" +FRAMEWORK_EXTENSION = PROJECT_ROOT / "framework" / "adapters" / "pi" / "mcp_bridge.ts" +for path in (PROJECT_ROOT, SKILL_DIR): + if str(path) not in sys.path: + sys.path.insert(0, str(path)) import read_tools # noqa: E402 from read_tools import TOOL_REGISTRY, execute_tool # noqa: E402 @@ -187,7 +189,7 @@ class ExtensionSyncTest(unittest.TestCase): """扩展不自带工具清单:它必须从登记表 --list 动态装载,防止双源漂移。""" def test_extension_loads_registry_dynamically(self): - extension = (SKILL_DIR / "muse_read_tools_extension.ts").read_text(encoding="utf-8") + extension = FRAMEWORK_EXTENSION.read_text(encoding="utf-8") self.assertIn("--list", extension) self.assertIn("registerTool", extension) self.assertIn("MUSE_READ_TOOLS_PYTHON", extension) diff --git a/tests/skills/embed-knowledge/test_embed_drafts_offline.py b/tests/skills/embed-knowledge/test_embed_drafts_offline.py index 741fb90..ff9a0c6 100644 --- a/tests/skills/embed-knowledge/test_embed_drafts_offline.py +++ b/tests/skills/embed-knowledge/test_embed_drafts_offline.py @@ -14,7 +14,7 @@ import muse_embed as embed # CLI 壳留在 Skill 里、不随包安装,只能按路径加载 CLI_PATH = (pathlib.Path(__file__).resolve().parents[3] - / ".agent/skills/embed-knowledge/scripts/embed_drafts.py") + / "muse/lifecycle/context/skills/embed-knowledge/scripts/embed_drafts.py") _spec = importlib.util.spec_from_file_location("embed_drafts_cli", CLI_PATH) cli = importlib.util.module_from_spec(_spec) _spec.loader.exec_module(cli) diff --git a/tests/skills/establish-voice-baseline/test_establish_voice_baseline.py b/tests/skills/establish-voice-baseline/test_establish_voice_baseline.py index 20f7477..40311d9 100644 --- a/tests/skills/establish-voice-baseline/test_establish_voice_baseline.py +++ b/tests/skills/establish-voice-baseline/test_establish_voice_baseline.py @@ -7,7 +7,7 @@ import unittest from unittest.mock import patch PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "establish-voice-baseline" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "humanization" / "skills" / "establish-voice-baseline" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import establish_voice_baseline as base # noqa: E402 diff --git a/tests/skills/evaluate-frozen-replay/test_fine_outline_detector.py b/tests/skills/evaluate-frozen-replay/test_fine_outline_detector.py index 632b7a4..80958f8 100644 --- a/tests/skills/evaluate-frozen-replay/test_fine_outline_detector.py +++ b/tests/skills/evaluate-frozen-replay/test_fine_outline_detector.py @@ -8,7 +8,7 @@ import sys import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "evaluate-frozen-replay" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "replay" / "evaluate-frozen-replay" / "scripts" if str(SCRIPT_DIR) not in sys.path: sys.path.insert(0, str(SCRIPT_DIR)) @@ -81,8 +81,11 @@ class FineOutlineDetectorTest(unittest.TestCase): skill_path = ( PROJECT_ROOT - / ".agent" + / "muse" + / "lifecycle" + / "quality" / "skills" + / "semantic" / "check-content-consistency" / "SKILL.md" ) diff --git a/tests/skills/evaluate-frozen-replay/test_run_replay.py b/tests/skills/evaluate-frozen-replay/test_run_replay.py index c41ccef..b995036 100644 --- a/tests/skills/evaluate-frozen-replay/test_run_replay.py +++ b/tests/skills/evaluate-frozen-replay/test_run_replay.py @@ -13,9 +13,9 @@ from unittest.mock import patch PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" -SCRIPT_DIR = SKILLS_DIR / "evaluate-frozen-replay" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "replay" / "evaluate-frozen-replay" / "scripts" TEST_DIR = PROJECT_ROOT / "tests" / "skills" / "evaluate-frozen-replay" -QUALITY_GATE_DIR = SKILLS_DIR / "score-content-quality" / "scripts" +QUALITY_GATE_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "judge" / "score-content-quality" / "scripts" REPLAY_GATE_TEST_DIR = PROJECT_ROOT / "tests" / "skills" / "adjudicate-quality-gate" for _import_dir in (SCRIPT_DIR, TEST_DIR, QUALITY_GATE_DIR, REPLAY_GATE_TEST_DIR): if str(_import_dir) not in sys.path: diff --git a/tests/skills/extract-chapter-knowledge/test_chapter_extract_lesson_offline.py b/tests/skills/extract-chapter-knowledge/test_chapter_extract_lesson_offline.py index 2dfb99c..7988adb 100644 --- a/tests/skills/extract-chapter-knowledge/test_chapter_extract_lesson_offline.py +++ b/tests/skills/extract-chapter-knowledge/test_chapter_extract_lesson_offline.py @@ -9,8 +9,8 @@ import unittest from unittest.mock import patch ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT = ROOT / ".agent" / "skills" / "extract-chapter-knowledge" / "scripts" -EVIDENCE = ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +SCRIPT = ROOT / "muse" / "content" / "entity" / "skills" / "extract" / "extract-chapter-knowledge" / "scripts" +EVIDENCE = ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" for path in (SCRIPT, EVIDENCE): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/extract-chapter-knowledge/test_dispatch_extraction_bridge.py b/tests/skills/extract-chapter-knowledge/test_dispatch_extraction_bridge.py index 905c251..79a0996 100644 --- a/tests/skills/extract-chapter-knowledge/test_dispatch_extraction_bridge.py +++ b/tests/skills/extract-chapter-knowledge/test_dispatch_extraction_bridge.py @@ -15,7 +15,7 @@ import unittest from unittest import mock PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "extract-chapter-knowledge" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "extract" / "extract-chapter-knowledge" / "scripts" for path in (SCRIPT_DIR,): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/extract-chapter-knowledge/test_extract_knowledge_offline.py b/tests/skills/extract-chapter-knowledge/test_extract_knowledge_offline.py index 6621c2c..21ada69 100644 --- a/tests/skills/extract-chapter-knowledge/test_extract_knowledge_offline.py +++ b/tests/skills/extract-chapter-knowledge/test_extract_knowledge_offline.py @@ -4,7 +4,7 @@ import pathlib import sys PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "extract-chapter-knowledge" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "extract" / "extract-chapter-knowledge" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) from extract_knowledge import ExtractionContractError, normalize_extraction, salvage_extraction # noqa: E402 diff --git a/tests/skills/extract-work-knowledge/test_parse_upgrade_offline.py b/tests/skills/extract-work-knowledge/test_parse_upgrade_offline.py index 2cc049e..89678aa 100644 --- a/tests/skills/extract-work-knowledge/test_parse_upgrade_offline.py +++ b/tests/skills/extract-work-knowledge/test_parse_upgrade_offline.py @@ -30,7 +30,7 @@ from click.testing import CliRunner # 从生产 scripts 导入 upgrade;upgrade 自己装配 parse-book/embed/llm 的生产模块路径。 PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "extract-work-knowledge" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "ingest" / "extract-work-knowledge" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import upgrade as pu # noqa: E402 import muse_embed as embed_drafts diff --git a/tests/skills/extract-work-knowledge/test_parse_upgrade_pg_smoke.py b/tests/skills/extract-work-knowledge/test_parse_upgrade_pg_smoke.py index 189ed2b..a719a42 100644 --- a/tests/skills/extract-work-knowledge/test_parse_upgrade_pg_smoke.py +++ b/tests/skills/extract-work-knowledge/test_parse_upgrade_pg_smoke.py @@ -6,7 +6,7 @@ import pathlib import sys PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "extract-work-knowledge" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "ingest" / "extract-work-knowledge" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import upgrade as pu # noqa: E402 diff --git a/tests/skills/extract-work-knowledge/test_presence_dedupe.py b/tests/skills/extract-work-knowledge/test_presence_dedupe.py index 83c899d..1f0f5b0 100644 --- a/tests/skills/extract-work-knowledge/test_presence_dedupe.py +++ b/tests/skills/extract-work-knowledge/test_presence_dedupe.py @@ -17,7 +17,7 @@ from click.testing import CliRunner # 从原生产 scripts 导入 upgrade;测试替身只隔离数据库连接,不替代生产逻辑。 PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "extract-work-knowledge" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "ingest" / "extract-work-knowledge" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import upgrade as pu # noqa: E402 diff --git a/tests/skills/extract-work-knowledge/test_upgrade_lesson_offline.py b/tests/skills/extract-work-knowledge/test_upgrade_lesson_offline.py index ca9c22d..5ee63d9 100644 --- a/tests/skills/extract-work-knowledge/test_upgrade_lesson_offline.py +++ b/tests/skills/extract-work-knowledge/test_upgrade_lesson_offline.py @@ -9,8 +9,8 @@ import unittest from unittest.mock import patch ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT = ROOT / ".agent" / "skills" / "extract-work-knowledge" / "scripts" -EVIDENCE = ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +SCRIPT = ROOT / "muse" / "content" / "entity" / "skills" / "ingest" / "extract-work-knowledge" / "scripts" +EVIDENCE = ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" for path in (SCRIPT, EVIDENCE): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/extract-work-knowledge/test_upgrade_work_lock_offline.py b/tests/skills/extract-work-knowledge/test_upgrade_work_lock_offline.py index 3ecae8d..ea14cb5 100644 --- a/tests/skills/extract-work-knowledge/test_upgrade_work_lock_offline.py +++ b/tests/skills/extract-work-knowledge/test_upgrade_work_lock_offline.py @@ -7,7 +7,7 @@ import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "extract-work-knowledge" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "ingest" / "extract-work-knowledge" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) from upgrade_work_lock import ( # noqa: E402 diff --git a/tests/skills/freeze-context/test_audit_leakage.py b/tests/skills/freeze-context/test_audit_leakage.py index 7e5e3d0..0011a02 100644 --- a/tests/skills/freeze-context/test_audit_leakage.py +++ b/tests/skills/freeze-context/test_audit_leakage.py @@ -9,7 +9,7 @@ import sys import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "freeze-context" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "freeze-context" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) from audit_leakage import audit_snapshot # noqa: E402 diff --git a/tests/skills/freeze-context/test_build_snapshot.py b/tests/skills/freeze-context/test_build_snapshot.py index 8f6186e..c829fd8 100644 --- a/tests/skills/freeze-context/test_build_snapshot.py +++ b/tests/skills/freeze-context/test_build_snapshot.py @@ -6,7 +6,7 @@ import sys import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "freeze-context" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "freeze-context" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) from build_snapshot import ( # noqa: E402 SnapshotError, diff --git a/tests/skills/freeze-context/test_check_snapshot.py b/tests/skills/freeze-context/test_check_snapshot.py index 6f777d8..f9dd6ab 100644 --- a/tests/skills/freeze-context/test_check_snapshot.py +++ b/tests/skills/freeze-context/test_check_snapshot.py @@ -6,7 +6,7 @@ import sys import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "freeze-context" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "freeze-context" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) from check_snapshot import ( # noqa: E402 STATUS_BLOCKED_AUTHORIZATION, diff --git a/tests/skills/freeze-context/test_load_reference_work.py b/tests/skills/freeze-context/test_load_reference_work.py index d275e81..b701975 100644 --- a/tests/skills/freeze-context/test_load_reference_work.py +++ b/tests/skills/freeze-context/test_load_reference_work.py @@ -11,7 +11,7 @@ import unittest from unittest.mock import patch PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "freeze-context" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "freeze-context" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import load_reference_work as loader # noqa: E402 from load_reference_work import ( # noqa: E402 diff --git a/tests/skills/load-replay-reference-work/test_load_writer_reference_work.py b/tests/skills/load-replay-reference-work/test_load_writer_reference_work.py index 7ea263a..0d9ce92 100644 --- a/tests/skills/load-replay-reference-work/test_load_writer_reference_work.py +++ b/tests/skills/load-replay-reference-work/test_load_writer_reference_work.py @@ -16,15 +16,15 @@ from unittest.mock import patch PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" -SCRIPT_DIR = SKILLS_DIR / "load-replay-reference-work" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "replay" / "load-replay-reference-work" / "scripts" TEST_DIR = PROJECT_ROOT / "tests" / "skills" / "load-replay-reference-work" -WRITER_REPLAY_SCRIPTS = SKILLS_DIR / "replay-writer-gate" / "scripts" -GATE_ADJUDICATION_SCRIPTS = SKILLS_DIR / "adjudicate-quality-gate" / "scripts" -READ_CONTEXT_SCRIPTS = SKILLS_DIR / "assemble-context" / "scripts" -DETECT_SCRIPTS = SKILLS_DIR / "check-content-consistency" / "scripts" -CONTINUATION_SCRIPTS = SKILLS_DIR / "write-next-chapter" / "scripts" +WRITER_REPLAY_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "replay" / "replay-writer-gate" / "scripts" +GATE_ADJUDICATION_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "mechanical" / "adjudicate-quality-gate" / "scripts" +READ_CONTEXT_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" +DETECT_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "semantic" / "check-content-consistency" / "scripts" +CONTINUATION_SCRIPTS = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "generate" / "write-next-chapter" / "scripts" CONTINUATION_TESTS = PROJECT_ROOT / "tests" / "skills" / "write-next-chapter" -REFRESH_RUNTIME_SCRIPTS = SKILLS_DIR / "refresh-runtime-probe" / "scripts" +REFRESH_RUNTIME_SCRIPTS = PROJECT_ROOT / "muse" / "platform" / "llm" / "skills" / "refresh-runtime-probe" / "scripts" for _path in ( SCRIPT_DIR, TEST_DIR, diff --git a/tests/skills/load-replay-reference-work/test_pattern_reference_injection.py b/tests/skills/load-replay-reference-work/test_pattern_reference_injection.py index 79a695d..5805234 100644 --- a/tests/skills/load-replay-reference-work/test_pattern_reference_injection.py +++ b/tests/skills/load-replay-reference-work/test_pattern_reference_injection.py @@ -15,16 +15,16 @@ import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" -SCRIPT_DIR = SKILLS_DIR / "load-replay-reference-work" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "replay" / "load-replay-reference-work" / "scripts" TEST_DIR = PROJECT_ROOT / "tests" / "skills" / "load-replay-reference-work" ASSEMBLE_CONTEXT_TESTS = PROJECT_ROOT / "tests" / "skills" / "assemble-context" -READ_CONTEXT_SCRIPTS = SKILLS_DIR / "assemble-context" / "scripts" +READ_CONTEXT_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" # 端到端链路测试要导入回放包,其依赖证据与评分 Skill 的 scripts;角色运行时走已安装的 muse_role 模块。 -WRITER_REPLAY_SCRIPTS = SKILLS_DIR / "replay-writer-gate" / "scripts" -EVIDENCE_SCRIPTS = SKILLS_DIR / "record-run-evidence" / "scripts" -QUALITY_GATE_SCRIPTS = SKILLS_DIR / "score-content-quality" / "scripts" -GATE_ADJUDICATION_SCRIPTS = SKILLS_DIR / "adjudicate-quality-gate" / "scripts" -REFRESH_RUNTIME_SCRIPTS = SKILLS_DIR / "refresh-runtime-probe" / "scripts" +WRITER_REPLAY_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "replay" / "replay-writer-gate" / "scripts" +EVIDENCE_SCRIPTS = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" +QUALITY_GATE_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "judge" / "score-content-quality" / "scripts" +GATE_ADJUDICATION_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "mechanical" / "adjudicate-quality-gate" / "scripts" +REFRESH_RUNTIME_SCRIPTS = PROJECT_ROOT / "muse" / "platform" / "llm" / "skills" / "refresh-runtime-probe" / "scripts" for _path in ( SCRIPT_DIR, TEST_DIR, diff --git a/tests/skills/merge-story-candidates/test_serial_merge.py b/tests/skills/merge-story-candidates/test_serial_merge.py index 64ae32e..6e34522 100644 --- a/tests/skills/merge-story-candidates/test_serial_merge.py +++ b/tests/skills/merge-story-candidates/test_serial_merge.py @@ -9,7 +9,7 @@ import unittest PROJECT_ROOT = Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "merge-story-candidates" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "flow" / "skills" / "book" / "merge-story-candidates" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) from serial_merge import SerialMergeError, build_packet, parse_raw, parser, validate_prefix # noqa: E402 diff --git a/tests/skills/plan-chapter/test_contract.py b/tests/skills/plan-chapter/test_contract.py index 21c1d3e..9c18c68 100644 --- a/tests/skills/plan-chapter/test_contract.py +++ b/tests/skills/plan-chapter/test_contract.py @@ -11,12 +11,12 @@ import unittest PROJECT_ROOT = Path(__file__).resolve().parents[3] SKILL = ( - PROJECT_ROOT / ".agent" / "skills" / "plan-chapter" / "SKILL.md" + PROJECT_ROOT / "muse" / "lifecycle" / "flow" / "skills" / "chapter" / "plan-chapter" / "SKILL.md" ).read_text(encoding="utf-8") PLANNER = (PROJECT_ROOT / ".agent" / "agents" / "planner.md").read_text(encoding="utf-8") -CHAINS = (PROJECT_ROOT / "meta" / "chains" / "README.md").read_text(encoding="utf-8") +CHAINS = (PROJECT_ROOT / "muse" / "lifecycle" / "flow" / "chains" / "README.md").read_text(encoding="utf-8") SCHEMA = ( - PROJECT_ROOT / "meta" / "schemas" / "fine_outline.yaml" + PROJECT_ROOT / "muse" / "content" / "meta" / "schemas" / "fine_outline.yaml" ).read_text(encoding="utf-8") # 与 meta/schemas/fine_outline.yaml 的必填/推荐集保持一致。 diff --git a/tests/skills/plan-story/test_field_coverage.py b/tests/skills/plan-story/test_field_coverage.py index a61c0f9..389bb08 100644 --- a/tests/skills/plan-story/test_field_coverage.py +++ b/tests/skills/plan-story/test_field_coverage.py @@ -12,7 +12,7 @@ import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "plan-story" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "flow" / "skills" / "book" / "plan-story" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) from persist_planning import ( # noqa: E402 diff --git a/tests/skills/plan-story/test_planning_lesson_offline.py b/tests/skills/plan-story/test_planning_lesson_offline.py index 0674dc6..03f2279 100644 --- a/tests/skills/plan-story/test_planning_lesson_offline.py +++ b/tests/skills/plan-story/test_planning_lesson_offline.py @@ -9,8 +9,8 @@ import unittest from unittest.mock import patch ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT = ROOT / ".agent" / "skills" / "plan-story" / "scripts" -EVIDENCE = ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +SCRIPT = ROOT / "muse" / "lifecycle" / "flow" / "skills" / "book" / "plan-story" / "scripts" +EVIDENCE = ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" for path in (SCRIPT, EVIDENCE): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/plan-story/test_record_planning_execution.py b/tests/skills/plan-story/test_record_planning_execution.py index 835de9e..f8699f5 100644 --- a/tests/skills/plan-story/test_record_planning_execution.py +++ b/tests/skills/plan-story/test_record_planning_execution.py @@ -7,7 +7,7 @@ import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "plan-story" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "flow" / "skills" / "book" / "plan-story" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import record_planning_execution as recorder # noqa: E402 diff --git a/tests/skills/plan-story/test_repair_deterministic_receipt.py b/tests/skills/plan-story/test_repair_deterministic_receipt.py index 3a7d864..5076568 100644 --- a/tests/skills/plan-story/test_repair_deterministic_receipt.py +++ b/tests/skills/plan-story/test_repair_deterministic_receipt.py @@ -7,7 +7,7 @@ import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "plan-story" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "flow" / "skills" / "book" / "plan-story" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import repair_deterministic_receipt as repair # noqa: E402 diff --git a/tests/skills/plan-story/test_select_patterns_offline.py b/tests/skills/plan-story/test_select_patterns_offline.py index b5cd806..6031221 100644 --- a/tests/skills/plan-story/test_select_patterns_offline.py +++ b/tests/skills/plan-story/test_select_patterns_offline.py @@ -8,7 +8,7 @@ from unittest.mock import patch PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "plan-story" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "flow" / "skills" / "book" / "plan-story" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import select_patterns as selector # noqa: E402 diff --git a/tests/skills/prevent-ai-flavor/test_prevent_ai_flavor.py b/tests/skills/prevent-ai-flavor/test_prevent_ai_flavor.py index 75d65a9..6f93ed3 100644 --- a/tests/skills/prevent-ai-flavor/test_prevent_ai_flavor.py +++ b/tests/skills/prevent-ai-flavor/test_prevent_ai_flavor.py @@ -6,7 +6,7 @@ import unittest from unittest.mock import patch PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "prevent-ai-flavor" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "humanization" / "skills" / "prevent-ai-flavor" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import prevent_ai_flavor as prev # noqa: E402 diff --git a/tests/skills/prevent-ai-flavor/test_prevention_lesson_offline.py b/tests/skills/prevent-ai-flavor/test_prevention_lesson_offline.py index 2e61330..86081cc 100644 --- a/tests/skills/prevent-ai-flavor/test_prevention_lesson_offline.py +++ b/tests/skills/prevent-ai-flavor/test_prevention_lesson_offline.py @@ -9,8 +9,8 @@ import unittest from unittest.mock import patch ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT = ROOT / ".agent" / "skills" / "prevent-ai-flavor" / "scripts" -EVIDENCE = ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +SCRIPT = ROOT / "muse" / "lifecycle" / "quality" / "humanization" / "skills" / "prevent-ai-flavor" / "scripts" +EVIDENCE = ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" for path in (SCRIPT, EVIDENCE): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/promote-ai-flavor-rule/test_propose_rule.py b/tests/skills/promote-ai-flavor-rule/test_propose_rule.py index 63fcf06..28f4465 100644 --- a/tests/skills/promote-ai-flavor-rule/test_propose_rule.py +++ b/tests/skills/promote-ai-flavor-rule/test_propose_rule.py @@ -10,8 +10,8 @@ from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" -SCRIPT_DIR = SKILLS_DIR / "promote-ai-flavor-rule" / "scripts" -CAPTURE_SCRIPTS = SKILLS_DIR / "capture-ai-flavor-cases" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "humanization" / "skills" / "promote-ai-flavor-rule" / "scripts" +CAPTURE_SCRIPTS = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "humanization" / "skills" / "capture-ai-flavor-cases" / "scripts" for _path in (SCRIPT_DIR, CAPTURE_SCRIPTS): sys.path.insert(0, str(_path)) diff --git a/tests/skills/record-run-evidence/test_agent_trace.py b/tests/skills/record-run-evidence/test_agent_trace.py index 7d8cf1a..2ec2097 100644 --- a/tests/skills/record-run-evidence/test_agent_trace.py +++ b/tests/skills/record-run-evidence/test_agent_trace.py @@ -13,7 +13,7 @@ import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" if str(SCRIPT_DIR) not in sys.path: sys.path.insert(0, str(SCRIPT_DIR)) diff --git a/tests/skills/record-run-evidence/test_file_cas.py b/tests/skills/record-run-evidence/test_file_cas.py index 6956a22..97e23b3 100644 --- a/tests/skills/record-run-evidence/test_file_cas.py +++ b/tests/skills/record-run-evidence/test_file_cas.py @@ -13,7 +13,7 @@ import unittest from unittest import mock PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) from file_cas import CasConflictError, CasRecoveryError, FileCasStore # noqa: E402 diff --git a/tests/skills/record-run-evidence/test_lesson_registry_db.py b/tests/skills/record-run-evidence/test_lesson_registry_db.py index 05abbf8..4a76b4a 100644 --- a/tests/skills/record-run-evidence/test_lesson_registry_db.py +++ b/tests/skills/record-run-evidence/test_lesson_registry_db.py @@ -23,7 +23,7 @@ from psycopg.errors import RaiseException PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" -SCRIPT_DIR = SKILLS_DIR / "record-run-evidence" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" if str(SCRIPT_DIR) not in sys.path: sys.path.insert(0, str(SCRIPT_DIR)) diff --git a/tests/skills/record-run-evidence/test_persist_raw.py b/tests/skills/record-run-evidence/test_persist_raw.py index 0c424fc..55bcc44 100644 --- a/tests/skills/record-run-evidence/test_persist_raw.py +++ b/tests/skills/record-run-evidence/test_persist_raw.py @@ -4,7 +4,7 @@ import pathlib import sys PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) from persist_raw import _check_no_secrets # noqa: E402 diff --git a/tests/skills/record-run-evidence/test_raw_vault.py b/tests/skills/record-run-evidence/test_raw_vault.py index d3cd54c..8bfac7b 100644 --- a/tests/skills/record-run-evidence/test_raw_vault.py +++ b/tests/skills/record-run-evidence/test_raw_vault.py @@ -14,7 +14,7 @@ from datetime import datetime, timedelta, timezone from unittest import mock PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import raw_vault # noqa: E402 diff --git a/tests/skills/record-run-evidence/test_record_failed_run.py b/tests/skills/record-run-evidence/test_record_failed_run.py index 415d819..41188a5 100644 --- a/tests/skills/record-run-evidence/test_record_failed_run.py +++ b/tests/skills/record-run-evidence/test_record_failed_run.py @@ -6,7 +6,7 @@ import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import record_failed_run as failure # noqa: E402 diff --git a/tests/skills/record-run-evidence/test_repair_receipt_evidence.py b/tests/skills/record-run-evidence/test_repair_receipt_evidence.py index 0d0e7c2..cac9ab3 100644 --- a/tests/skills/record-run-evidence/test_repair_receipt_evidence.py +++ b/tests/skills/record-run-evidence/test_repair_receipt_evidence.py @@ -6,7 +6,7 @@ import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import repair_receipt_evidence as repair # noqa: E402 diff --git a/tests/skills/record-run-evidence/test_run_registry.py b/tests/skills/record-run-evidence/test_run_registry.py index 371d73a..1e030f8 100644 --- a/tests/skills/record-run-evidence/test_run_registry.py +++ b/tests/skills/record-run-evidence/test_run_registry.py @@ -4,7 +4,7 @@ import pathlib import sys PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import run_registry # noqa: E402 diff --git a/tests/skills/refresh-runtime-probe/test_refresh_runtime_probe.py b/tests/skills/refresh-runtime-probe/test_refresh_runtime_probe.py index cd904c8..3c78dde 100644 --- a/tests/skills/refresh-runtime-probe/test_refresh_runtime_probe.py +++ b/tests/skills/refresh-runtime-probe/test_refresh_runtime_probe.py @@ -14,9 +14,9 @@ from unittest import mock PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" -SCRIPT_DIR = SKILLS_DIR / "refresh-runtime-probe" / "scripts" -WRITER_REPLAY_DIR = SKILLS_DIR / "replay-writer-gate" / "scripts" -GATE_ADJUDICATION_DIR = SKILLS_DIR / "adjudicate-quality-gate" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "platform" / "llm" / "skills" / "refresh-runtime-probe" / "scripts" +WRITER_REPLAY_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "replay" / "replay-writer-gate" / "scripts" +GATE_ADJUDICATION_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "mechanical" / "adjudicate-quality-gate" / "scripts" for _import_dir in (SCRIPT_DIR, WRITER_REPLAY_DIR, GATE_ADJUDICATION_DIR): if str(_import_dir) not in sys.path: sys.path.insert(0, str(_import_dir)) diff --git a/tests/skills/replay-writer-gate/test_run_writer_replay.py b/tests/skills/replay-writer-gate/test_run_writer_replay.py index b48b5c4..5385c57 100644 --- a/tests/skills/replay-writer-gate/test_run_writer_replay.py +++ b/tests/skills/replay-writer-gate/test_run_writer_replay.py @@ -21,11 +21,11 @@ from datetime import datetime, timedelta, timezone TEST_DIR = pathlib.Path(__file__).resolve().parent PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" -SCRIPT_DIR = SKILLS_DIR / "replay-writer-gate" / "scripts" -READ_CONTEXT_DIR = SKILLS_DIR / "assemble-context" / "scripts" -EVIDENCE_DIR = SKILLS_DIR / "record-run-evidence" / "scripts" -QUALITY_GATE_DIR = SKILLS_DIR / "score-content-quality" / "scripts" -GATE_ADJUDICATION_DIR = SKILLS_DIR / "adjudicate-quality-gate" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "replay" / "replay-writer-gate" / "scripts" +READ_CONTEXT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" +EVIDENCE_DIR = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" +QUALITY_GATE_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "judge" / "score-content-quality" / "scripts" +GATE_ADJUDICATION_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "mechanical" / "adjudicate-quality-gate" / "scripts" for import_path in ( SCRIPT_DIR, READ_CONTEXT_DIR, diff --git a/tests/skills/replay-writer-gate/test_writer_eval_preregister.py b/tests/skills/replay-writer-gate/test_writer_eval_preregister.py index 226dd42..65ec0ab 100644 --- a/tests/skills/replay-writer-gate/test_writer_eval_preregister.py +++ b/tests/skills/replay-writer-gate/test_writer_eval_preregister.py @@ -9,7 +9,7 @@ import sys import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "replay-writer-gate" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "replay" / "replay-writer-gate" / "scripts" if str(SCRIPT_DIR) not in sys.path: sys.path.insert(0, str(SCRIPT_DIR)) diff --git a/tests/skills/reset-work-extraction/test_reset_upgrade_work_offline.py b/tests/skills/reset-work-extraction/test_reset_upgrade_work_offline.py index 198c5d1..3d84705 100644 --- a/tests/skills/reset-work-extraction/test_reset_upgrade_work_offline.py +++ b/tests/skills/reset-work-extraction/test_reset_upgrade_work_offline.py @@ -13,9 +13,9 @@ from click.testing import CliRunner PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" -SCRIPT_DIR = SKILLS_DIR / "reset-work-extraction" / "scripts" -BACKUP_SCRIPTS = SKILLS_DIR / "backup-work-extraction" / "scripts" -EXTRACTION_SCRIPTS = SKILLS_DIR / "extract-work-knowledge" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "ingest" / "reset-work-extraction" / "scripts" +BACKUP_SCRIPTS = PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "ingest" / "backup-work-extraction" / "scripts" +EXTRACTION_SCRIPTS = PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "ingest" / "extract-work-knowledge" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) sys.path.insert(0, str(BACKUP_SCRIPTS)) sys.path.insert(0, str(EXTRACTION_SCRIPTS)) diff --git a/tests/skills/review-knowledge-cards/test_calibrate_stamp.py b/tests/skills/review-knowledge-cards/test_calibrate_stamp.py index 195b301..f32a417 100644 --- a/tests/skills/review-knowledge-cards/test_calibrate_stamp.py +++ b/tests/skills/review-knowledge-cards/test_calibrate_stamp.py @@ -8,7 +8,7 @@ from pathlib import Path import click PROJECT_ROOT = Path(__file__).resolve().parents[3] -SCRIPTS = PROJECT_ROOT / ".agent" / "skills" / "review-knowledge-cards" / "scripts" +SCRIPTS = PROJECT_ROOT / "muse" / "content" / "entity" / "skills" / "review" / "review-knowledge-cards" / "scripts" sys.path.insert(0, str(SCRIPTS)) from review_cards import ( # noqa: E402 diff --git a/tests/skills/review-knowledge-cards/test_review_lesson_offline.py b/tests/skills/review-knowledge-cards/test_review_lesson_offline.py index c4692f5..3827254 100644 --- a/tests/skills/review-knowledge-cards/test_review_lesson_offline.py +++ b/tests/skills/review-knowledge-cards/test_review_lesson_offline.py @@ -9,8 +9,8 @@ import unittest from unittest.mock import patch ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT = ROOT / ".agent" / "skills" / "review-knowledge-cards" / "scripts" -EVIDENCE = ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +SCRIPT = ROOT / "muse" / "content" / "entity" / "skills" / "review" / "review-knowledge-cards" / "scripts" +EVIDENCE = ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" for path in (SCRIPT, EVIDENCE): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/revise-ai-flavor/test_revise_ai_flavor.py b/tests/skills/revise-ai-flavor/test_revise_ai_flavor.py index 163f374..cc0cfbf 100644 --- a/tests/skills/revise-ai-flavor/test_revise_ai_flavor.py +++ b/tests/skills/revise-ai-flavor/test_revise_ai_flavor.py @@ -8,8 +8,8 @@ import unittest from unittest.mock import patch PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "revise-ai-flavor" / "scripts" -DIAGNOSE_SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "diagnose-ai-flavor" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "humanization" / "skills" / "revise-ai-flavor" / "scripts" +DIAGNOSE_SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "humanization" / "skills" / "diagnose-ai-flavor" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) sys.path.insert(0, str(DIAGNOSE_SCRIPT_DIR)) diff --git a/tests/skills/revise-ai-flavor/test_revision_lesson_offline.py b/tests/skills/revise-ai-flavor/test_revision_lesson_offline.py index 9a5ec46..0caa097 100644 --- a/tests/skills/revise-ai-flavor/test_revision_lesson_offline.py +++ b/tests/skills/revise-ai-flavor/test_revision_lesson_offline.py @@ -9,8 +9,8 @@ import unittest from unittest.mock import patch ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT = ROOT / ".agent" / "skills" / "revise-ai-flavor" / "scripts" -EVIDENCE = ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +SCRIPT = ROOT / "muse" / "lifecycle" / "quality" / "humanization" / "skills" / "revise-ai-flavor" / "scripts" +EVIDENCE = ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" for path in (SCRIPT, EVIDENCE): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/rewrite-selection/test_assert_expected_revision.py b/tests/skills/rewrite-selection/test_assert_expected_revision.py index cb278c3..d635921 100644 --- a/tests/skills/rewrite-selection/test_assert_expected_revision.py +++ b/tests/skills/rewrite-selection/test_assert_expected_revision.py @@ -4,7 +4,7 @@ import sys from pathlib import Path PROJECT_ROOT = Path(__file__).resolve().parents[3] -SCRIPTS = PROJECT_ROOT / ".agent" / "skills" / "rewrite-selection" / "scripts" +SCRIPTS = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "generate" / "rewrite-selection" / "scripts" sys.path.insert(0, str(SCRIPTS)) import click # noqa: E402 diff --git a/tests/skills/score-content-quality/test_dispatch_judge_bridge.py b/tests/skills/score-content-quality/test_dispatch_judge_bridge.py index a3059fa..acd5561 100644 --- a/tests/skills/score-content-quality/test_dispatch_judge_bridge.py +++ b/tests/skills/score-content-quality/test_dispatch_judge_bridge.py @@ -15,7 +15,7 @@ import unittest from unittest import mock PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "score-content-quality" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "judge" / "score-content-quality" / "scripts" for path in (SCRIPT_DIR,): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/score-content-quality/test_rubric.py b/tests/skills/score-content-quality/test_rubric.py index 26f7536..154bcca 100644 --- a/tests/skills/score-content-quality/test_rubric.py +++ b/tests/skills/score-content-quality/test_rubric.py @@ -7,7 +7,7 @@ import sys import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "score-content-quality" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "judge" / "score-content-quality" / "scripts" if str(SCRIPT_DIR) not in sys.path: sys.path.insert(0, str(SCRIPT_DIR)) from fine_outline_rubric import ( # noqa: E402 diff --git a/tests/skills/score-content-quality/test_run_writer_blind_judge.py b/tests/skills/score-content-quality/test_run_writer_blind_judge.py index 7628157..848802f 100644 --- a/tests/skills/score-content-quality/test_run_writer_blind_judge.py +++ b/tests/skills/score-content-quality/test_run_writer_blind_judge.py @@ -12,7 +12,7 @@ import unittest from typing import Any, Mapping PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "score-content-quality" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "judge" / "score-content-quality" / "scripts" if str(SCRIPT_DIR) not in sys.path: sys.path.insert(0, str(SCRIPT_DIR)) diff --git a/tests/skills/score-content-quality/test_score_lesson_offline.py b/tests/skills/score-content-quality/test_score_lesson_offline.py index 744e29e..f0988e8 100644 --- a/tests/skills/score-content-quality/test_score_lesson_offline.py +++ b/tests/skills/score-content-quality/test_score_lesson_offline.py @@ -9,8 +9,8 @@ import unittest from unittest.mock import patch PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "score-content-quality" / "scripts" -EVIDENCE = PROJECT_ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "judge" / "score-content-quality" / "scripts" +EVIDENCE = PROJECT_ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" for path in (SCRIPT_DIR, EVIDENCE): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/score-content-quality/test_writer_rubric.py b/tests/skills/score-content-quality/test_writer_rubric.py index 448b9d3..c22b3ab 100644 --- a/tests/skills/score-content-quality/test_writer_rubric.py +++ b/tests/skills/score-content-quality/test_writer_rubric.py @@ -8,7 +8,7 @@ import sys import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "score-content-quality" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "judge" / "score-content-quality" / "scripts" if str(SCRIPT_DIR) not in sys.path: sys.path.insert(0, str(SCRIPT_DIR)) diff --git a/tests/skills/search-knowledge/test_search.py b/tests/skills/search-knowledge/test_search.py index 556b4d7..eab49c9 100644 --- a/tests/skills/search-knowledge/test_search.py +++ b/tests/skills/search-knowledge/test_search.py @@ -8,7 +8,7 @@ import sys import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "search-knowledge" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "search-knowledge" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) from search import search_cards diff --git a/tests/skills/write-next-chapter/test_candidate_cas.py b/tests/skills/write-next-chapter/test_candidate_cas.py index 98051e7..7d06a0f 100644 --- a/tests/skills/write-next-chapter/test_candidate_cas.py +++ b/tests/skills/write-next-chapter/test_candidate_cas.py @@ -20,9 +20,9 @@ PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" TEST_DIR = PROJECT_ROOT / "tests" / "skills" / "write-next-chapter" CHECK_TEST_DIR = PROJECT_ROOT / "tests" / "skills" / "check-content-consistency" -SCRIPT_DIR = SKILLS_DIR / "write-next-chapter" / "scripts" -DETECT_DIR = SKILLS_DIR / "check-content-consistency" / "scripts" -READ_CONTEXT_DIR = SKILLS_DIR / "assemble-context" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "generate" / "write-next-chapter" / "scripts" +DETECT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "semantic" / "check-content-consistency" / "scripts" +READ_CONTEXT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" for path in (READ_CONTEXT_DIR, DETECT_DIR, SCRIPT_DIR, TEST_DIR, CHECK_TEST_DIR): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/write-next-chapter/test_candidate_cas_db.py b/tests/skills/write-next-chapter/test_candidate_cas_db.py index 139036a..536960f 100644 --- a/tests/skills/write-next-chapter/test_candidate_cas_db.py +++ b/tests/skills/write-next-chapter/test_candidate_cas_db.py @@ -19,7 +19,7 @@ from psycopg.errors import RaiseException PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" -SCRIPT_DIR = SKILLS_DIR / "write-next-chapter" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "generate" / "write-next-chapter" / "scripts" for path in (SCRIPT_DIR,): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/write-next-chapter/test_dispatch_writer_bridge.py b/tests/skills/write-next-chapter/test_dispatch_writer_bridge.py index 9e14203..e6981f4 100644 --- a/tests/skills/write-next-chapter/test_dispatch_writer_bridge.py +++ b/tests/skills/write-next-chapter/test_dispatch_writer_bridge.py @@ -13,7 +13,7 @@ import tempfile import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "write-next-chapter" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "generate" / "write-next-chapter" / "scripts" DISPATCH_TEST_DIR = PROJECT_ROOT / "tests" / "skills" / "dispatch-agent-task" CHECK_TEST_DIR = PROJECT_ROOT / "tests" / "skills" / "check-content-consistency" WNC_TEST_DIR = PROJECT_ROOT / "tests" / "skills" / "write-next-chapter" diff --git a/tests/skills/write-next-chapter/test_gate_anchor_projection.py b/tests/skills/write-next-chapter/test_gate_anchor_projection.py index 21b20a9..e383a15 100644 --- a/tests/skills/write-next-chapter/test_gate_anchor_projection.py +++ b/tests/skills/write-next-chapter/test_gate_anchor_projection.py @@ -11,7 +11,7 @@ from pathlib import Path def _load_production_entry(): path = ( Path(__file__).resolve().parents[3] - / ".agent" / "skills" / "write-next-chapter" / "scripts" / "produce_next_chapter.py" + / "muse" / "content" / "work" / "skills" / "generate" / "write-next-chapter" / "scripts" / "produce_next_chapter.py" ) spec = importlib.util.spec_from_file_location("produce_next_chapter", path) mod = importlib.util.module_from_spec(spec) diff --git a/tests/skills/write-next-chapter/test_persist_writer_run.py b/tests/skills/write-next-chapter/test_persist_writer_run.py index 758b48d..09df4dc 100644 --- a/tests/skills/write-next-chapter/test_persist_writer_run.py +++ b/tests/skills/write-next-chapter/test_persist_writer_run.py @@ -6,7 +6,7 @@ import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "write-next-chapter" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "generate" / "write-next-chapter" / "scripts" sys.path.insert(0, str(SCRIPT_DIR)) import persist_writer_run as writer_persist # noqa: E402 diff --git a/tests/skills/write-next-chapter/test_production_evidence_reassemble.py b/tests/skills/write-next-chapter/test_production_evidence_reassemble.py index 2f11e1b..179a8ec 100644 --- a/tests/skills/write-next-chapter/test_production_evidence_reassemble.py +++ b/tests/skills/write-next-chapter/test_production_evidence_reassemble.py @@ -12,8 +12,8 @@ PROJECT_ROOT = Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" TEST_DIR = PROJECT_ROOT / "tests" / "skills" / "write-next-chapter" CHECK_TEST_DIR = PROJECT_ROOT / "tests" / "skills" / "check-content-consistency" -SCRIPT_DIR = SKILLS_DIR / "write-next-chapter" / "scripts" -READ_CONTEXT_DIR = SKILLS_DIR / "assemble-context" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "generate" / "write-next-chapter" / "scripts" +READ_CONTEXT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" for path in (READ_CONTEXT_DIR, SCRIPT_DIR, TEST_DIR, CHECK_TEST_DIR): sys.path.insert(0, str(path)) diff --git a/tests/skills/write-next-chapter/test_run_writer.py b/tests/skills/write-next-chapter/test_run_writer.py index 3ec8af0..399d549 100644 --- a/tests/skills/write-next-chapter/test_run_writer.py +++ b/tests/skills/write-next-chapter/test_run_writer.py @@ -17,8 +17,8 @@ import unittest from decimal import Decimal PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "write-next-chapter" / "scripts" -READ_CONTEXT_DIR = PROJECT_ROOT / ".agent" / "skills" / "assemble-context" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "generate" / "write-next-chapter" / "scripts" +READ_CONTEXT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" TEST_CONTEXT_DIR = PROJECT_ROOT / "tests" / "skills" / "assemble-context" sys.path.insert(0, str(SCRIPT_DIR)) sys.path.insert(0, str(READ_CONTEXT_DIR)) diff --git a/tests/skills/write-next-chapter/test_run_writer_pipeline.py b/tests/skills/write-next-chapter/test_run_writer_pipeline.py index 7950bd4..faec6e7 100644 --- a/tests/skills/write-next-chapter/test_run_writer_pipeline.py +++ b/tests/skills/write-next-chapter/test_run_writer_pipeline.py @@ -16,9 +16,9 @@ PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] SKILLS_DIR = PROJECT_ROOT / ".agent" / "skills" TEST_DIR = PROJECT_ROOT / "tests" / "skills" / "write-next-chapter" CHECK_TEST_DIR = PROJECT_ROOT / "tests" / "skills" / "check-content-consistency" -SCRIPT_DIR = SKILLS_DIR / "write-next-chapter" / "scripts" -DETECT_DIR = SKILLS_DIR / "check-content-consistency" / "scripts" -READ_CONTEXT_DIR = SKILLS_DIR / "assemble-context" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "generate" / "write-next-chapter" / "scripts" +DETECT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "quality" / "skills" / "semantic" / "check-content-consistency" / "scripts" +READ_CONTEXT_DIR = PROJECT_ROOT / "muse" / "lifecycle" / "context" / "skills" / "assemble-context" / "scripts" for path in (READ_CONTEXT_DIR, DETECT_DIR, SCRIPT_DIR, TEST_DIR, CHECK_TEST_DIR): sys.path.insert(0, str(path)) diff --git a/tests/skills/write-next-chapter/test_semantic_verdict.py b/tests/skills/write-next-chapter/test_semantic_verdict.py index 58a74b0..7920740 100644 --- a/tests/skills/write-next-chapter/test_semantic_verdict.py +++ b/tests/skills/write-next-chapter/test_semantic_verdict.py @@ -15,7 +15,7 @@ import sys import unittest PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "write-next-chapter" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "generate" / "write-next-chapter" / "scripts" if str(SCRIPT_DIR) not in sys.path: sys.path.insert(0, str(SCRIPT_DIR)) diff --git a/tests/skills/write-next-chapter/test_two_phase_writer.py b/tests/skills/write-next-chapter/test_two_phase_writer.py index 1c8e662..ee77818 100644 --- a/tests/skills/write-next-chapter/test_two_phase_writer.py +++ b/tests/skills/write-next-chapter/test_two_phase_writer.py @@ -15,7 +15,7 @@ import unittest from unittest import mock PROJECT_ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT_DIR = PROJECT_ROOT / ".agent" / "skills" / "write-next-chapter" / "scripts" +SCRIPT_DIR = PROJECT_ROOT / "muse" / "content" / "work" / "skills" / "generate" / "write-next-chapter" / "scripts" for path in (SCRIPT_DIR,): if str(path) not in sys.path: sys.path.insert(0, str(path)) diff --git a/tests/skills/write-next-chapter/test_writer_lesson_offline.py b/tests/skills/write-next-chapter/test_writer_lesson_offline.py index c6574dc..e82dbb3 100644 --- a/tests/skills/write-next-chapter/test_writer_lesson_offline.py +++ b/tests/skills/write-next-chapter/test_writer_lesson_offline.py @@ -9,8 +9,8 @@ import unittest from unittest.mock import patch ROOT = pathlib.Path(__file__).resolve().parents[3] -SCRIPT = ROOT / ".agent" / "skills" / "write-next-chapter" / "scripts" -EVIDENCE = ROOT / ".agent" / "skills" / "record-run-evidence" / "scripts" +SCRIPT = ROOT / "muse" / "content" / "work" / "skills" / "generate" / "write-next-chapter" / "scripts" +EVIDENCE = ROOT / "muse" / "authority" / "evidence" / "skills" / "record-run-evidence" / "scripts" for path in (SCRIPT, EVIDENCE): if str(path) not in sys.path: sys.path.insert(0, str(path))