ktg-plugin-marketplace/plugins/linkedin-studio/docs/hardening/plan.md
Kjell Tore Guttormsen 2f90880f7a docs(linkedin-studio): hardening-phase foundation (brief + adversarially-reviewed plan)
New phase after the baseline-audit remediation (S1-S17, 2633d32, complete):
a command-hardening pass that simulates each of the 29 commands and tightens
it to its stated intention (intention-fidelity + prompt-quality only — no
structural redesign, no new features, no GUI/M0). Runs over ~8 journey-grouped
Voyage sessions, gated by lint + /trekreview ALLOW before push.

Foundation laid this session (execution starts next session):
- docs/hardening/brief.md (valid; 3 locked forks: hybrid simulation,
  intention-fidelity+prompt-quality, per-journey cadence; research skipped —
  the 2026 bar is frozen in algorithm-signals-reference.md)
- docs/hardening/plan.md (8 sessions, Grade B+ 87)

Adversarial review: brief-reviewer PROCEED_WITH_RISKS (3 findings folded:
self-graded quality axis, SC-H deferral contradiction, no stopping rule);
plan-critic REVISE (2 blockers + 10 major — all addressed: anchored coverage
predicate kills substring false-positives, full-session cold-reviewer oracle
on concrete before/after output, per-type mechanical predicate, Failed:0 gate
not literal-74, S1 HALT circuit-breaker); scope-guardian ALIGNED.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-05-31 05:31:52 +02:00

