@mmerterden/multi-agent-pipeline 19.0.0 → 19.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +121 -0
- package/README.md +3 -3
- package/docs/ecosystem.md +12 -4
- package/docs/facts.json +20 -4
- package/docs/features.md +1 -1
- package/docs/recovery-guide.md +8 -8
- package/manifest.json +64 -62
- package/package.json +1 -1
- package/pipeline/agents/dev-critic.md +4 -4
- package/pipeline/commands/multi-agent/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/analysis/SKILL.md +6 -6
- package/pipeline/commands/multi-agent/analysis-resolve/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/resume-local/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/review/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/review-analysis/SKILL.md +1 -1
- package/pipeline/lib/model-dispatch.sh +140 -0
- package/pipeline/lib/outbound-gate.mjs +14 -0
- package/pipeline/multi-agent-refs/_dev-context.md +5 -5
- package/pipeline/multi-agent-refs/analysis/evidence.md +2 -2
- package/pipeline/multi-agent-refs/analysis/intake.md +6 -6
- package/pipeline/multi-agent-refs/analysis/locked.md +27 -0
- package/pipeline/multi-agent-refs/analysis/redesign.md +1 -1
- package/pipeline/multi-agent-refs/analysis/render.md +9 -9
- package/pipeline/multi-agent-refs/analysis/resolve.md +1 -1
- package/pipeline/multi-agent-refs/analysis/review.md +2 -2
- package/pipeline/multi-agent-refs/analysis/synthesis.md +2 -2
- package/pipeline/multi-agent-refs/analysis-template-corporate.md +9 -9
- package/pipeline/multi-agent-refs/analysis-template.md +19 -19
- package/pipeline/multi-agent-refs/component-dispatch.md +5 -5
- package/pipeline/multi-agent-refs/conventions-defaults.md +2 -2
- package/pipeline/multi-agent-refs/features/analysis-jira.md +1 -1
- package/pipeline/multi-agent-refs/features/doctor.md +1 -1
- package/pipeline/multi-agent-refs/features/model-fallback.md +36 -0
- package/pipeline/multi-agent-refs/features/review-multi-repo.md +1 -1
- package/pipeline/multi-agent-refs/features/url-enrichment.md +1 -1
- package/pipeline/multi-agent-refs/phases/phase-1-plan.md +2 -2
- package/pipeline/multi-agent-refs/phases/phase-3-review.md +2 -2
- package/pipeline/preferences-template.json +5 -0
- package/pipeline/rules/figma-pipeline.md +8 -8
- package/pipeline/schemas/analysis-output.schema.json +1 -1
- package/pipeline/schemas/analysis-spec.schema.json +2 -2
- package/pipeline/schemas/figma-project-config.schema.json +1 -1
- package/pipeline/schemas/prefs.schema.json +2 -2
- package/pipeline/schemas/secret-patterns.json +124 -0
- package/pipeline/scripts/build-references.mjs +2 -2
- package/pipeline/scripts/bulk-read.sh +10 -1
- package/pipeline/scripts/cost-table.json +8 -1
- package/pipeline/scripts/doctor.mjs +1 -1
- package/pipeline/scripts/gen-facts.mjs +112 -7
- package/pipeline/scripts/phase-tracker.sh +5 -5
- package/pipeline/scripts/pre-commit-check.sh +30 -1
- package/pipeline/scripts/scan-skills.sh +26 -0
- package/pipeline/scripts/validate-analysis-doc.mjs +201 -26
- package/pipeline/scripts/verify-citations.mjs +1 -1
- package/pipeline/scripts/write-state.mjs +32 -0
- package/pipeline/skills/.skill-manifest.json +5 -5
- package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +6 -6
- package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +6 -6
- package/pipeline/skills/shared/core/multi-agent/SKILL.md +14 -13
- package/pipeline/skills/shared/external/NOTICE-swift-ios-skills.md +1 -1
- package/pipeline/skills/shared/external/signal-community/SKILL.md +8 -1
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# model-dispatch.sh - which rung answers this call.
|
|
3
|
+
#
|
|
4
|
+
# The one place `prefs.global.modelRouting` turns into a rung. Every call site
|
|
5
|
+
# that may be routed asks here, so the policy has a single implementation and
|
|
6
|
+
# `/multi-agent:route-status` describes something real.
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# model-dispatch.sh <call-site> [--persona P] [--phase N] [--task-kind K]
|
|
10
|
+
# [--default RUNG] [--task-id ID]
|
|
11
|
+
#
|
|
12
|
+
# <call-site> is one of the `scope` members: subagent | bulk-read | research.
|
|
13
|
+
# stdout is a single rung NAME. Rung names are the contract; the model id behind
|
|
14
|
+
# one lives in cost-table.json and moves without a config edit.
|
|
15
|
+
#
|
|
16
|
+
# Exit is always 0 and stdout is always a usable rung. A router that can fail
|
|
17
|
+
# turns every call site into a place the run can die, for a feature that ships
|
|
18
|
+
# disabled; when anything is missing, unparseable or out of scope, the caller's
|
|
19
|
+
# default comes back unchanged.
|
|
20
|
+
#
|
|
21
|
+
# Two layers, and the difference is the safety argument the schema spells out:
|
|
22
|
+
#
|
|
23
|
+
# Layer 1 an Anthropic rung. Reachable from every call site, because it
|
|
24
|
+
# writes to a seam that already exists and opens no new network path.
|
|
25
|
+
# Layer 2 a non-Anthropic rung. Reachable ONLY from a call site the pipeline
|
|
26
|
+
# makes itself. A subagent is dispatched by the HOST, so a rule that
|
|
27
|
+
# prefers an external rung for a subagent cannot be honoured - and
|
|
28
|
+
# this script says so on stderr rather than pretending it was.
|
|
29
|
+
|
|
30
|
+
set -uo pipefail
|
|
31
|
+
|
|
32
|
+
CALL_SITE="${1:-}"
|
|
33
|
+
shift || true
|
|
34
|
+
|
|
35
|
+
PERSONA=""; PHASE=""; TASK_KIND=""; DEFAULT_RUNG=""; TASK_ID="${MULTI_AGENT_TASK_ID:-unknown}"
|
|
36
|
+
while [ $# -gt 0 ]; do
|
|
37
|
+
case "$1" in
|
|
38
|
+
--persona) PERSONA="${2:-}"; shift 2 ;;
|
|
39
|
+
--phase) PHASE="${2:-}"; shift 2 ;;
|
|
40
|
+
--task-kind) TASK_KIND="${2:-}"; shift 2 ;;
|
|
41
|
+
--default) DEFAULT_RUNG="${2:-}"; shift 2 ;;
|
|
42
|
+
--task-id) TASK_ID="${2:-}"; shift 2 ;;
|
|
43
|
+
*) shift ;;
|
|
44
|
+
esac
|
|
45
|
+
done
|
|
46
|
+
|
|
47
|
+
emit() { printf '%s\n' "$1"; exit 0; }
|
|
48
|
+
|
|
49
|
+
case "$CALL_SITE" in
|
|
50
|
+
subagent|bulk-read|research) ;;
|
|
51
|
+
*) emit "$DEFAULT_RUNG" ;;
|
|
52
|
+
esac
|
|
53
|
+
|
|
54
|
+
[ -n "$DEFAULT_RUNG" ] || DEFAULT_RUNG="sonnet"
|
|
55
|
+
|
|
56
|
+
command -v jq >/dev/null 2>&1 || emit "$DEFAULT_RUNG"
|
|
57
|
+
|
|
58
|
+
PREFS=""
|
|
59
|
+
for candidate in \
|
|
60
|
+
"${MULTI_AGENT_PREFS:-}" \
|
|
61
|
+
"$HOME/.claude/multi-agent-preferences.json" \
|
|
62
|
+
"$HOME/.config/multi-agent-pipeline/multi-agent-preferences.json"
|
|
63
|
+
do
|
|
64
|
+
[ -n "$candidate" ] && [ -f "$candidate" ] && { PREFS="$candidate"; break; }
|
|
65
|
+
done
|
|
66
|
+
[ -n "$PREFS" ] || emit "$DEFAULT_RUNG"
|
|
67
|
+
|
|
68
|
+
ENABLED=$(jq -r '.global.modelRouting.enabled // false' "$PREFS" 2>/dev/null) || emit "$DEFAULT_RUNG"
|
|
69
|
+
[ "$ENABLED" = "true" ] || emit "$DEFAULT_RUNG"
|
|
70
|
+
|
|
71
|
+
# Out of scope is not a failure and not a warning. The user named the call sites
|
|
72
|
+
# routing may touch; the ones they left out keep their existing behaviour, which
|
|
73
|
+
# is the point of naming them.
|
|
74
|
+
IN_SCOPE=$(jq -r --arg cs "$CALL_SITE" \
|
|
75
|
+
'((.global.modelRouting.scope // ["subagent"]) | index($cs)) != null' "$PREFS" 2>/dev/null)
|
|
76
|
+
[ "$IN_SCOPE" = "true" ] || emit "$DEFAULT_RUNG"
|
|
77
|
+
|
|
78
|
+
# First rule whose every stated condition matches. A `when` with three keys has
|
|
79
|
+
# to match on all three - the schema requires at least one, so an always-matching
|
|
80
|
+
# rule cannot be written by accident.
|
|
81
|
+
MATCH=$(jq -r \
|
|
82
|
+
--arg persona "$PERSONA" --arg phase "$PHASE" --arg kind "$TASK_KIND" \
|
|
83
|
+
'[ (.global.modelRouting.rules // [])[]
|
|
84
|
+
| select(
|
|
85
|
+
((.when.persona // null) as $p | $p == null or $p == $persona)
|
|
86
|
+
and ((.when.phase // null) as $h | $h == null or ($phase != "" and ($h | tostring) == $phase))
|
|
87
|
+
and ((.when.taskKind // null) as $k | $k == null or $k == $kind)
|
|
88
|
+
)
|
|
89
|
+
] | first | (.prefer // []) | join(" ")' "$PREFS" 2>/dev/null) || emit "$DEFAULT_RUNG"
|
|
90
|
+
[ -n "$MATCH" ] && [ "$MATCH" != "null" ] || emit "$DEFAULT_RUNG"
|
|
91
|
+
|
|
92
|
+
HERE="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
93
|
+
COST_TABLE="$HERE/../scripts/cost-table.json"
|
|
94
|
+
|
|
95
|
+
# The fable rung answers only when the fable switch is on. Routing is a policy
|
|
96
|
+
# over what is available; it is not a second way to turn a rung on, or
|
|
97
|
+
# `/multi-agent:model off` would stop meaning anything the moment a rule named
|
|
98
|
+
# fable.
|
|
99
|
+
FABLE_ON=$(jq -r '.global.modelFallback.fableEnabled // false' "$PREFS" 2>/dev/null)
|
|
100
|
+
|
|
101
|
+
record() {
|
|
102
|
+
[ -x "$HERE/../scripts/log-metric.sh" ] || return 0
|
|
103
|
+
local rec
|
|
104
|
+
rec=$(jq -r '.global.modelRouting.recordDecisions // true' "$PREFS" 2>/dev/null)
|
|
105
|
+
[ "$rec" = "false" ] && return 0
|
|
106
|
+
"$HERE/../scripts/log-metric.sh" "$TASK_ID" "${PHASE:-0}" model_routing.decision \
|
|
107
|
+
call_site="$CALL_SITE" rung="$1" reason="$2" >/dev/null 2>&1 || true
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
for rung in $MATCH; do
|
|
111
|
+
if [ ! -f "$COST_TABLE" ]; then
|
|
112
|
+
record "$rung" "no cost table; rung taken on trust"
|
|
113
|
+
emit "$rung"
|
|
114
|
+
fi
|
|
115
|
+
PROVIDER=$(jq -r --arg r "$rung" '.prices[$r].provider // ""' "$COST_TABLE" 2>/dev/null)
|
|
116
|
+
# A rung nobody priced is a typo in a config far more often than it is a new
|
|
117
|
+
# model. Skipping it silently would route to the next one and leave the user
|
|
118
|
+
# certain their rule applied.
|
|
119
|
+
if [ -z "$PROVIDER" ]; then
|
|
120
|
+
echo "model-dispatch: rung '$rung' is not in cost-table.json; skipping it" >&2
|
|
121
|
+
continue
|
|
122
|
+
fi
|
|
123
|
+
if [ "$rung" = "fable" ] && [ "$FABLE_ON" != "true" ]; then
|
|
124
|
+
echo "model-dispatch: rule prefers 'fable' but modelFallback.fableEnabled is false; skipping it" >&2
|
|
125
|
+
continue
|
|
126
|
+
fi
|
|
127
|
+
if [ "$PROVIDER" != "anthropic" ] && [ "$CALL_SITE" = "subagent" ]; then
|
|
128
|
+
# The honest limit, said out loud at the moment it bites. Subagent dispatch
|
|
129
|
+
# belongs to the host; we cannot send one to another provider, and a router
|
|
130
|
+
# that quietly downgraded to an Anthropic rung here would leave the user
|
|
131
|
+
# believing a rule worked that never could.
|
|
132
|
+
echo "model-dispatch: rung '$rung' is $PROVIDER and subagent dispatch belongs to the host; skipping it" >&2
|
|
133
|
+
continue
|
|
134
|
+
fi
|
|
135
|
+
record "$rung" "rule matched"
|
|
136
|
+
emit "$rung"
|
|
137
|
+
done
|
|
138
|
+
|
|
139
|
+
record "$DEFAULT_RUNG" "every preferred rung was unavailable"
|
|
140
|
+
emit "$DEFAULT_RUNG"
|
|
@@ -68,6 +68,20 @@ export const RULES = [
|
|
|
68
68
|
{ name: "anthropic-key", certain: true, re: /\bsk-ant-[A-Za-z0-9_-]{32,}\b/g },
|
|
69
69
|
{ name: "figma-token", certain: true, re: /\bfig[a-z]_[A-Za-z0-9_-]{20,}\b/g },
|
|
70
70
|
{ name: "npm-token", certain: true, re: /\bnpm_[A-Za-z0-9]{36}\b/g },
|
|
71
|
+
// This list and the one in scripts/pre-commit-check.sh cover the same
|
|
72
|
+
// provider set. smoke-secret-parity.sh holds them to it by running a fake
|
|
73
|
+
// token of each shape through both, rather than comparing the regexes: a
|
|
74
|
+
// pattern that matches in one dialect and not the other reads as agreement
|
|
75
|
+
// and is not.
|
|
76
|
+
{ name: "gitlab-pat", certain: true, re: /\bglpat-[A-Za-z0-9_-]{20,}\b/g },
|
|
77
|
+
{ name: "stripe-key", certain: true, re: /\b[sr]k_live_[A-Za-z0-9]{20,}\b/g },
|
|
78
|
+
{ name: "perplexity-key", certain: true, re: /\bpplx-[A-Za-z0-9]{32,}\b/g },
|
|
79
|
+
{ name: "huggingface-token", certain: true, re: /\bhf_[A-Za-z0-9]{30,}\b/g },
|
|
80
|
+
{
|
|
81
|
+
name: "service-account-json",
|
|
82
|
+
certain: true,
|
|
83
|
+
re: /"type"\s*:\s*"service_account"/g,
|
|
84
|
+
},
|
|
71
85
|
{
|
|
72
86
|
name: "jwt",
|
|
73
87
|
certain: true,
|
|
@@ -63,7 +63,7 @@ Selects extra repos the pipeline may touch beyond the primary repo(s) - typica
|
|
|
63
63
|
entry, plus any selected `extras[]` that is not being given a worktree. The
|
|
64
64
|
phases that consume them run hours later and have no access to the picker's
|
|
65
65
|
return value, so a result that is not written here is a result nothing can
|
|
66
|
-
read. Phase
|
|
66
|
+
read. Phase 3's platform-parity cross-check reads `state.siblings[]` as the
|
|
67
67
|
fourth of its four counterpart sources, after `--with`,
|
|
68
68
|
`prefs.projects[<slug>].counterpartRoots[]` and the primary checkout's sibling
|
|
69
69
|
directories (`platform-parity.md`), so a submodule or a hand-picked repo that
|
|
@@ -142,14 +142,14 @@ When `MULTI_AGENT_AUTOPILOT=1`:
|
|
|
142
142
|
|
|
143
143
|
## Pipeline contract for read-only siblings
|
|
144
144
|
|
|
145
|
-
When a read-only sibling is present (e.g. a vendored SDK checkout), Phase
|
|
145
|
+
When a read-only sibling is present (e.g. a vendored SDK checkout), Phase 2 (Dev) MUST:
|
|
146
146
|
- Treat it as **read-only context** - code may be read for understanding, never edited or committed.
|
|
147
147
|
- Prefer solving the task in the primary repo(s) (e.g. by wrapping/extending in consumer code) rather than patching the sibling.
|
|
148
|
-
- Surface this constraint in the Phase
|
|
148
|
+
- Surface this constraint in the Phase 2 plan output so reviewers know why a workaround was chosen.
|
|
149
149
|
|
|
150
150
|
A **counterpart app repo** is a legitimate read-only sibling: the same product's
|
|
151
|
-
other mobile platform, added here so Phase
|
|
152
|
-
Phase
|
|
151
|
+
other mobile platform, added here so Phase 3 can compare the change against it.
|
|
152
|
+
Phase 2 treats it exactly like any other sibling - read, never edited. Phase 3
|
|
153
153
|
additionally runs the parity cross-check over it
|
|
154
154
|
(`$HOME/.claude/multi-agent-refs/platform-parity.md`), which is also read-only.
|
|
155
155
|
Adding one is worthwhile when the feature exists on both platforms and their
|
|
@@ -164,7 +164,7 @@ The index answers "does this component exist and is it bound". It does not answe
|
|
|
164
164
|
|
|
165
165
|
Output: `state.analysisSpec.evidence.variantMatrix[<component>] = { axis, allValues[], usedValues[] }`, which fills Section 6.X.
|
|
166
166
|
|
|
167
|
-
Why it lives here and nowhere later: Locked
|
|
167
|
+
Why it lives here and nowhere later: Locked 29 forbids Figma access from Phase 2 onward, so an axis not captured now cannot be recovered - Section 13.6 Preview and Section 15.2 Snapshot would then be validated against a subset nobody could check.
|
|
168
168
|
|
|
169
169
|
A component with no variant axis (a plain component, not a set) records `axis: null` and is not a finding.
|
|
170
170
|
|
|
@@ -202,7 +202,7 @@ Phase 2 Section 20 Risks reads this list and emits one open question per entry.
|
|
|
202
202
|
|
|
203
203
|
**Fallback source**: when `confidence == "none"` AND `evidence.standards[]` does not contain an explicit rule for that field, the renderer reads `$HOME/.claude/multi-agent-refs/conventions-defaults.md` and applies the platform default.
|
|
204
204
|
|
|
205
|
-
**Caching (Locked
|
|
205
|
+
**Caching (Locked 26)**: compute `evidence_digest = sha256(featureName || sorted(platforms) || options.redesign || hash(evidence.repoEvidence) || hash(evidence.conventions))`. `options.redesign` is a digest input: without it a redesign within a day of a normal run on the same feature reuses that cache, skips Phase 1b, and renders an empty current-behaviour table every redesign check then passes over. Cache key on disk: `/tmp/multi-agent-analysis-cache/<digest>.json` with mtime <= 24h. Cache hit skips Phase 1b and Phase 1c. `--no-cache` flag forces re-run.
|
|
206
206
|
|
|
207
207
|
Phase 1d is deliberately absent from the digest inputs. Community signal changes by the hour, so folding it in would produce a new digest on every run, invalidate the cache every time, and re-run the two expensive repo phases the cache exists to skip. The consequence is worth stating plainly: a cache hit reuses yesterday's signal rows. That is the correct trade for an advisory tier, and `--no-cache` is the way to refresh them.
|
|
208
208
|
|
|
@@ -19,7 +19,7 @@ Result: `state.analysisSpec.featureName` (state key kept for backward compatibil
|
|
|
19
19
|
|
|
20
20
|
#### Step 1b - Analysis profile
|
|
21
21
|
|
|
22
|
-
Asked once, immediately after the analysis name and before anything is fetched, because the profile decides which template the whole run renders against (Locked
|
|
22
|
+
Asked once, immediately after the analysis name and before anything is fetched, because the profile decides which template the whole run renders against (Locked 31). Never re-asked mid-run.
|
|
23
23
|
|
|
24
24
|
Read the available profiles from `prefs.global.analysisProfiles` (default `["global", "corporate"]`). When only one is available, auto-resolve and print the breadcrumb with the resolution noted rather than asking a question whose answer is already settled.
|
|
25
25
|
|
|
@@ -36,7 +36,7 @@ options:
|
|
|
36
36
|
|
|
37
37
|
Result: `state.analysisSpec.profile` (`global` | `corporate`). Empty submit re-asks; an empty answer does not imply the default (`feedback_no-inferred-defaults-from-empty-answer`).
|
|
38
38
|
|
|
39
|
-
The profile changes nothing about intake, fetching, repo evidence or convention extraction - those are shared. It selects the template at Phase 3 and switches the omission rule for the corporate backbone (Locked
|
|
39
|
+
The profile changes nothing about intake, fetching, repo evidence or convention extraction - those are shared. It selects the template at Phase 3 and switches the omission rule for the corporate backbone (Locked 32).
|
|
40
40
|
|
|
41
41
|
**Corporate profile bindings.** Publication targets and house terminology are read from `prefs.global.analysisProfile.corporate` when present: `confluenceSpaceKey`, `confluenceParentPageId`, `titleFormat`, `titlePrefix`, `apiSpecCommand` and a `glossary` map. The key set is closed in `prefs.schema.json`, so a typo is caught by `validate-prefs.mjs` rather than silently ignored at emit time. They are deployment configuration, not part of the shipped template: an unconfigured corporate run still renders the full document and asks for the destination at Phase 3.5 like any other run.
|
|
42
42
|
|
|
@@ -69,13 +69,13 @@ Empty submit → re-ask. Result: `state.analysisSpec.platforms[]`.
|
|
|
69
69
|
`web` is the canonical id; the pre-rename `frontend` is still read back (older state,
|
|
70
70
|
`:stack frontend`, the `ai-frontend-toolkit` plugin id) and normalises to `web`.
|
|
71
71
|
|
|
72
|
-
**`No platform yet` is a real answer, not a cancel** (Locked
|
|
72
|
+
**`No platform yet` is a real answer, not a cancel** (Locked 34). It leaves
|
|
73
73
|
`platforms[]` empty, skips Step 4 entirely, and the run continues: evidence is still
|
|
74
74
|
fetched from every declared source, and the document renders every layer that does not
|
|
75
75
|
need a target repository. Only the development layer and the Pass B projection drop,
|
|
76
76
|
and Section 20 records that they await a repo selection.
|
|
77
77
|
|
|
78
|
-
**The channel split is then derived from the evidence, not abandoned** (Locked
|
|
78
|
+
**The channel split is then derived from the evidence, not abandoned** (Locked 34,
|
|
79
79
|
which carries the reasoning). After evidence collection, classify the run's channels
|
|
80
80
|
from what the sources say:
|
|
81
81
|
|
|
@@ -135,7 +135,7 @@ tool call, and an improvised retry separates the spec sources from each other.
|
|
|
135
135
|
- **Batch 2/2 - what constrains it**: Swagger, Standards, Firebase.
|
|
136
136
|
|
|
137
137
|
**Development-layer questions are gated on a platform being selected.** With
|
|
138
|
-
`platforms[]` empty that layer does not render (Locked
|
|
138
|
+
`platforms[]` empty that layer does not render (Locked 34), so a question feeding only
|
|
139
139
|
it spends attention on an answer nothing consumes.
|
|
140
140
|
|
|
141
141
|
Two questions feed only that layer and are therefore skipped:
|
|
@@ -270,7 +270,7 @@ layer; `options.a11yDepth` gates the Section 16 VoiceOver / TalkBack walkthrough
|
|
|
270
270
|
does not. Both default to the lighter choice so the doc stays lean unless the user opts in.
|
|
271
271
|
|
|
272
272
|
`options.redesign` gates Sections 4.5, 4.6 and 9.5 and loads `analysis/redesign.md`, read
|
|
273
|
-
on no other run (Locked
|
|
273
|
+
on no other run (Locked 36).
|
|
274
274
|
|
|
275
275
|
#### Step 5b - Repo-evidence collector (automatic, no prompt)
|
|
276
276
|
|
|
@@ -16,6 +16,33 @@ Browse-friendly grouping of the 36 Locked decisions. Numbering stays canonical (
|
|
|
16
16
|
|
|
17
17
|
When citing a Locked decision in code or docs, prefer `Locked <n> (<short label>)` form so the category is inferable (e.g. `Locked 30 (analysis self-contained, category B)`).
|
|
18
18
|
|
|
19
|
+
### Gate status
|
|
20
|
+
|
|
21
|
+
Which of the 36 a script enforces. An unmarked decision reads as enforced.
|
|
22
|
+
|
|
23
|
+
**Gated (18):** 2, 7, 13, 14, 15, 16, 17, 18, 21, 24, 28, 30, 32, 35, 36 by
|
|
24
|
+
`validate-analysis-doc.mjs`; 29 by `smoke-analysis-mode.sh`; 33 by
|
|
25
|
+
`build-references.mjs --check`; 34 by `smoke-validate-analysis-doc.sh`. Each has
|
|
26
|
+
a smoke of its own.
|
|
27
|
+
|
|
28
|
+
**Not gated (18):** 1, 3, 4, 5, 6, 8, 9, 10, 11, 12, 19, 20, 22, 23, 25, 26, 27,
|
|
29
|
+
31. Breaking one produces a worse document, not a failing run. Two read like
|
|
30
|
+
gates and are not: 12 opens "MUST: Figma access", 23 "Convention extraction
|
|
31
|
+
mandatory". Both are model-applied.
|
|
32
|
+
|
|
33
|
+
A gate checks a SHAPE the template prescribes, never whether it was filled
|
|
34
|
+
honestly: 13 asks if a scenario is Gherkin, not if it is the right one. The rest
|
|
35
|
+
stays prose because it is run behaviour no document records (5, 6, 10, 25),
|
|
36
|
+
evidence gathered before rendering (11, 12, 19, 23, 26), or judgement about
|
|
37
|
+
meaning (3, 4, 8, 9, 20, 22, 27, 31).
|
|
38
|
+
|
|
39
|
+
A decision counts as gated only when a script names it in the message it fails
|
|
40
|
+
with: that message is what the attribution check reads.
|
|
41
|
+
|
|
42
|
+
`smoke-locked-citations.sh` checks these two lists against what the scripts
|
|
43
|
+
actually enforce, so a decision that gains or loses a gate cannot leave them
|
|
44
|
+
behind.
|
|
45
|
+
|
|
19
46
|
### Full list
|
|
20
47
|
|
|
21
48
|
1. **One feature per run.** Every Figma URL, Confluence page, Jira ID, and Standards source the user supplies belongs to the **same feature**. The command never asks "which feature is this for?" or "which URL is primary?". Mixed inputs covering multiple features are treated as user error: surface the conflict, stop, and ask the user to split into separate runs.
|
|
@@ -111,7 +111,7 @@ All in `validate-analysis-doc.mjs`, all live only when the front-matter says
|
|
|
111
111
|
|
|
112
112
|
## The cache, and the silent failure to avoid
|
|
113
113
|
|
|
114
|
-
`evidence_digest` (Locked
|
|
114
|
+
`evidence_digest` (Locked 26) summarises `featureName || platforms ||
|
|
115
115
|
repoEvidence || conventions`, with a 24-hour TTL. `options.redesign` **is a
|
|
116
116
|
digest input**. Without it, a redesign started within a day of a normal run on
|
|
117
117
|
the same feature hits that run's cache, skips Phase 1b entirely, and renders a
|
|
@@ -6,11 +6,11 @@
|
|
|
6
6
|
|
|
7
7
|
1. **Language resolution**: read `prefs.global.outputLanguage` (`tr` or `en`, default `tr`). Use the `Output language matrix` table in `$HOME/.claude/multi-agent-refs/analysis-template.md` to swap headings and system strings.
|
|
8
8
|
|
|
9
|
-
1b. **Template selection** (Locked
|
|
9
|
+
1b. **Template selection** (Locked 31): read `state.analysisSpec.profile`. `global` renders against `$HOME/.claude/multi-agent-refs/analysis-template.md`; `corporate` renders against `$HOME/.claude/multi-agent-refs/analysis-template-corporate.md`. The evidence is the same either way - this step chooses the projection, nothing else. In the corporate profile the Part A backbone and the footer render even with zero evidence, carrying `N/A` or `EKLENECEK`, and each `EKLENECEK` emits its Section 20 row (Locked 32).
|
|
10
10
|
|
|
11
11
|
2. **Markdown render**: for each platform in `state.analysisSpec.platforms[]`, concatenate the per-platform spec into one markdown file. Tables in pipe-syntax. Numbering uses plain `## 1.`, `## 2.`, ... - omitted sections do **not** create gaps. Visible numbering is sequential 1..N over the rendered set. In the corporate profile the Part A and footer numbers are fixed and do not re-flow, since the backbone never drops; Part B and Part C follow the omission table as usual.
|
|
12
12
|
|
|
13
|
-
**When `platforms[]` is empty** (Locked
|
|
13
|
+
**When `platforms[]` is empty** (Locked 34), the channels come from the evidence instead of from repo stack tags, so this loop runs once per derived channel (`mobile`, `web`, or one channel-agnostic pass). What drops is the development layer (corporate Part C, global Sections 13, 14, 15) and the Pass B projection are skipped, Section 20 carries a row recording that they await a repo selection, and the front-matter `platform` key reads `none`. Everything that does not need a target repository still renders in full.
|
|
14
14
|
|
|
15
15
|
3. **Humanizer pass (required: actually invoke the `ai-common-toolkit:humanizer` skill on the rendered markdown - the punctuation grep alone does NOT satisfy this step)** (`technical-explanatory` tone for the scratch buffer; per-channel re-humanize happens in Phase 4 when actually emitting):
|
|
16
16
|
```
|
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
**Explicit punctuation policy** (enforced by `stripFancyPunctuation: true`): no em-dash (U+2014), no en-dash (U+2013), no horizontal ellipsis (U+2026), no curly quotes (U+2018, U+2019, U+201C, U+201D), no section sign (U+00A7). The humanizer replaces these with ASCII equivalents (`-`, `:`, `,`, `...`, `'`, `"`, and `bölüm` / `section` for the section sign per `outputLanguage`) before emit. Tables, code blocks, URLs, and front-matter YAML are exempt. Post-emit verification runs through `node $HOME/.claude/scripts/validate-analysis-doc.mjs <file>`, which checks this policy deterministically in Node on all three operating systems. Do NOT verify with `grep -P`: BSD grep (macOS, the pipeline's primary platform) has no `-P`, so that command never runs and "zero matches" is trivially true. The per-language readability rules (Turkish sentence shape, nominalization chains, which terms stay untranslated) live in the humanizer skill itself, not here; this paragraph owns only the punctuation policy the validator enforces. **Diacritics are PRESERVED, not stripped: this policy targets ONLY the listed fancy-punctuation codepoints. Turkish letters (ş/Ş, ç/Ç, ğ/Ğ, ı/I, İ, ö/Ö, ü/Ü) and all other `outputLanguage` letters MUST stay verbatim. Never ASCII-fold the prose - emit `Geliştirme Özeti`, `için`, `Kullanıcı Hikayeleri`, NOT `Gelistirme Ozeti`, `icin`, `Kullanici`. ASCII-folded Turkish is a humanizer-skipped smell and fails review.**
|
|
25
25
|
|
|
26
|
-
3b. **Build Section 21 References** (Locked
|
|
26
|
+
3b. **Build Section 21 References** (Locked 33): emit the table with
|
|
27
27
|
|
|
28
28
|
```bash
|
|
29
29
|
node "$HOME/.claude/scripts/build-references.mjs" <state.json> --lang "$OUTPUT_LANGUAGE"
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
|
|
32
32
|
and paste its output under the References heading. The model does not hand-write this table; it is a projection of `state.analysisSpec.evidence.*`, which is what keeps a source the run actually read from going unlisted and a remembered-but-unread source from appearing.
|
|
33
33
|
|
|
34
|
-
4. **Write scratch drafts**: create `/tmp/analysis-<feature-slug>-<UTC-iso8601>/` and write `<feature>-<platform>.md` per selected platform. With `platforms[]` empty, write one file per derived channel (`<feature>-mobile.md`, `<feature>-web.md`; Locked
|
|
34
|
+
4. **Write scratch drafts**: create `/tmp/analysis-<feature-slug>-<UTC-iso8601>/` and write `<feature>-<platform>.md` per selected platform. With `platforms[]` empty, write one file per derived channel (`<feature>-mobile.md`, `<feature>-web.md`; Locked 34), or a single `<feature>.md` when the evidence describes no interface. Update `state.analysisSpec.outputs.draftDir` with the path.
|
|
35
35
|
|
|
36
36
|
5. **Surface the draft tree to the user**:
|
|
37
37
|
```
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
|
|
45
45
|
### Phase 3.2 - Draft review (BLOCKING, runs in every mode)
|
|
46
46
|
|
|
47
|
-
Locked
|
|
47
|
+
Locked 35 carries the rule. Operationally:
|
|
48
48
|
|
|
49
49
|
1. Run `phases/phase-3-review.md` Step 0, the analysis-mode branch. It already defines
|
|
50
50
|
the strict validator, the host's three-reviewer set with its model routing, and the
|
|
@@ -128,15 +128,15 @@ for f in /tmp/analysis-<feature-slug>-<ts>/*.md; do
|
|
|
128
128
|
done
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
-
`validate-analysis-doc.mjs` enforces the mechanically-checkable Locked decisions on the emitted markdown itself (front-matter completeness, never-omitted sections per Locked 2, humanizer punctuation per Locked 7, Full-mode business-rule traceability per Locked
|
|
131
|
+
`validate-analysis-doc.mjs` enforces the mechanically-checkable Locked decisions on the emitted markdown itself (front-matter completeness, never-omitted sections per Locked 2, humanizer punctuation per Locked 7, Full-mode business-rule traceability per Locked 30, and in the corporate profile the backbone presence and `EKLENECEK`-to-Section-20 pairing per Locked 32). `build-references.mjs --check` runs the References coverage gate (Locked 33): a source the run consumed but did not list, or a listed row with no evidence behind it, blocks dispatch. `verify-citations.mjs` resolves each claimed `file:line` at HEAD with `git cat-file`, so `Foo.swift:9999` in a repo with no Foo.swift blocks dispatch (Locked 3, Locked 36). Any ERROR blocks dispatch: fix the draft and re-validate. Warnings are advisory (run with `--strict` to treat them as blocking). This turns the "fails the dispatch gate" prose into a real, model-independent check.
|
|
132
132
|
|
|
133
133
|
Iterate `state.analysisSpec.outputs.requested`. For each target:
|
|
134
134
|
|
|
135
135
|
| Target | Action |
|
|
136
136
|
|--------|--------|
|
|
137
|
-
| Local | For each per-platform draft, `cp /tmp/analysis-<feature-slug>-<ts>/<feature>-<platform>.md` into `analysis/<feature>-<platform>.md` in the matching repo's working tree. When multiple repos exist for the same platform, the file is duplicated into each and the dispatch report lists every destination. **When no repo was selected** (Locked
|
|
138
|
-
| Confluence | Re-humanize each draft with `formal-stakeholder` tone. One page per draft under the chosen parent, titled `<Feature> - <Platform>` - including a repo-less run, whose drafts are the derived channels (`<Feature> - Mobile` / `<Feature> - Web`, Locked
|
|
139
|
-
| Jira | Re-humanize the combined body with `informal-technical` tone. Concatenate the drafts under `h2. Platform: <X>` separators in production order - `iOS`, `Android`, `Web`, `Backend` repo-backed, `Mobile` / `Web` for channels derived on a repo-less run (Locked
|
|
137
|
+
| Local | For each per-platform draft, `cp /tmp/analysis-<feature-slug>-<ts>/<feature>-<platform>.md` into `analysis/<feature>-<platform>.md` in the matching repo's working tree. When multiple repos exist for the same platform, the file is duplicated into each and the dispatch report lists every destination. **When no repo was selected** (Locked 34) there is no working tree to be relative to, so files land in `~/Desktop/multiAgentAnalysis/<feature-name>/`, one per derived channel (`<feature>-mobile.md`, `<feature>-web.md`) or a single `<feature>.md` when none could be derived. The current working directory is never written to: for a repo-less run it is arbitrary, and creating a folder in whatever directory the command happened to be invoked from is the kind of surprise that costs a tool its trust. The user can override the path through the picker's Other input. **No commit.** |
|
|
138
|
+
| Confluence | Re-humanize each draft with `formal-stakeholder` tone. One page per draft under the chosen parent, titled `<Feature> - <Platform>` - including a repo-less run, whose drafts are the derived channels (`<Feature> - Mobile` / `<Feature> - Web`, Locked 34). A single channel-agnostic draft becomes one page titled `<Feature>`, with no suffix implying a split that was not made. Cross-link siblings inside each page via `<ac:link><ri:page ri:content-title="<Feature> - <OtherPlatform>"/></ac:link>`; a lone page has no sibling block. Markdown -> storage XML via `$HOME/.claude/multi-agent-refs/channels/confluence.md`. Re-emit on existing pages uses PUT with version bump. |
|
|
139
|
+
| Jira | Re-humanize the combined body with `informal-technical` tone. Concatenate the drafts under `h2. Platform: <X>` separators in production order - `iOS`, `Android`, `Web`, `Backend` repo-backed, `Mobile` / `Web` for channels derived on a repo-less run (Locked 34). A single channel-agnostic draft gets no separator: a heading announcing a split of one is noise. then run the whole body through the markdown → Jira wiki conversion table in `$HOME/.claude/multi-agent-refs/channels/jira.md` - both the comment body and the `description` field render wiki markup, so raw `##`/`**`/backticks arrive as literal text. Write the converted body to a file and publish it with `$HOME/.claude/lib/jira-publish.sh`, never with a hand-rolled `curl`: <br><br>`bash "$HOME/.claude/lib/jira-publish.sh" --issue "$KEY" --body-file "$F" --target comment` <br>`bash "$HOME/.claude/lib/jira-publish.sh" --issue "$KEY" --body-file "$F" --target description --mode append` <br><br>The script owns the parts that are easy to get wrong: it runs `jira-wiki-escape.mjs` on the body, resolves host + token without putting either in argv, and on the description path it GETs the current value, writes it to a backup under `~/.claude/logs/multi-agent/jira-backups/` and reports the path, appends below a `----` rule by default, and **refuses with exit 3** when `--mode replace` would discard a non-empty description unless `--confirm-overwrite` is passed. Exit 3 is reported to the user with the backup path, never retried with the flag added automatically - only the user's explicit "Description - replace" answer from Phase 3.5 supplies it. `--dry-run` previews the exact final body without writing. |
|
|
140
140
|
|
|
141
141
|
**Output capture**: fill `state.analysisSpec.outputs.localPaths[]` (one entry per per-platform-per-repo write, or one per derived channel on a repo-less run), `outputs.confluencePageUrls[]` (one entry per emitted document), `outputs.confluencePages[]` (the same pages by IDENTITY - `pageId`, `title`, `space`, `channel` - because a write-back needs the id and a `/display/SPACE/Title` URL cannot be parsed for one), `outputs.jiraIssueKey` (single string).
|
|
142
142
|
|
|
@@ -37,7 +37,7 @@
|
|
|
37
37
|
| `citation-tbd` | row originated from a `[label TBD - see Open Questions]` downgrade (Locked 3) | repo localization keys / Figma evidence already cited elsewhere in the doc |
|
|
38
38
|
| `legacy-decision` | row phrased `current code does X; should the new feature keep, change, or drop this?` (Locked 4) | repo lookup confirms current behavior with `file:line` |
|
|
39
39
|
| `standards-conflict` | row cites a binding standards source (Locked 8) | quote the binding section verbatim from References |
|
|
40
|
-
| `design-gap` | row needs new Figma/design information (tier-3 forced questions, missing variants per Locked 12/19) | NONE - Locked
|
|
40
|
+
| `design-gap` | row needs new Figma/design information (tier-3 forced questions, missing variants per Locked 12/19) | NONE - Locked 29; offer only Defer + the re-run recommendation |
|
|
41
41
|
| `generic` | anything else | all three standard sources |
|
|
42
42
|
|
|
43
43
|
4. **Batched repo lookup** (single Explore subagent, one call regardless of row count; skip if every row classified `design-gap`):
|
|
@@ -66,13 +66,13 @@ Parallel model review, same shape as `/multi-agent:review`: 3 models on Claude C
|
|
|
66
66
|
- Each business requirement or rule is testable: two readers cannot disagree about whether it passed.
|
|
67
67
|
- Nothing important is deferred to a conversation the reader was not in.
|
|
68
68
|
|
|
69
|
-
**B. Evidence** (Locked 3, 4,
|
|
69
|
+
**B. Evidence** (Locked 3, 4, 33)
|
|
70
70
|
|
|
71
71
|
- Every quoted string, endpoint, status code and event name carries a citation.
|
|
72
72
|
- Nothing in a forward-looking section is actually a description of the current code.
|
|
73
73
|
- References carry their precision anchors, and a source that could not be fetched is listed as unreachable rather than dropped.
|
|
74
74
|
|
|
75
|
-
**C. Spine** (Locked
|
|
75
|
+
**C. Spine** (Locked 30 global, Locked 32 corporate)
|
|
76
76
|
|
|
77
77
|
- Global: every `BR-` id reaches an acceptance criterion and a test row.
|
|
78
78
|
- Corporate: every `IG` is realised by a `UC`, every `FG` names a source that exists, and the traceability matrix agrees with the sections. The matrix half is already machine-checked in Phase 1; the reviewer judges whether the chain is *meaningful*, not merely present.
|
|
@@ -32,7 +32,7 @@ synthesizedSections = {
|
|
|
32
32
|
| 6. Business + Tests | If sections 2 and 4 are both `null` AND `evidence.firebase[]` is empty → null. Otherwise produce use-case + mock stubs + per-platform test skeletons + shared Firebase events table. Reuse Red-Green-Refactor naming from `$HOME/.claude/rules/tdd.md`. |
|
|
33
33
|
| 7. Development Plan | Always present. Tasks for the current platform only. Architecture standards come from `evidence.standards[]` filtered by platform (see Pass B step 1). **Reuse-first rule (Locked 11)**: when an item has `direct-match` in `evidence.repoEvidence[<repo>].buckets.<X>`, emit `Reuse existing <FQN> (<file>:<line>)` instead of `Add new <FQN>`. New-write task with a `direct-match` competitor becomes a Risk row. |
|
|
34
34
|
|
|
35
|
-
#### Phase 2a - Pass B preview (Locked
|
|
35
|
+
#### Phase 2a - Pass B preview (Locked 25)
|
|
36
36
|
|
|
37
37
|
Before Pass B renders any file, present the resolved convention table to the user via `AskUserQuestion`. The table is one row per concept, one column per selected platform.
|
|
38
38
|
|
|
@@ -94,7 +94,7 @@ For each `platform` in `state.analysisSpec.platforms[]`:
|
|
|
94
94
|
that list fought Locked 2 in both directions: a small feature with rich
|
|
95
95
|
business rules lost Section 15 because it was not on the list, and a feature
|
|
96
96
|
with no API contract kept Section 9 because it was. Evidence decides now.
|
|
97
|
-
4. **Produce YAML front-matter header** (see `$HOME/.claude/multi-agent-refs/analysis-template.md`). Include `profile: <state.analysisSpec.profile | global>` and `platform: <platform | none>` so the validator applies the right contract per profile (Locked
|
|
97
|
+
4. **Produce YAML front-matter header** (see `$HOME/.claude/multi-agent-refs/analysis-template.md`). Include `profile: <state.analysisSpec.profile | global>` and `platform: <platform | none>` so the validator applies the right contract per profile (Locked 31) and recognises the stack-optional render (Locked 34), plus `ui_tests: <state.analysisSpec.options.uiTests | false>`, `a11y_depth: <state.analysisSpec.options.a11yDepth | basic>` and `redesign: <state.analysisSpec.options.redesign | false>` so the pre-dispatch validator can enforce the opt-in coverage (15.6 present when ui_tests, 16.2 walkthrough present when a11y_depth is full, 4.5 / 4.6 / 9.5 present when redesign). `status` is written only by `/multi-agent:analysis-resolve`; a rendered document is a draft.
|
|
98
98
|
5. **Read conventions for this platform's repo.** For each cell Pass B fills in Section 13 and in any per-platform projection (Sections 5, 6, 7, 8, 10, 11, 13, 14, 15, 16, 17), read `state.analysisSpec.evidence.conventions[<repo>].<field>` and emit the value with a footnote (Locked 24). If `conventionOverrides` has an entry for that field, use the override and footnote with `^[user-override: <reason>]` instead of evidence path.
|
|
99
99
|
6. **Concatenate non-null sections in canonical order.** Each rendered section keeps its canonical template number, so omitted sections DO leave gaps - `1, 2, 4, 9, 13, 14, 21` is a correct rendered document. Locked 30 cites sections by number across the whole document; re-flowing them would break every one of those references.
|
|
100
100
|
7. **Schema validation** on the per-platform spec object:
|
|
@@ -6,7 +6,7 @@ description: "Corporate profile template for /multi-agent:analysis. Requirements
|
|
|
6
6
|
|
|
7
7
|
The corporate profile renders a **requirements document**, not a development brief. Its spine is `IG -> UC -> FG`: a business requirement is realised by a use case, which is satisfied by functional requirements, which are served by services. Three matrices prove the chain closes.
|
|
8
8
|
|
|
9
|
-
This is a sibling of `analysis-template.md` (the global profile), not a replacement. Both read the same `state.analysisSpec.evidence.*`; only the projection differs. Phase 0 Step 1b picks one (Locked
|
|
9
|
+
This is a sibling of `analysis-template.md` (the global profile), not a replacement. Both read the same `state.analysisSpec.evidence.*`; only the projection differs. Phase 0 Step 1b picks one (Locked 31).
|
|
10
10
|
|
|
11
11
|
> **Language**: This file is read as a system prompt, so its prose stays English. Section headings carry TR / EN scaffolds; the renderer picks the column matching `prefs.global.outputLanguage`.
|
|
12
12
|
|
|
@@ -19,7 +19,7 @@ This is a sibling of `analysis-template.md` (the global profile), not a replacem
|
|
|
19
19
|
| Requirement spine | `BR-<slug>-NN` business rules with Gherkin acceptance criteria | `IG-NN` -> `UC-00N` -> `FG-NN`, plus three cross matrices |
|
|
20
20
|
| Altitude | What to build and how | What is required and why; the how follows in Parts B and C |
|
|
21
21
|
| Current state | Legacy findings are blockquotes inside forward-looking sections (Locked 4) | Section 2.1 is a first-class current-state analysis, and 2.3 is the diff between 2.1 and 2.2 |
|
|
22
|
-
| Empty section | Dropped entirely (Locked 2) | Backbone sections always render, with `N/A` or `EKLENECEK` (Locked
|
|
22
|
+
| Empty section | Dropped entirely (Locked 2) | Backbone sections always render, with `N/A` or `EKLENECEK` (Locked 32) |
|
|
23
23
|
| Version history | Section 22 Changelog at the bottom | `DOKÜMAN TARİHÇESİ` table at the top |
|
|
24
24
|
| Use cases | Gherkin scenarios in Section 4 | UC tables with Aktör / Ön Koşul / Ana Akış / Alternatif Akış |
|
|
25
25
|
|
|
@@ -27,7 +27,7 @@ Everything else is shared: citation discipline (Locked 3), forward-looking spec
|
|
|
27
27
|
|
|
28
28
|
## Section map
|
|
29
29
|
|
|
30
|
-
Numbering is fixed for Parts A and B and does not re-flow, because the corporate backbone never drops (Locked
|
|
30
|
+
Numbering is fixed for Parts A and B and does not re-flow, because the corporate backbone never drops (Locked 32). Section 5 sub-numbering shifts with the use-case count, exactly as the source documents do.
|
|
31
31
|
|
|
32
32
|
| Layer | Sections | Carries |
|
|
33
33
|
|---|---|---|
|
|
@@ -39,7 +39,7 @@ Numbering is fixed for Parts A and B and does not re-flow, because the corporate
|
|
|
39
39
|
|
|
40
40
|
**Boundary rule** (inherited from the global template): remove a row, and ask what becomes unclear. Part A carries no technology name. Part C carries no business rationale. A row unclear in two layers at once is two rows.
|
|
41
41
|
|
|
42
|
-
**Part C drops when no repo is selected** (Locked
|
|
42
|
+
**Part C drops when no repo is selected** (Locked 34). Parts A and B always render.
|
|
43
43
|
|
|
44
44
|
---
|
|
45
45
|
|
|
@@ -189,7 +189,7 @@ Rules the renderer enforces:
|
|
|
189
189
|
|
|
190
190
|
## 4. Yapay Zeka Gereksinimleri / AI Requirements
|
|
191
191
|
|
|
192
|
-
Renders `N/A` when the feature has no model-backed behaviour (Locked
|
|
192
|
+
Renders `N/A` when the feature has no model-backed behaviour (Locked 32). When it does, each row states the decision the model makes, the input it sees, and the fallback when it is unavailable.
|
|
193
193
|
|
|
194
194
|
```markdown
|
|
195
195
|
## 4. Yapay Zeka Gereksinimleri <!-- TR -->
|
|
@@ -401,7 +401,7 @@ Part B carries what is technically true. It reuses the global template's scaffol
|
|
|
401
401
|
|
|
402
402
|
Sections 15 and 16 are the implementation of the requirements stated in 7.1 and 7.3. State the requirement once, in Part A, and the implementation once, here. A sentence that appears in both is a sentence one of the two sections did not need.
|
|
403
403
|
|
|
404
|
-
Part B follows the global omission table: a section with zero evidence drops. The corporate backbone guarantee (Locked
|
|
404
|
+
Part B follows the global omission table: a section with zero evidence drops. The corporate backbone guarantee (Locked 32) covers Part A and the References section, not Part B.
|
|
405
405
|
|
|
406
406
|
---
|
|
407
407
|
|
|
@@ -417,9 +417,9 @@ Identical to the global template's Sections 13, 14 and 15, renumbered:
|
|
|
417
417
|
|
|
418
418
|
Part C is written against the conventions extracted at Phase 1c, and every projected cell carries its Pass B footnote (Locked 24).
|
|
419
419
|
|
|
420
|
-
**Part C drops entirely when no repo was selected** (Locked
|
|
420
|
+
**Part C drops entirely when no repo was selected** (Locked 34). The document then ends after Part B, and Section 20 carries a row stating that the development analysis awaits a repo selection. Parts A and B are complete on their own; a requirements document does not need a target repository to be useful.
|
|
421
421
|
|
|
422
|
-
**Traceability into Part C.** The `FG` ids are the join. Section 19's unit-test rows cite the `FG` they cover, the same way the global profile's rows cite `BR-` ids (Locked
|
|
422
|
+
**Traceability into Part C.** The `FG` ids are the join. Section 19's unit-test rows cite the `FG` they cover, the same way the global profile's rows cite `BR-` ids (Locked 30). An `FG` with no test row in Full mode fails the dispatch gate.
|
|
423
423
|
|
|
424
424
|
---
|
|
425
425
|
|
|
@@ -438,7 +438,7 @@ Never omitted.
|
|
|
438
438
|
| AS-01 | <question> | <what evidence is missing> | <role or team> | 2.3 |
|
|
439
439
|
```
|
|
440
440
|
|
|
441
|
-
The source corporate documents keep open questions out of the page and raise them in conversation instead. This profile keeps them in the document deliberately: an `EKLENECEK` with no matching `AS-NN` row here is an unanswered question nobody owns. Every `EKLENECEK` and every unverified assumption in 2.4 emits a row (Locked
|
|
441
|
+
The source corporate documents keep open questions out of the page and raise them in conversation instead. This profile keeps them in the document deliberately: an `EKLENECEK` with no matching `AS-NN` row here is an unanswered question nobody owns. Every `EKLENECEK` and every unverified assumption in 2.4 emits a row (Locked 32).
|
|
442
442
|
|
|
443
443
|
## 21. Referanslar / References
|
|
444
444
|
|