571 lines
43 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# LinkedIn Studio — Command Hardening Plan
> **Plan quality: B+** (87/100) — APPROVE_WITH_NOTES (post-revision; plan-critic REVISE
> blockers + majors addressed — see Revisions)
>
> Generated by trekplan v2.0 on 2026-05-31 — `plan_version: 1.7`
>
> Source brief: `docs/hardening/brief.md`. Predecessor: `docs/remediation/`
> (S1S17, complete, commit `2633d32`). Research: none (`research_status: skipped`
> — the 2026 algorithm bar was triangulated in remediation research 0103 and is
> frozen in `references/algorithm-signals-reference.md`).
## Context
The remediation made every claim honest, wired every orphan agent, rebuilt the
lint, and reconciled the algorithm bar — *structure, correctness, honesty*. It did
**not** exercise each command's workflow end-to-end and judge **the quality of what
it produces** against the command's own stated intention. A command can be
structurally correct (right frontmatter, right agent wired, lint-green) and still
under-deliver: a step that under-determines the next move, a question that yields a
weak answer, a prompt that produces generic output, a missing graceful-degradation
path.
This is a **hardening phase**: a per-command pass that simulates a realistic
invocation, judges the result against intention + the 2026 algorithm bar + the
content-quality rules, and tightens the command definition where it falls short. It
is the last quality gate **before** the GUI/M0 track. The operator tests the
commands **live** in parallel; this phase is the complementary intention-fidelity
pass from the definition side, converging through a field-notes inbox.
Scope is deliberately bounded (locked forks): **intention-fidelity + prompt-quality
only** — no structural redesign, no new features, no GUI/M0, no re-litigation of the
algorithm bar. The command set stays 29/19/25/6.
## Architecture Diagram
```mermaid
graph TD
subgraph "Hardening pass — 5-step method per command, 8 journey-grouped sessions"
M["docs/hardening/brief.md<br/>(method contract)"] --> LOG["docs/hardening/log.md<br/>(per-command audit trail,<br/>unique anchor per entry)"]
FN["field-notes.local.md<br/>(operator live findings, optional)"] -.steers priority.-> LOG
REF["references/algorithm-signals-reference.md<br/>+ content-quality rules<br/>(the frozen bar)"] --> EVAL
subgraph "Per command"
INT["1 INTENT"] --> SIM["2 SIMULATE<br/>(persona + CONCRETE output)"]
SIM --> EVAL["3 EVALUATE<br/>4 axes (mechanical predicate per type)"]
EVAL --> HARD["4 HARDEN<br/>(edit commands/&lt;x&gt;.md, surgical)"]
HARD --> VER["5 VERIFY<br/>lint + before/after + counts"]
end
VER --> CMD["commands/*.md (29)"]
CMD -. invokes .-> AG["agents/*.md (19)"]
VER --> GATE["per-session gate:<br/>test-runner.sh (Failed:0) + node --test<br/>+ /trekreview ALLOW — reviewer adjudicates<br/>EVERY hardened command's before/after"]
GATE --> PUSH["commit own files → push (Forgejo)"]
end
```
## Codebase Analysis
- **Tech stack:** Markdown command/agent definitions (Claude Code plugin); Node.js
(.mjs) hooks + helpers (zero deps); TypeScript analytics CLI (`scripts/analytics/`,
`tsx`); bash structural lint (`scripts/test-runner.sh`, `set -e`, dynamic PASS/FAIL
counters, `EXPECT_*` count-guards); `node:test`.
- **Key patterns:** commands invoke agents via `subagent_type: linkedin-studio:<name>`
(namespaced) — sometimes as a literal frontmatter-style line, sometimes via a
`--type → subagent_type` table (e.g. `headless-review.md`); content commands
auto-copy to clipboard via `clipboard-helper.mjs`; PreToolUse content-quality gate
(`hooks/prompts/content-quality-gate.md`); progressive onboarding (score hidden < 3
posts, voice guardian < 5 samples).
- **Relevant files (verified, 216 source files):**
- `commands/*.md` — 29 surfaces (inventory confirmed). Agent wiring per command:
- *with `subagent_type:` line:* ab-test→content-optimizer · analyze/report→analytics-interpreter ·
batch/pipeline→content-planner,trend-spotter · calendar→post-feedback-monitor ·
carousel/quick/react→differentiation-checker · firsthour→engagement-coach,post-feedback-monitor ·
newsletter→content-repurposer,editorial-reviewer,fact-checker (+ persona/voice/headless deeper) ·
outreach→network-builder · post→content-optimizer,differentiation-checker ·
setup→voice-trainer · strategy→strategy-advisor · video→differentiation-checker,video-scripter
- *invokes via a `--type → subagent_type` table (not a bare line):* `headless-review`
→ content-reviewer/language-reviewer/fact-reviewer/persona-reviewer (CONFIRMED present,
`headless-review.md:77-79,141-142` — wiring is correct, just a different syntactic form).
- *no agent (prose/CLI/routing — verify intention + a type-specific mechanical predicate, not wiring):*
audit, competitive, create, first-post, import, linkedin, measure, monetize, multiplatform,
onboarding, pivot, profile.
- `references/algorithm-signals-reference.md` — the single source of truth (the bar).
- `references/*.md` (25), `skills/linkedin-studio/SKILL.md`,
`hooks/prompts/content-quality-gate.md`, `scripts/test-runner.sh`,
`hooks/scripts/state-updater.mjs` (`recordFirstHourPlan`, `recordOutreachContact`),
`scripts/analytics/` (`parseOptionalCount`).
- **Reusable code:** the hardening method (brief §"Hardening method"); the four
*mechanically-checkable* content-quality rules (hook 110140 chars, length bands,
no body links, no buzzwords); the S17 disposition record as the log model.
- **External tech (researched):** none — the bar is frozen; no `/trekresearch`.
- **Recent git activity:** S17 (`2633d32`) closed remediation; plugin v4.1.0, stable, sync 0/0.
## Implementation Plan
> **Unit of work = one command** (operator: "én og én kommando"). For tractable
> execution + per-session checkpoints, the 29 commands are grouped into **8
> journey-sessions**; each session-step applies the 5-step method to every command it
> lists and records the result in `docs/hardening/log.md`.
>
> **Log-entry anchor convention (closes plan-critic blockers #1/#2 — substring
> false-positives):** every `log.md` entry begins with a UNIQUE, anchored header of
> the exact form `### /linkedin:<command-name> — <one-line intent>`. Coverage and
> per-step checks grep the anchored header (`^### /linkedin:<name>`), never the bare
> word — so "measure" no longer collides with the "Measure journey" label, nor "post"
> with "post-publish".
>
> The per-command procedure for **every** command in **every** step:
>
> 1. **INTENT** — distil the promise (frontmatter `description` + journey role +
> quality rules + algorithm signals it must honor) → one paragraph under the
> command's anchored `log.md` header.
> 2. **SIMULATE** — pick a concrete persona (default: the plugin's ICP — a solo
> AI-advisor creator, ~1048 followers, "Validation", 5 pillars; PLUS a fresh adopter
> with no voice samples/analytics for graceful-degradation + progressive-onboarding
> paths). Walk the workflow exactly as written; answer its questions; **produce the
> CONCRETE output the command would generate from those exact mock inputs** (the
> actual draft/report/plan/routing-decision text — reproducible from the inputs, NOT
> a vague paraphrase). Log every friction/dead-end/under-determined step. This
> concrete **before** output is the artifact the oracle adjudicates.
> 3. **EVALUATE** on 4 axes → pass/gap each:
> - (a) **intention fidelity** — does it deliver the description's promise? (judgment)
> - (b) **algorithm bar** — consistent with `algorithm-signals-reference.md`? (cite)
> - (c) **MECHANICAL predicate (hard, per command — never "N/A → judgment")**:
> - *emits a post/hook* (post, quick, react, carousel, video, batch, pipeline, first-post):
> hook 110140 chars · length band (1,2001,800 std / 150500 quick) · `grep` no body
> link · `grep` no banned buzzword · topic maps to the 5 pillars.
> - *routing/front-door* (linkedin, create, measure): every routing target the
> simulation emits resolves to a real `commands/<x>.md` (grep).
> - *analytics/CLI* (import, report, analyze, audit, ab-test): the documented
> graceful-degradation path is present (grep) and the directional/saves honesty
> wording is intact.
> - *guided/stateful* (onboarding, setup, calendar, firsthour, monetize, outreach,
> strategy, competitive, profile, multiplatform, newsletter, headless-review, pivot):
> the command's PRIMARY promised artifact is actually produced in the simulation
> (draft / plan / funnel / analysis / checklist / routing) and there is no dead-end
> hand-off string; for agent-invoking ones, the promised `subagent_type` targets
> resolve to real `agents/<x>.md`.
> - (d) **agent-wiring + graceful degradation** — right `subagent_type` (literal line
> OR `--type` table); sensible fallback when an agent/tool/mcp/CLI is unavailable.
> 4. **HARDEN** — edit `commands/<x>.md` (surgical; agent/reference only if intention
> requires). **Stopping rule (anti-gold-plating):** harden until every axis returns
> pass OR a recorded deferral; do NOT add NICE-only polish beyond axis-pass. No
> structural redesign. Record the concrete **after** output for every hardened command.
> 5. **VERIFY** — `test-runner.sh` exit 0 + `Failed: 0` + counts unchanged (29/19/25/6)
> + `node --test` green where touched + the before/after pair shows the failing axis
> now passes. Record before/after + disposition under the command's `log.md` anchor.
>
> **Independent oracle (closes plan-critic #3/#12 — self-grading):** the per-session
> `/trekreview` code-correctness reviewer reads, in `log.md`, the **before/after concrete
> output of EVERY command hardened that session** (sessions are ≤5 commands — tractable)
> and independently judges whether each claimed gap is genuinely closed. The cold
> reviewer — not the author — signs off. A session is not ALLOW until every hardened
> command's before/after has been adjudicated.
>
> **Manifest scope (closes plan-critic #10):** manifests anchor on the guaranteed
> artifact — the `log.md` entry with its unique per-command anchor (proving the command
> was *processed*). The **actual command-file hardening edits are verified by the
> per-session `/trekreview`**, which reads the real diffs. Manifest proves processing;
> review proves the edit. (A command may legitimately need zero edits if it passes all
> axes — so "command file modified" cannot be a manifest predicate.)
>
> **Prior-disposition rule (closes plan-critic #11):** where a step relies on a prior
> session's disposition (S15-B1, S17 F-VIDEO, overlap-measurement, the CWD fix),
> **spot-confirm it still holds with one grep/read** before relying on it — never "do
> not re-verify".
### Step 1: Method calibration on `quick`, then harden the Start journey
- **Files:** `commands/quick.md`, `commands/onboarding.md`, `commands/first-post.md`, `commands/setup.md`, `docs/hardening/log.md` (new), `docs/hardening/field-notes.local.md` (read-if-present)
- **Changes:** First run the full 5-step method on `commands/quick.md` ALONE as a **method calibration** — produce the concrete before/after output, present the diff + the `log.md` entry shape to the operator, and lock the method before scaling. Then apply the method to the Start journey: `onboarding` (spot-confirm the S15-B1 inline-draft still delivers, then re-evaluate), `first-post`, `setup` (voice-trainer wiring + 5-pillar capture). Create `docs/hardening/log.md`; one anchored entry per command (`### /linkedin:<name> — …`). Harden each `.md` only where an axis gaps. (`log.md` is a new file.)
- **Reuses:** the hardening method (`docs/hardening/brief.md`); `references/algorithm-signals-reference.md`; the mechanical content-quality rules (`hooks/prompts/content-quality-gate.md`); persona basis from the state file + voice-samples; the S17 record (`docs/remediation/c13-c46-triage.md`) as the log model.
- **Verify:**
- `bash scripts/test-runner.sh; echo "exit=$?"` → expected: output contains `Failed: 0` and `exit=0` (gate on `Failed: 0` + exit 0 + unchanged `EXPECT_*` counts, NOT the literal `Passed: 74` — it is incidental and `set -e`-fragile).
- `ls commands/*.md | wc -l``29`.
- `for c in quick onboarding first-post setup; do grep -qE "^### /linkedin:$c" docs/hardening/log.md || echo "MISSING $c"; done` → no output.
- **On failure:** **HALT** — S1 is the method-calibration gate that gates S2S8 (hard dependency, not advisory). If calibration reveals the method itself is unsound, do NOT proceed to S2; revert command edits (`git checkout -- commands/quick.md commands/onboarding.md commands/first-post.md commands/setup.md`, keep `log.md`), and re-lock the method WITH THE OPERATOR before any later session runs.
- **Checkpoint:** `git commit -m "fix(linkedin-studio): S1 hardening — method calibration (quick) + Start journey"`
- **Manifest:**
```yaml
manifest:
expected_paths:
- docs/hardening/log.md
min_file_count: 1
commit_message_pattern: "^fix\\(linkedin-studio\\): S1 hardening"
bash_syntax_check: []
forbidden_paths:
- docs/linkedin-studio-persona-brief.md
- docs/linkedin-studio-ui-brief.md
- docs/voyage-build/progress.json
must_contain:
- path: docs/hardening/log.md
pattern: "^### /linkedin:quick"
```
### Step 2: Harden Create I (atomic short-form)
> *quick is COMPLETE after S1 and is NOT re-hardened here (closes plan-critic #16).*
> *Session-grouping refinement (closes plan-critic #6): the brief's session table was
> explicitly "to be confirmed/refined by /trekplan". multiplatform moves to S2 (atomic
> cross-format short-form), batch to S3 (with the visual cluster), headless-review+pivot
> to S4 (the long-form cluster with newsletter). Coverage preserved — 29, none dropped/doubled.*
- **Files:** `commands/post.md`, `commands/react.md`, `commands/multiplatform.md`, `docs/hardening/log.md`
- **Changes:** Apply the 5-step method to `post` (content-optimizer + differentiation-checker; hook/length mechanical pass), `react` (URL→post; de-AI gate), `multiplatform` (cross-format adaptation; confirm long-form correctly routes to `/linkedin:newsletter`). Append anchored entries; harden where an axis gaps.
- **Reuses:** hardening method; `algorithm-signals-reference.md`; content-quality gate; the `differentiation-checker` wiring pattern from S1.
- **Verify:**
- `bash scripts/test-runner.sh; echo "exit=$?"` → `Failed: 0` + `exit=0` + counts unchanged.
- `for c in post react multiplatform; do grep -qE "^### /linkedin:$c" docs/hardening/log.md || echo "MISSING $c"; done` → no output.
- **On failure:** revert — `git checkout -- commands/post.md commands/react.md commands/multiplatform.md` (keep `log.md`); if `/trekreview` ≠ ALLOW, HALT until resolved.
- **Checkpoint:** `git commit -m "fix(linkedin-studio): S2 hardening — Create I (post, react, multiplatform)"`
- **Manifest:**
```yaml
manifest:
expected_paths:
- docs/hardening/log.md
min_file_count: 1
commit_message_pattern: "^fix\\(linkedin-studio\\): S2 hardening"
bash_syntax_check: []
forbidden_paths:
- docs/linkedin-studio-persona-brief.md
- docs/linkedin-studio-ui-brief.md
- docs/voyage-build/progress.json
must_contain:
- path: docs/hardening/log.md
pattern: "^### /linkedin:post"
```
### Step 3: Harden Create II (visual + batch)
- **Files:** `commands/carousel.md`, `commands/video.md`, `commands/batch.md`, `docs/hardening/log.md`
- **Changes:** Apply the method to `carousel` (spot-confirm the S15-B3 full-deck clipboard still holds; differentiation-checker; mcp-image graceful degradation to text-only), `video` (video-scripter + differentiation-checker; spot-confirm the S17 F-VIDEO disposition (deliberate aspect-ratio decision) before relying on it; caption guidance; graceful degradation), `batch` (content-planner + trend-spotter; pillar-rotation across the week). Focus axis (d) graceful degradation when mcp-image/tools are unavailable.
- **Reuses:** hardening method; `references/linkedin-formats.md`, `references/video-strategy-guide.md`; the S17 F-VIDEO disposition (spot-confirmed, not assumed).
- **Verify:**
- `bash scripts/test-runner.sh; echo "exit=$?"` → `Failed: 0` + `exit=0` + counts unchanged.
- `for c in carousel video batch; do grep -qE "^### /linkedin:$c" docs/hardening/log.md || echo "MISSING $c"; done` → no output.
- **On failure:** revert — `git checkout -- commands/carousel.md commands/video.md commands/batch.md` (keep `log.md`); if `/trekreview` ≠ ALLOW, HALT.
- **Checkpoint:** `git commit -m "fix(linkedin-studio): S3 hardening — Create II (carousel, video, batch)"`
- **Manifest:**
```yaml
manifest:
expected_paths:
- docs/hardening/log.md
min_file_count: 1
commit_message_pattern: "^fix\\(linkedin-studio\\): S3 hardening"
bash_syntax_check: []
forbidden_paths:
- docs/linkedin-studio-persona-brief.md
- docs/linkedin-studio-ui-brief.md
- docs/voyage-build/progress.json
must_contain:
- path: docs/hardening/log.md
pattern: "^### /linkedin:carousel"
```
### Step 4: Harden Create III (long-form cluster)
- **Files:** `commands/newsletter.md`, `commands/headless-review.md`, `commands/pivot.md`, `docs/hardening/log.md`
- **Changes:** Apply the method to the long-form cluster. `newsletter` = **orchestration only** (the 16-phase gate sequence + per-gate agents were heavily reviewed in remediation; simulate the operator's path THROUGH the phases — banner, phase transitions, lock/visual-assets/headless gates — NOT a re-review of each gate agent; spot-confirm `overlap-measurement.md` exists before citing "do not re-measure"). `headless-review` — wiring is **CONFIRMED present** (`headless-review.md:77-79,141-142`, `--type → subagent_type` table); the step VERIFIES that table resolves to real agents (mechanical axis-c) and simulates the consolidated-report output — no wiring fix expected. `pivot` (re-open-gates heuristic). **May split into its own session** if newsletter's orchestration simulation is large — decide at session start, log the split explicitly (not a silent cap).
- **Reuses:** hardening method; `references/newsletter-strategy-guide.md`; `references/longform-quality-rules.md`; `docs/remediation/overlap-measurement.md` (spot-confirmed).
- **Verify:**
- `bash scripts/test-runner.sh; echo "exit=$?"` → `Failed: 0` + `exit=0` + counts unchanged.
- `for c in newsletter headless-review pivot; do grep -qE "^### /linkedin:$c" docs/hardening/log.md || echo "MISSING $c"; done` → no output.
- `grep -qE "linkedin-studio:(content|language|fact)-reviewer" commands/headless-review.md` → present (wiring confirmed).
- **On failure:** revert — `git checkout -- commands/newsletter.md commands/headless-review.md commands/pivot.md` (keep `log.md`); if `/trekreview` ≠ ALLOW, HALT.
- **Checkpoint:** `git commit -m "fix(linkedin-studio): S4 hardening — Create III long-form (newsletter, headless-review, pivot)"`
- **Manifest:**
```yaml
manifest:
expected_paths:
- docs/hardening/log.md
min_file_count: 1
commit_message_pattern: "^fix\\(linkedin-studio\\): S4 hardening"
bash_syntax_check: []
forbidden_paths:
- docs/linkedin-studio-persona-brief.md
- docs/linkedin-studio-ui-brief.md
- docs/voyage-build/progress.json
must_contain:
- path: docs/hardening/log.md
pattern: "^### /linkedin:newsletter"
```
### Step 5: Harden the Engage journey
- **Files:** `commands/firsthour.md`, `commands/calendar.md`, `commands/pipeline.md`, `docs/hardening/log.md`
- **Changes:** Apply the method to `firsthour` (engagement-coach + post-feedback-monitor; `recordFirstHourPlan` state path), `calendar` (queue view + publish action; spot-confirm the auto-publish honesty boundary holds; state mutation), `pipeline` (content-planner + trend-spotter). Focus axis (c) guided/stateful predicate + axis (d) state-mutation + honesty boundaries.
- **Reuses:** hardening method; `hooks/scripts/state-updater.mjs` (`recordFirstHourPlan`, queue); the remediation scheduling-boundary wording (spot-confirmed).
- **Verify:**
- `bash scripts/test-runner.sh; echo "exit=$?"` → `Failed: 0` + `exit=0` + counts unchanged.
- `node --test hooks/scripts/__tests__/*.test.mjs` → `Failed: 0` (pass 98) if any hook touched.
- `for c in firsthour calendar pipeline; do grep -qE "^### /linkedin:$c" docs/hardening/log.md || echo "MISSING $c"; done` → no output.
- **On failure:** revert — `git checkout -- commands/firsthour.md commands/calendar.md commands/pipeline.md` (keep `log.md`); if `/trekreview` ≠ ALLOW, HALT.
- **Checkpoint:** `git commit -m "fix(linkedin-studio): S5 hardening — Engage journey (firsthour, calendar, pipeline)"`
- **Manifest:**
```yaml
manifest:
expected_paths:
- docs/hardening/log.md
min_file_count: 1
commit_message_pattern: "^fix\\(linkedin-studio\\): S5 hardening"
bash_syntax_check: []
forbidden_paths:
- docs/linkedin-studio-persona-brief.md
- docs/linkedin-studio-ui-brief.md
- docs/voyage-build/progress.json
must_contain:
- path: docs/hardening/log.md
pattern: "^### /linkedin:firsthour"
```
### Step 6: Harden the Measure journey
- **Files:** `commands/import.md`, `commands/report.md`, `commands/analyze.md`, `commands/audit.md`, `commands/ab-test.md`, `docs/hardening/log.md`
- **Changes:** Apply the method to `import` (analytics CLI graceful degradation — spot-confirm the remediation CWD/`npm install` fix holds; the S16 saves manual-entry path), `report`/`analyze` (analytics-interpreter; saves + directional framing), `audit` (quarterly strategy audit; type-c = guided/stateful predicate), `ab-test` (directional-not-significant framing; content-optimizer). Focus axis (c) analytics graceful-degradation + (a) directional-A/B + saves honesty.
- **Reuses:** hardening method; `scripts/analytics/`; the remediation's saves/dwell honesty wording; the S16 `parseOptionalCount()` saves path (spot-confirmed).
- **Verify:**
- `bash scripts/test-runner.sh; echo "exit=$?"` → `Failed: 0` + `exit=0` + counts unchanged.
- if analytics touched: `cd scripts/analytics && npm test` → `Failed: 0` (pass 116).
- `for c in import report analyze audit ab-test; do grep -qE "^### /linkedin:$c" docs/hardening/log.md || echo "MISSING $c"; done` → no output.
- **On failure:** revert — `git checkout -- commands/import.md commands/report.md commands/analyze.md commands/audit.md commands/ab-test.md` (keep `log.md`); if `/trekreview` ≠ ALLOW, HALT.
- **Checkpoint:** `git commit -m "fix(linkedin-studio): S6 hardening — Measure journey (import, report, analyze, audit, ab-test)"`
- **Manifest:**
```yaml
manifest:
expected_paths:
- docs/hardening/log.md
min_file_count: 1
commit_message_pattern: "^fix\\(linkedin-studio\\): S6 hardening"
bash_syntax_check: []
forbidden_paths:
- docs/linkedin-studio-persona-brief.md
- docs/linkedin-studio-ui-brief.md
- docs/voyage-build/progress.json
must_contain:
- path: docs/hardening/log.md
pattern: "^### /linkedin:ab-test"
```
### Step 7: Harden the Grow journey
- **Files:** `commands/strategy.md`, `commands/competitive.md`, `commands/monetize.md`, `commands/outreach.md`, `commands/profile.md`, `docs/hardening/log.md`
- **Changes:** Apply the method to `strategy` (phase guidance/trajectory; strategy-advisor), `competitive` (niche analysis; type-c guided predicate; remediation un-gated it), `monetize` (~1K soft-gating; readiness scoring), `outreach` (collab + speaking; network-builder; tracked-pipeline via `recordOutreachContact`), `profile` (profile-SEO surface from remediation). Focus (a) intention for the ~1K-gated commands (soft-gate guidance, not dead-ends) + (c)/(d) tracked-pipeline state.
- **Reuses:** hardening method; the remediation's profile-SEO additions, outreach pipeline tracker (`state-updater.mjs`), ~1K soft-gating rule.
- **Verify:**
- `bash scripts/test-runner.sh; echo "exit=$?"` → `Failed: 0` + `exit=0` + counts unchanged.
- `for c in strategy competitive monetize outreach profile; do grep -qE "^### /linkedin:$c" docs/hardening/log.md || echo "MISSING $c"; done` → no output.
- **On failure:** revert — `git checkout -- commands/strategy.md commands/competitive.md commands/monetize.md commands/outreach.md commands/profile.md` (keep `log.md`); if `/trekreview` ≠ ALLOW, HALT.
- **Checkpoint:** `git commit -m "fix(linkedin-studio): S7 hardening — Grow journey (strategy, competitive, monetize, outreach, profile)"`
- **Manifest:**
```yaml
manifest:
expected_paths:
- docs/hardening/log.md
min_file_count: 1
commit_message_pattern: "^fix\\(linkedin-studio\\): S7 hardening"
bash_syntax_check: []
forbidden_paths:
- docs/linkedin-studio-persona-brief.md
- docs/linkedin-studio-ui-brief.md
- docs/voyage-build/progress.json
must_contain:
- path: docs/hardening/log.md
pattern: "^### /linkedin:outreach"
```
### Step 8: Harden the front-doors + router, and close the phase
- **Files:** `commands/create.md`, `commands/measure.md`, `commands/linkedin.md`, `docs/hardening/log.md`
- **Changes:** Apply the method to the routing surfaces: `create` (Create front-door — simulate "what should I make?" and confirm axis-c routing predicate: every target it emits resolves to a real, now-hardened creation command), `measure` (Measure front-door — routes to the correct analytics command), `linkedin` (the five-journey router — every journey + command listed and reachable, no stale entries). **Brand-consistency judgment (from plan-critic #5):** evaluate `commands/linkedin.md:4,16` ("LinkedIn thought leadership assistant/commands") — these are domain descriptors (S17 ruled them not-stale plugin-name misnomers), but the router is the brand front-door, so harden to "LinkedIn Studio" phrasing IF it improves intention clarity (a hardening judgment, not forced). **Phase close:** confirm `log.md` has all 29 anchored entries (SC-F); decide the optional v4.2.0 bump (if taken, it is the ONE feat-gated, three-doc, version-synced commit of the phase — run the full version grep — NOT a `fix:`).
- **Reuses:** hardening method; `docs/remediation/journey-layer-design.md` (the five-journey design); the hardened commands S1S7 as routing targets.
- **Verify:**
- `bash scripts/test-runner.sh; echo "exit=$?"` → `Failed: 0` + `exit=0` + counts unchanged.
- **SC-F coverage (anchored, closes blockers #1/#2):** `for c in $(ls commands/*.md | xargs -n1 basename | sed 's/.md//'); do grep -qE "^### /linkedin:$c( |—|$)" docs/hardening/log.md || echo "MISSING: $c"; done` → no output (all 29 anchored entries present).
- **SC-G stale-brand (broadened, closes #5):** `grep -rn "thought leadership plugin" commands/ skills/ references/ README.md` → 0 (the plugin-NAME misnomer; domain phrases are allowed).
- **On failure:** revert — `git checkout -- commands/create.md commands/measure.md commands/linkedin.md` (keep `log.md`); escalate if SC-F coverage is incomplete.
- **Checkpoint:** `git commit -m "fix(linkedin-studio): S8 hardening — front-doors + router; phase complete"`
- **Manifest:**
```yaml
manifest:
expected_paths:
- docs/hardening/log.md
min_file_count: 1
commit_message_pattern: "^fix\\(linkedin-studio\\): S8 hardening"
bash_syntax_check: []
forbidden_paths:
- docs/linkedin-studio-persona-brief.md
- docs/linkedin-studio-ui-brief.md
- docs/voyage-build/progress.json
must_contain:
- path: docs/hardening/log.md
pattern: "^### /linkedin:linkedin"
```
## Alternatives Considered
| Approach | Pros | Cons | Why rejected |
|----------|------|------|--------------|
| One Voyage session per command (29 sessions) | Deepest per command; granular checkpoints | ~29 sessions; high startup overhead; uneven | Operator locked "per journey, large groups split" — 8 sessions |
| Spec-audit only (no simulation) | Faster, cheaper | Misses output-quality gaps — the phase's whole reason | Operator locked "hybrid: run + spec-audit" |
| Allow structural redesign (merge/split commands) | Could fix root-cause structure | Churn right after remediation; rocks the count/journey invariants; re-opens 14a | Operator locked "intention-fidelity + prompt-quality, no structural" |
| Full exploration swarm (68 agents) in planning | Canonical /trekplan rigor | Re-maps an already-fully-mapped, frozen codebase — wasted spend | Scaled down per the "adaptive / don't over-spawn" rule; kept the high-value brief-review + plan-critic + scope-guardian gates |
| Oracle = "≥1 command/session spot-check" (original draft) | Cheaper review | Leaves 80%+ of a session self-graded — does not break the loop | Replaced (plan-critic #3) by "reviewer adjudicates EVERY hardened command's before/after" |
## Test Strategy
- **Framework:** no unit tests are written *by* this phase (it edits Markdown command
prompts). The "test" per command is the **simulation + per-type mechanical predicate +
the concrete before/after output pair**, recorded in `docs/hardening/log.md` and
**adjudicated by the cold `/trekreview` reviewer** (the independent oracle). The
existing suites (`test-runner.sh`, hooks `node --test`, analytics `npm test`) are
**regression guards**, gated on `Failed: 0` (not a literal pass-count).
- **Existing patterns:** evidence-per-row disposition records (S17 `c13-c46-triage.md`).
- **New tests in this plan:** 0 new automated tests; the concrete before/after pair +
per-type mechanical predicate is the falsifiable evidence, adjudicated independently.
### Tests to write
| Type | File | Verifies | Model |
|------|------|----------|-------|
| Evidence record | `docs/hardening/log.md` | per-command INTENT→VERIFY + concrete before/after + mechanical predicate; unique anchor per entry | `docs/remediation/c13-c46-triage.md` |
| Regression | (existing) `scripts/test-runner.sh` | counts 29/19/25/6 + structural guards; gate on `Failed: 0` + exit 0 | — |
| Regression | (existing) hooks/analytics `node --test` | `Failed: 0` (98 / 116) when those surfaces touched | — |
## Risks and Mitigations
| Priority | Risk | Location | Impact | Mitigation |
|----------|------|----------|--------|------------|
| High | **Self-graded quality axis** (brief-review #1, plan-critic #3/#12) | method 3+5 | "hardened" claimed without provable improvement | Concrete (reproducible) before/after output + per-type mechanical predicate + `/trekreview` reviewer adjudicates **every** hardened command's before/after (not a sample) |
| High | **Coverage gate false-positive** (plan-critic #1/#2) | SC-F + per-step greps | a dropped command reads as covered | Unique anchored log header `^### /linkedin:<name>`; all greps anchored, never bare-word |
| Medium | **Gold-plating / unbounded depth** (brief-review #3) | method 4 | token blowup; uneven coverage | Stopping rule: axes pass-or-defer; no NICE polish; per-session split logged if scope balloons |
| Medium | **SC-H vs deferral contradiction** (brief-review #2) | brief SC-H | gate unsatisfiable, or "open finding" redefined | SC-H = "0 **un-triaged** findings; each fixed or recorded-deferral; `/trekreview` ALLOW with deferrals noted" |
| Medium | **`Passed: 74` brittle under `set -e`** (plan-critic #7, scope-guardian caveat) | every Verify | spurious gate failure on any added check | Gate on `Failed: 0` + exit 0 + unchanged `EXPECT_*` counts; `74` is incidental |
| Medium | **No circuit-breaker on the S1 method gate** (plan-critic #9) | S1 On-failure | headless run proceeds with an unsound method | S1 On-failure = HALT; S1→S2..S8 is a hard dependency; any non-ALLOW `/trekreview` halts the phase |
| Medium | **Mechanical axis absent on ~13 no-output commands** (plan-critic #4) | method 3(c) | the non-circular axis evaporates → pure judgment | Per-type mechanical predicate defined for every command class (routing/analytics/guided), never "N/A → judgment" |
| Low | Simulation ≠ live run | method 2 | a gap only real testing surfaces is missed | Field-notes inbox: operator's live findings outrank simulated; checked before each journey; SC-I |
| Low | Prior-disposition premise misremembered (plan-critic #11) | S1/S3/S4/S6 | an axis skipped on a false premise | Spot-confirm each cited disposition with one grep/read before relying |
| Low | Stale-brand grep mis-scoped (plan-critic #5) | SC-G | a plugin-name misnomer in commands/ slips | SC-G greps commands/+skills/+references/+README; S8 also judges the router's domain phrasing |
| Low | Touching a not-mine untracked file | repo `docs/` | accidental commit of operator/UI briefs | `forbidden_paths` in every manifest + explicit staging (own files only) |
| Low | Optional v4.2.0 bump fumbled as `fix:` (brief-review #4) | S8 phase-close | version-skew | If taken, the bump is the ONE feat-gated three-doc version-synced commit; run the full version grep |
## Assumptions
| # | Assumption | Why unverifiable | Impact if wrong |
|---|-----------|-----------------|-----------------|
| 1 | `quick` is the right S1 calibration command | operator preference, not yet confirmed | trivial — swap at S1 start |
| 2 | SC-H means "0 un-triaged findings", deferrals allowed | reconciling brief SC-H with SC-D | a legitimately-deferred finding would otherwise fail the gate |
| 3 | `newsletter` orchestration fits S4 with headless-review + pivot | depends on simulation size | S4 splits into its own session (logged) — permitted |
| 4 | ~~headless-review wiring may be broken~~ **RESOLVED** — wiring confirmed present (`headless-review.md:77-79,141-142`) | n/a | n/a — S4 verifies the table resolves, no fix expected |
| 5 | Version stays v4.1.0 through the phase; optional v4.2.0 at phase end | phase-end decision | none — pre-committed as optional |
## Verification
*Per-step manifest verification runs automatically during execution. End-to-end /
phase-level checks:*
- [ ] **SC-F (coverage, anchored):** `for c in $(ls commands/*.md | xargs -n1 basename | sed 's/.md//'); do grep -qE "^### /linkedin:$c( |—|$)" docs/hardening/log.md || echo "MISSING $c"; done` → no output (all 29 anchored entries; no substring false-positives).
- [ ] **SC-A…SC-E (per command):** each anchored `log.md` entry has intention + simulation (persona + CONCRETE before-output) + 4-axis evaluation + (if hardened) concrete after-output + verify line.
- [ ] **SC-C (mechanical, hard, per type):** every command records a pass/fail on its type's mechanical predicate (post-emitting → 4 content rules; routing → targets resolve; analytics → graceful-degradation present; guided → primary artifact produced) — never "N/A → judgment".
- [ ] **SC-G (no structural drift):** `ls commands/*.md | wc -l` → `29` every session; `bash scripts/test-runner.sh` → `Failed: 0` + exit 0 + `EXPECT_*` counts unchanged; `grep -rn "thought leadership plugin" commands/ skills/ references/ README.md` → 0.
- [ ] **SC-H (clean gate, reconciled):** each session's `review.md` shows **0 un-triaged findings** (each fixed in-session or carrying a recorded deferral rationale) and `/trekreview` returns **ALLOW** (deferrals noted, not WARN-override).
- [ ] **Oracle (independent):** each session's `/trekreview` adjudicated the before/after of **every** command hardened that session (recorded in `review.md`) — not a sample.
- [ ] **SC-I (field-notes):** where `docs/hardening/field-notes.local.md` has a finding for a session's commands, the log addresses or triages it; absent file → graceful no-op (does not block; the inbox is operator-owned).
- [ ] **Regression:** `node --test hooks/scripts/__tests__/*.test.mjs` → `Failed: 0` and `cd scripts/analytics && npm test` → `Failed: 0` whenever those surfaces are touched.
## Estimated Scope
- **Files to modify:** up to 29 command `.md` files (only where an axis gaps — some pass
clean with no edit) + occasional agent/reference edits where intention requires.
- **Files to create:** 1 (`docs/hardening/log.md`); `field-notes.local.md` is
operator-created (gitignored).
- **Complexity:** medium — low risk per edit (surgical prompt changes, no code/structure),
broad (29 surfaces) and judgment-heavy, de-risked by the per-type mechanical predicate +
the full-session cold-reviewer oracle.
## Execution Strategy
*8 sessions, sequential (each depends on the method locked in S1 and shares the single
`log.md` append target → not parallelizable without log-merge conflicts). Run one per
Voyage session via `/trekcontinue`. **Session-grouping note (plan-critic #6):** the
brief's session table was explicitly "to be confirmed/refined by /trekplan"; this plan
refines it — multiplatform→S2, batch→S3, headless-review+pivot→S4 — with full coverage
preserved (29, none dropped/doubled). `quick` is complete after S1.*
### Session 1: Method calibration + Start
- **Steps:** 1 · **Wave:** 1 · **Depends on:** none
- **Scope fence:** Touch: `commands/{quick,onboarding,first-post,setup}.md`, `docs/hardening/log.md`. Never touch: other commands, the 3 not-mine untracked files.
- **Circuit-breaker:** if S1 calibration fails, HALT — no later session runs until the method is re-locked with the operator.
### Session 2: Create I (atomic short-form)
- **Steps:** 2 · **Wave:** 2 · **Depends on:** Session 1 (hard gate — method locked)
- **Scope fence:** Touch: `commands/{post,react,multiplatform}.md`, `log.md`. Never touch: other commands.
### Session 3: Create II (visual + batch)
- **Steps:** 3 · **Wave:** 3 · **Depends on:** Session 1
- **Scope fence:** Touch: `commands/{carousel,video,batch}.md`, `log.md`. Never touch: other commands.
### Session 4: Create III (long-form cluster)
- **Steps:** 4 · **Wave:** 4 · **Depends on:** Session 1
- **Scope fence:** Touch: `commands/{newsletter,headless-review,pivot}.md`, `log.md`. Never touch: other commands. (May split 4a/4b if newsletter orchestration is large — logged.)
### Session 5: Engage
- **Steps:** 5 · **Wave:** 5 · **Depends on:** Session 1
- **Scope fence:** Touch: `commands/{firsthour,calendar,pipeline}.md`, `log.md`. Never touch: other commands.
### Session 6: Measure
- **Steps:** 6 · **Wave:** 6 · **Depends on:** Session 1
- **Scope fence:** Touch: `commands/{import,report,analyze,audit,ab-test}.md`, `log.md`. Never touch: other commands.
### Session 7: Grow
- **Steps:** 7 · **Wave:** 7 · **Depends on:** Session 1
- **Scope fence:** Touch: `commands/{strategy,competitive,monetize,outreach,profile}.md`, `log.md`. Never touch: other commands.
### Session 8: Front-doors + router (phase close)
- **Steps:** 8 · **Wave:** 8 · **Depends on:** Sessions 17 (routing targets must be hardened first)
- **Scope fence:** Touch: `commands/{create,measure,linkedin}.md`, `log.md`. Never touch: other commands.
### Execution Order
- **Wave 1:** Session 1 (calibration — hard gate; HALT-on-failure)
- **Waves 27:** Sessions 27 (each depends only on S1; sequential because they share `log.md`)
- **Wave 8:** Session 8 (after all targets hardened)
### Grouping rules applied
- Unit = one command; grouped by journey per the locked cadence.
- Create (8 cmd) split across S2S4; small journeys = one session each.
- Sessions share the single `log.md` append target → sequential, not parallel.
- Session 8 (routers) last — depends on its targets being hardened.
## Plan Quality Score
*Recomputed post-revision (the pre-review self-score was struck per plan-critic #17).*
| Dimension | Weight | Score | Notes |
|-----------|--------|-------|-------|
| Structural integrity | 0.15 | 90 | 8 steps dependency-ordered; S1 now a HALT-enforced gate; brief-vs-plan reassignment justified |
| Step quality | 0.20 | 85 | per-command 5-step method; VERIFY now backed by an independent oracle, not self-re-sim; headless-review resolved |
| Coverage completeness | 0.20 | 90 | anchored coverage predicate (no substring false-positives); all 29 mapped, none dropped/doubled |
| Specification quality | 0.15 | 86 | concrete files/verify; gate on `Failed: 0` not literal 74; stale-brand grep broadened; prior dispositions spot-confirmed |
| Risk & pre-mortem | 0.15 | 88 | brief-review + plan-critic blockers/majors folded with mitigations |
| Headless readiness | 0.10 | 85 | On-failure + Checkpoint per step; S1 HALT circuit-breaker; non-ALLOW halts the phase |
| Manifest quality | 0.05 | 78 | manifests anchor on the unique-anchored log entry; edit-correctness explicitly delegated to `/trekreview` (honest separation) |
| **Weighted total** | **1.00** | **87** | **Grade: B+** |
**Adversarial review:**
- **Plan critic:** REVISE — 2 blockers + 10 major + 5 minor (Grade C, 66). All blockers + majors addressed in this revision; see Revisions. (1 claim, #8 headless-review, found RESOLVED on verification; #5 found overstated, scope broadened anyway.)
- **Scope guardian:** ALIGNED — 0 creep, 0 material gaps; the `Failed: 0`-not-`74` caveat is adopted.
## Revisions
*Added by adversarial review (Phase 9) — plan-critic REVISE + scope-guardian caveat.*
| # | Finding | Severity | Resolution |
|---|---------|----------|------------|
| 1 | SC-F coverage grep matches command names as substrings (dropped command reads as covered) | blocker | Unique anchored log header `### /linkedin:<name> —`; all coverage/per-step greps anchored `^### /linkedin:$c` |
| 2 | `measure`/`create` collide with the Measure/Create journey labels | blocker | Same anchored-header fix; `:measure` ≠ the word "Measure" |
| 3 | Oracle samples ≥1/session of author-written sketches (80%+ self-graded) | major | Oracle now adjudicates **every** hardened command's before/after per session; simulation captures CONCRETE reproducible output, not a sketch |
| 4 | Mechanical axis inapplicable to ~13 no-output commands → pure judgment | major | Per-type mechanical predicate defined for every command class (routing/analytics/guided); never "N/A → judgment" |
| 5 | Stale-brand grep scoped to skills/ only | major→adjusted | Verified: `"thought leadership plugin"` is absent everywhere; grep broadened to commands/+skills/+references/+README; S8 also judges the router's domain phrasing |
| 6 | Brief-vs-plan session reassignment unjustified | major | Explicit refinement note (brief table was "to be confirmed by /trekplan"); coverage preserved |
| 7 | `Passed: 74` brittle under `set -e`; 74 hardcoded | major | All Verify/gate predicates → `Failed: 0` + exit 0 + unchanged `EXPECT_*` counts |
| 8 | headless-review wiring assumed-broken-then-deferred | major→resolved | Verified wiring is PRESENT (`--type → subagent_type` table, lines 77-79/141-142); S4 verifies, no fix expected; Assumption #4 struck |
| 9 | No circuit-breaker; S1 failure doesn't halt S2S8 | major | S1 On-failure = HALT; S1→S2..S8 hard dependency; any non-ALLOW `/trekreview` halts the phase |
| 10 | Manifests anchor on log.md; hardened command file invisible | major | Documented honest separation: manifest proves processing (unique anchor); `/trekreview` proves the edit (reads real diffs); a clean-pass command may have 0 edits |
| 11 | Prior dispositions cited but unverified ("do not re-verify") | major | Spot-confirm each cited disposition with one grep/read before relying |
| 12 | SC-E re-simulation is circular | major | Same as #3 — independent oracle + concrete captured output |
| 13 | node --test counts hardcoded/conditional | minor | Framed as `Failed: 0` (counts incidental) |
| 16 | `quick` double-count (S1 + brief's S2 spillover) | minor | Explicit "quick complete after S1; not re-hardened in S2" note |
| 17 | Plan pre-assigned Grade A before review | minor | Score recomputed post-revision (B+ 87); header note added |