Commit graph

57 commits

Author SHA1 Message Date
9e7b96fb95 feat(voyage): add lib/exporters/otlp-format.mjs — OTLP/JSON enum-integer SC #13
Step 10 av v4.1-execute (Wave 2, Session 3).

Pure function transformToOtlpJson(records) → OTLP/JSON v1.0 metrics payload
matching OTLP metrics.proto wire format.

CRITICAL (per research/01 dim 4 + risk-assessor CRITICAL 2):
- AggregationTemporality enum values er INTEGERS i JSON, IKKE strings
  ("CUMULATIVE" → 2, ikke "CUMULATIVE")
- timeUnixNano er uint64 over wire — emit som decimal STRING i JSON for å
  unngå JS Number precision loss på nanosekund-skala

Inline integer enum constants ved module-scope:
- AGG_TEMPORALITY_UNSPECIFIED = 0
- AGG_TEMPORALITY_DELTA = 1
- AGG_TEMPORALITY_CUMULATIVE = 2
- DATA_POINT_FLAGS_NONE = 0
- DATA_POINT_FLAGS_NO_RECORDED_VALUE_MASK = 1

Output struktur: resourceMetrics → scopeMetrics → metrics array. Sum-metrics
(counters: *_total, *_count, *_passed, *_failed, *_skipped) får sum +
isMonotonic + aggregationTemporality. Andre får gauge.

Tester (7 nye, baseline 406 → 413):
- SC #13: typeof aggregationTemporality === 'number' (HEART of SC #13)
- SC #13: enum-konstant drift-pin (typeof + verdi-assert)
- SC #13: typeof timeUnixNano === 'string' (precision-loss mitigation)
- SC #13: strukturell shape-assertion
- Empty input → valid envelope, tomt metrics-array
- isSum heuristic counter vs gauge
- Allowlist-redaksjon sanity (command_excerpt + session_id leaker ikke)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 09:32:29 +02:00
4e6b026104 feat(voyage): add lib/exporters/textfile-format.mjs — Prometheus text-format pure transform SC #12
Step 9 av v4.1-execute (Wave 2, Session 3).

Pure function transformToPrometheus(records) → Prometheus text-format 0.0.4.

Hard rules:
- NO client-side timestamps (research/01 node_exporter#1284 mitigation)
- Allowlist-redacted records ONLY (caller responsibility — Step 11 enforces)
- UTF-8 metric names normalized: lowercase, [.\\-\\s] → _, voyage_ prefix
- Empty input → empty string output
- Sorted output for determinism (snapshot-test-friendly)

Heuristic metric typing:
- counter: *_total, *_count, *_passed, *_failed, *_skipped
- histogram: *_ms, *_duration, *_p\\d+, *_seconds
- gauge: everything else (Prometheus convention)

Snapshot: tests/fixtures/expected.prom byte-for-byte match.
Regenerate: node scripts/gen-expected-prom.mjs > tests/fixtures/expected.prom

Tester (6 nye, baseline 400 → 406):
- Snapshot byte-for-byte match (SC #12)
- Empty input handling (null, undefined, [])
- Allowlist-redaction sanity (post-bash-stats uten command_excerpt)
- NO client-side timestamps (token-count-assertion per linje)
- normalizeMetricName edge-cases
- Determinism (identisk input → identisk output)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 09:30:58 +02:00
f8fc0bb1c2 feat(voyage): add lib/profiles/resolver.mjs — locked interface SC #5-#9
Step 6 av v4.1-execute (Wave 2, Session 2).

Implementer locked interface contract fra brief Preferences:

- loadProfile(name, opts) → ProfileObject
  Leser lib/profiles/<name>.yaml (built-in) eller custom fra
  <cwd>/voyage-profiles/ > ~/.claude/voyage-profiles/. Throws Error med
  cause: PROFILE_NOT_FOUND. Returnerer parsed object med phase_models
  flattened til {brief: 'sonnet', research: 'opus', ...} (object form
  for downstream JSON-stats).

- resolveProfile(argv, env) → {profile, profile_source}
  Ordre: --profile flag > VOYAGE_PROFILE env > 'premium' default.

- resolveTrekcontinueProfile(planPath, argv, opts) → {profile, profile_source}
  --profile flag wins ('flag'); ellers leser plan.md frontmatter
  ('inheritance'); v4.0-stil plan uten profile-felt → 'default' premium
  (backward-compat). Flag overstyrer arv → console.error advisory.

- validateProfileFile(path) → Result
  Tynn re-eksport av validateProfile fra profile-validator.mjs.

- findProfilePath(name, opts) → {path, attempted}
  Lookup-helper. attempted-array brukes i error-melding for HIGH-risk-
  mitigering (ENOENT-diagnose).

Tester (13 nye, baseline 387 → 400):
- SC #5 x4 (loadProfile economy/balanced/premium + PROFILE_NOT_FOUND)
- SC #6 (flag > env > default ordre)
- SC #7 (performance: 1000-iter < 50ms gjennomsnitt; faktisk ~0.055ms)
- SC #8 x2 (cwd > home precedence + error-msg attempted-paths)
- SC #9 x2 (inheritance + flag-override-advisory)
- Backward-compat x2 (v4.0 plan + non-existent plan)
- validateProfileFile re-export sanity

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 09:29:01 +02:00
b56ba13b04 feat(voyage): add lib/validators/profile-validator.mjs — SC #1, #2, #3
Step 5 av v4.1-execute (Wave 2, Session 2).

Profile-validator etter brief-validator-mønsteret eksakt: validateProfileContent
(pure), validateProfile (file-reader), CLI shim med --json flag. Eksporter
PROFILE_REQUIRED_FIELDS (frozen), PROFILE_REQUIRED_PHASES (frozen).

Validerer:
- Required frontmatter fields (name, phase_models, parallel_agents_min/max,
  external_research_enabled, brief_reviewer_iter_cap)
- phase_models = list-of-dicts med phase + model
- 6 required phases (brief, research, plan, execute, review, continue)
- parallel_agents_max ≥ parallel_agents_min
- Allowed model values: ['sonnet', 'opus']; haiku tillatt KUN ved
  VOYAGE_ALLOW_HAIKU=1 (per global CLAUDE.md modellvalg-prinsipp)

Issue codes: PROFILE_MISSING_FIELD, PROFILE_INVALID_MODEL, PROFILE_INVALID_ENUM,
PROFILE_READ_ERROR, PROFILE_NOT_FOUND.

Field-path-reporting i error-location: phase_models[N].model for SC #2.

Tester (10 nye, baseline 377 → 387):
- SC #1 x3 (innebygde profiler grønne)
- SC #2 (PROFILE_INVALID_MODEL med location phase_models[2].model)
- SC #3 (PROFILE_INVALID_ENUM for external_research_enabled: "yes" string)
- VOYAGE_ALLOW_HAIKU env-var deny/allow
- PROFILE_MISSING_FIELD når name fraværende
- PROFILE_NOT_FOUND for ikke-eksisterende fil
- 2 export drift-pins

Fixturer: profile-invalid-model.yaml (gpt-4 i phase_models[2]),
profile-invalid-enum.yaml (external_research_enabled som string "yes").

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 09:26:23 +02:00
6d1c9f8967 feat(voyage): add OPTIONAL_STRING_KEYS path to manifest-yaml — profile_used additive
Step 3 av v4.1-execute (Wave 1, Session 1).

Legg ny eksportert const OPTIONAL_STRING_KEYS = ['profile_used'] parallel
til eksisterende OPTIONAL_KEYS. Utvid parseManifest med ny dispatch-loop
etter OPTIONAL_BOOLEAN_KEYS. Returnerer MANIFEST_OPTIONAL_TYPE hvis
profile_used finnes men ikke er string.

Forskjell fra OPTIONAL_BOOLEAN_KEYS: absence == not-present (NOT defaulted
til false, unlike boolean). Downstream-konsumenter kan dermed skille mellom
unset og empty-string.

Tester (5 nye, baseline 372 → 377):
- OPTIONAL_STRING_KEYS export drift-pin
- profile_used: economy parses successfully (SC #10 forward-compat)
- profile_used: numeric rejected
- absence: field NOT in parsed (string-key semantics)
- profile_used + skip_commit_check + memory_write co-existence

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 09:23:32 +02:00
0787048f90 feat(voyage): add --profile valued flag to arg-parser FLAG_SCHEMA — v4.1 SC #4
Step 2 av v4.1-execute (Wave 1, Session 1).

Legg --profile i valued-arrayen for alle 6 voyage-kommandoer (trekbrief,
trekresearch, trekplan, trekexecute, trekreview, trekcontinue). Mønster
identisk med eksisterende --project/--brief valued-handling. Ingen endring
til parseArgs-logikk — utvider kun schema.

Tester (11 nye, baseline 361 → 372):
- 6 happy-path-tests (én per kommando)
- ARG_MISSING_VALUE for --profile uten verdi
- --profile + --quick kombo
- --profile + --gates edge-case (--gates parses inline, ikke i FLAG_SCHEMA)
- --profile + --project kombo
- trekcontinue --profile (validerer at tomt valued[] nå er utvidet)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 09:22:01 +02:00
43a3e4f11d docs(voyage): jsonl schema audit — field-allowlist input for v4.1 otel exporter
Step 1 av v4.1-execute (Wave 1, Session 1).

Audit alle 6 trek*-stats.jsonl-skjemaer + lib/stats/event-emit.mjs autonomy
events + hooks/scripts/post-bash-stats.mjs PostToolUse Bash records. Produser
markdown-tabell {schema_id, fields[], writer_path, line_ref, v4.1 additive,
PII} som load-bearing input til Step 11 (field-allowlist) og Step 8 (stats
plumbing).

Spesielle merker:
- command_excerpt fra post-bash-stats.mjs flagget CWE-212 (improper cross-
  boundary removal of sensitive data) — eksporten MÅ hard-ekskludere uten
  eksplisitt VOYAGE_EXPORT_INCLUDE_COMMAND_EXCERPT=1 (deferred til v4.2)
- v4.1 additive fields enumerert per skjema: profile, phase_models,
  parallel_agents, external_research_enabled, profile_source
- EXPORT_ALLOWLIST + EXPORT_DENYLIST utdrag i bunnen som forhåndsdefinisjon
  av Step 11 inline static consts

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-09 09:20:54 +02:00
c909466c99 feat(voyage)!: bulk content rewrite ultra -> voyage/trek prose [skip-docs]
Sed-pipeline (16 patterns, longest-match-first) sweeper residuelle ultra*-treff
i prose, command-narrativ, agent-prompts, hook-kommentarer, doc-prosa.

Pipeline-utvidelser fra V4-prompten:
- BSD-syntax [[:<:]]ultra[[:>:]] istedenfor \bultra\b (BSD sed mangler \b)
- 6 compound-patterns for ultraplan/ultraexecute/ultraresearch/ultrabrief/
  ultrareview/ultracontinue uten -local-suffiks
- ultra*-stats glob -> trek*-stats glob
- Linje-eksklusjon redusert til ultra-cc-architect (Q8); session-state-
  eksklusjonen var over-protektiv
- File-eksklusjon utvidet til settings.json, package.json, plugin.json,
  hele .claude/-treet (gitignored + V5-territorium)

Q8-undantak holdt: architecture-discovery.mjs + project-discovery.mjs urort.
Filnavn-konvensjon holdt: .session-state.local.json + *.local.* preservert.

Manuell narrative-fix: tests/lib/agent-frontmatter.test.mjs linje 10
mangled "/ultra*-local" til "/voyage*-local" (ingen slik kommando finnes);
korrigert til "/trek*".

Residualer utenfor scope (V5 handterer): package.json + .claude-plugin/
plugin.json (Step 12-14 versjons-bump). .claude/* er gitignored
spec-historikk med tilsiktet BEFORE/AFTER-narrativ.

Part of voyage-rebrand session 3 (Wave 4 / Step 10).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-05 15:08:20 +02:00
d22ec05fed feat(voyage)!: rename stats filenames, settings keys, hook prefixes [skip-docs]
- lib/stats/event-emit.mjs: STATS_FILENAME -> trekexecute-stats.jsonl + comment
- hooks/scripts/post-bash-stats.mjs: stats target + comment -> trekexecute-stats.jsonl
- lib/stats/cache-analyzer.mjs: help-text + comment -> trekexecute-stats.jsonl
- tests/lib/stats-event-emit.test.mjs (lines 104, 117): fixture assertions
- settings.json: ultraplan/ultraresearch -> trekplan/trekresearch keys + statsFile values
- tests/lib/doc-consistency.test.mjs: allowlist (line 83) + accessor cfg.ultraplan?.* -> cfg.trekplan?.* (lines 91, 93) — atomic-pair, prevents vacuous undefined assertions
- scripts/q3-cache-prefix-experiment.mjs: STATS_JSONL hardcoded path -> voyage data dir + trekexecute filename
- hooks/scripts/pre-bash-executor.mjs (2 lines), pre-compact-flush.mjs (2 lines), pre-write-executor.mjs (1 line): [ultraplan]/[ultraplan-local] stderr prefix -> [voyage]
- commands + agents/review-orchestrator.md + CLAUDE.md: prose stats filename literals -> trek* equivalents

Atomic per session-spec: settings.json scope keys + doc-consistency.test.mjs
allowlist + property accessors committed together to prevent silent vacuous
undefined-equals-undefined assertions.

Part of voyage-rebrand session 2 (W3.7 / Step 9).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-05 14:49:03 +02:00
acc053ae6d feat(voyage)!: rename produced_by field values + validator comments [skip-docs]
- commands/trekexecute.md: produced_by literals -> trekexecute (4 occurrences)
- commands/trekendsession.md: produced_by literals -> trekendsession (2 occurrences)
- tests/validators/next-session-prompt-validator.test.mjs: 11 'ultraexecute-local' refs -> 'trekexecute'
- tests/commands/trekcontinue.test.mjs: 3 fixture strings updated
- tests/lib/cleanup.test.mjs: 1 fixture string updated
- lib/validators/next-session-prompt-validator.mjs: producer-list comment
- docs/HANDOVER-CONTRACTS.md line 432: example producer names updated

Part of voyage-rebrand session 2 (W3.4 / Step 6).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-05 14:42:21 +02:00
12f4391dca feat(voyage)!: rename type discriminators across validators + fixtures [skip-docs]
- brief-validator: BRIEF_TYPE_VALUES ['ultrabrief','ultrareview'] -> ['trekbrief','trekreview'] + dependent branches
- research-validator: 'ultraresearch-brief' -> 'trekresearch-brief'
- review-validator: 'ultrareview' -> 'trekreview'
- 3 templates frontmatter type:
- 4 synthetic fixtures: ultraplan-synthetic/ultrareview-synthetic -> trek* (frontmatter only; bodies untouched, Jaccard floor preserved)
- 2 trekreview fixtures: type: trekreview
- 6 validator-test fixtures + asserts
- agents/review-coordinator.md frontmatter example

Atomic: validator + fixtures committed together — partial state would cause vacuous
test passes or hard validator rejection.

Part of voyage-rebrand session 2 (W3.3 / Step 5).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-05 14:40:25 +02:00
6dee27c136 feat(voyage)!: FLAG_SCHEMA keys trek* + arg-parser test cases [skip-docs]
- Rename FLAG_SCHEMA keys ultrabrief|ultraresearch|ultraplan|ultraexecute|ultrareview|ultracontinue -> trek* equivalents
- Update 26 literal key references in tests/lib/arg-parser.test.mjs
- Update parseArgs($ARGUMENTS, 'ultracontinue') -> 'trekcontinue' in commands/trekcontinue.md
- trekendsession.md audited: no parseArgs invocation, no FLAG_SCHEMA entry needed

Atomic per session-spec: schema + tests + consuming commands committed together to
avoid vacuous-pass risk.

Part of voyage-rebrand session 2 (W3.2 / Step 4).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-05 14:35:01 +02:00
4f8d9c70e5 feat(voyage)!: rename commands, templates, fixtures for v4.0.0 [skip-docs] 2026-05-05 14:13:44 +02:00
1574a74556 docs(ultraplan-local): Handover 7 § Lifecycle (SC-5 stale-file principle)
Step 11 of v3.4.1 plan. Adds the lifecycle subsection to Handover 7
documenting:

- Producer/consumer arbeidsdeling (executor + helper write; ultracontinue
  reads; pre-compact-flush refreshes only)
- Stale-file principle: status==='completed' state files SHOULD be
  removed via /ultracontinue-local --cleanup --confirm (operator-invoked,
  no auto-cleanup, no force flag)
- Frontmatter contract for NEXT-SESSION-PROMPT.local.md: producers MUST
  write produced_by + produced_at (ISO-8601); files without frontmatter
  are tolerated (warning, not error) for backwards compatibility
- Idempotency: --cleanup --confirm is safe to re-run; partial state
  reported but never auto-recovered

Adds 3 doc-consistency pins:
- next-session-prompt-validator CLI shim
- Handover 7 § Lifecycle subsection present
- Handover 7 § Lifecycle names --cleanup + produced_by contract

358 -> 361 tests, all green.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 17:48:37 +02:00
054bff5231 feat(ultraplan-local): Bug 4 — wire --cleanup into /ultracontinue-local [skip-docs]
Step 10 of v3.4.1 plan.

commands/ultracontinue-local.md:
- New Phase 0.5 between Phase 0 and Phase 1 — terminal cleanup mode
  triggered by parsed flags['--cleanup'] === true. Requires explicit
  positional[0] (no "clean all"), no template placeholders in the Bash
  invocation. Passes through to cleanupProject via inline ESM. Cleanup
  never falls through to Phase 1/2/3/4.
- Phase 0 usage block updated to document --cleanup and --cleanup
  --confirm forms alongside the legacy <project-dir> form.

tests/commands/ultracontinue.test.mjs:
- Test (Bug 4 prose) — Phase 0.5 header present, references
  cleanupProject and flags['--cleanup'], appears between Phase 0 and
  Phase 1 in document order, usage mentions --cleanup --confirm.
- Test (f-1) dry-run on completed project lists candidates without
  deleting; both files still on disk.
- Test (f-2 + f-3) confirm-mode deletes both files; subsequent
  invocation on the already-cleaned dir signals CLEANUP_NO_STATE_FILE
  (deterministic terminal state, idempotent for operators).

Tests 355 -> 358 (+3).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 17:42:56 +02:00
c7c6d8d09d feat(ultraplan-local): cleanup util (Bug 4 dry-run/confirm/idempotent) [skip-docs]
Step 9 of v3.4.1 plan.

lib/util/cleanup.mjs (new):
- cleanupProject(projectDir, {dryRun, confirm}) reads
  .session-state.local.json via validateSessionState; refuses unless the
  parsed status is strictly equal to 'completed' (per risk-assessor
  Critical 2 — no soft-match on similar statuses).
- Default dryRun: true; refuses dryRun: false without explicit
  confirm: true (CLEANUP_REQUIRES_CONFIRM).
- Removes .session-state.local.json + NEXT-SESSION-PROMPT.local.md
  candidates; ENOENT counts as "already absent" so the function is
  idempotent.
- No CLI shim — invoked from /ultracontinue --cleanup via inline ESM
  (Step 10 wires this in).

tests/lib/cleanup.test.mjs (new):
- 7 cases: dry-run lists candidates without deleting; confirm-mode
  deletes both files; idempotent re-run signals CLEANUP_NO_STATE_FILE
  after fully cleaned; refuses on status: in_progress
  (CLEANUP_NOT_COMPLETED); refuses dryRun: false without confirm
  (CLEANUP_REQUIRES_CONFIRM); defaults to dry-run; missing state file
  returns CLEANUP_NO_STATE_FILE.

Internal scaffolding consumed by Step 10 (Phase 0.5 wire-up). User-facing
docs land with Step 14.

Tests 348 -> 355 (+7).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 17:41:06 +02:00
6a300b854b fix(ultraplan-local): Bug 3 — wire frontmatter consistency check into /ultracontinue Phase 1.5
Step 8 of v3.4.1 plan.

commands/ultracontinue-local.md:
- New Phase 1.5 between Phase 1 and Phase 2 — runs the
  next-session-prompt-validator in --consistency mode when both candidates
  exist (plugin-root + project-dir). Refuses on producer mismatch with
  fresh candidates, downgrades stale candidate to a warning, downgrades
  >24h wall-clock drift to a soft warning.
- Anti-substitution rule applies — paths emitted as concrete tokens, not
  template placeholders.

lib/validators/next-session-prompt-validator.mjs:
- Sharpen NEXT_SESSION_PROMPT_PRODUCER_MISMATCH error message to include
  the literal "produced_by" field name so consumers (and operators) can
  trace the disagreement back to the YAML key.

tests/commands/ultracontinue.test.mjs:
- Test (Bug 3 prose) — Phase 1.5 header present, references validator,
  appears between Phase 1 and Phase 2 in document order.
- Test (Bug 3 e) — tmp project dir with state file + two prompt files
  with mismatched producers, both fresh relative to state.updated_at;
  CLI consistency mode exits non-zero, JSON stdout surfaces
  NEXT_SESSION_PROMPT_PRODUCER_MISMATCH with both paths and the
  "produced_by" token in the message.

Tests 346 -> 348 (+2).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 17:39:42 +02:00
deb42f43e9 feat(ultraplan-local): next-session-prompt-validator (Bug 3 consistency check) [skip-docs]
Step 6 of v3.4.1 plan. Adds the validator quartet
(Content/Object/Consistency/CLI) for NEXT-SESSION-PROMPT.local.md
frontmatter (produced_by, produced_at). State-anchored staleness check
is the primary refusal; 24h wall-clock drift downgraded to soft warning
to avoid false positives on weekend pauses.

Internal scaffolding consumed by Step 8 (Phase 1.5 wire-up). User-facing
docs land with Step 14 (CHANGELOG + README + version bump).

Tests 335 -> 346 (+11): 9 unit + 2 CLI shim cases.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-04 17:34:16 +02:00
ced27c24cd test(ultraplan-local): failing tests for /ultracontinue Bug 2 (SC-3)
Step 4 of v3.4.1 hot-fix plan. Two new tests in
tests/commands/ultracontinue.test.mjs:

  (d-1) ALLOW-resolved-path — runHook + pre-bash-executor sanity check
        that a concrete validator invocation (no template placeholders)
        is not blocked by the marketplace bash-guard.
  (d-2) NO-PLACEHOLDER — Pattern D structure assertion that Phase 2
        contains neither {state-file-path} nor any other
        {lowercase-template} curly-brace placeholder, and that the
        Phase 2 prose explicitly documents the deterministic Read
        tool flow.

(d-1) passes today (the planned bash form is allowed). (d-2) fails
intentionally on current Phase 2 — Step 5 fix turns it green.
2026-05-04 16:38:56 +02:00
fb44f161ed test(ultraplan-local): failing tests for /ultracontinue Bug 1 (SC-1, SC-2)
Step 2 of v3.4.1 hot-fix plan. Establishes tests/commands/
directory and adds Pattern D structure tests against
commands/ultracontinue-local.md prose:

  (a) Phase 1 must document Date.parse(updated_at) numeric sort
  (b) Phase 0 must NOT use substring "contains --help" dispatch;
      must reference parsed flags or positional[0]
  (c) Phase 1 must reference auto-discovery as empty-args fallback
  (d) Phase 1 must emit SC-2 diagnostic strings for .md positional arg

Tests (a), (b), (d) fail intentionally on current prose; Step 3
fix turns them green. Test (c) passes already (current Phase 1
prose says "non-empty" which matches the regex assertion).
2026-05-04 16:36:44 +02:00
9070a126a8 test(ultraplan-local): add ultracontinue to FLAG_SCHEMA + tests
Step 1 of v3.4.1 hot-fix plan (project 2026-05-04-v3.3.1-ultracontinue-fixes).

Adds ultracontinue entry to FLAG_SCHEMA covering boolean flags --help,
--cleanup, --confirm, --dry-run with no valued flags. The -h short form
is intentionally not aliased: it appears as positional[0] === '-h' and
the command prose dispatches usage on either condition.

7 new tests in tests/lib/arg-parser.test.mjs verify empty args, --help,
-h positional, --cleanup, --cleanup --confirm, project-dir positional,
and .md positional (parser-level accept; command-level reject).
2026-05-04 16:34:55 +02:00
14c3ff858f test(ultraplan-local): add path-guard + bash-guard baseline hook tests (SC8 baseline)
Pins existing BLOCK rules in the two pre-* executor hooks so a future
silent weakening of BLOCK_RULES surfaces as test failures instead of
slipping through code review.

50 new tests covering both hooks plus allow-list pins (lib/, tests/,
docs/, ls, git, npm) and fail-open on malformed input. Reuses
tests/helpers/hook-helper.mjs child-process spawner.

[skip-docs]
2026-05-04 08:55:49 +02:00
c37e41d324 test(ultraplan-local): add plan-determinism + review-determinism synthetic fixtures (SC7 floor)
Adds 6 files in tests/synthetic/ exercising the determinism pipeline at the
SC7 brief floor (Jaccard >= 0.833). Plan fixture pair: 40 step titles each
with 38 shared (Jaccard 0.905). Review fixture pair: 30 finding-IDs each
with 28 shared (Jaccard 0.875). Reuses lib/parsers/jaccard.mjs +
lib/parsers/finding-id.mjs.

The new pair coexists with tests/lib/review-determinism.test.mjs which
holds the older SC4 (0.70) floor against tests/fixtures/ultrareview/.
The lower floor protects pipeline regressions; the higher floor anchors
the speedup brief's determinism aspiration.

[skip-docs]
2026-05-04 08:46:39 +02:00
ecca22999e feat(ultraplan-local): add PostCompact rehydrate hook to re-inject session-state after compaction
New hooks/scripts/post-compact-flush.mjs (PostCompact event, CC v2.1.105+):
auto-discovers <cwd>/.claude/projects/*/.session-state.local.json (most
recently modified), validates it via session-state-validator, emits
additionalContext via stdout so the post-compact assistant turn has
Handover 7 resume context loaded immediately.

Read-only — never writes. Always exits 0; never blocks compaction. Uses
only node:fs sync APIs available since Node 12 (no glob dependency).

Companion to the existing pre-compact-flush.mjs:
  - PreCompact: refresh progress.json + .session-state.local.json
  - PostCompact: re-inject .session-state.local.json into context

Wired in hooks/hooks.json under a new PostCompact matcher block.

Both files staged via /tmp/claude-* and copied into hooks/* via Bash to
respect the llm-security plugin path-guard (which blocks direct Write to
hooks/scripts/*.mjs and hooks*.json).

Test: tests/hooks/post-compact-flush.test.mjs (4 tests) covers no-state,
malformed-state, valid-state, and multi-project mtime selection.
2026-05-04 07:57:42 +02:00
c3ae101417 feat(ultraplan-local): emit main-merge-gate stats event from Phase 8
Wire the main-merge-gate lifecycle event into commands/ultraexecute-local.md
Phase 8. Three event variants emitted via lib/stats/event-emit.mjs (S8):
  - main-merge-gate     fired at the gate boundary
  - main-merge-approved fired on operator confirm
  - main-merge-declined fired on operator decline (run recorded as partial)

The gate ALWAYS pauses regardless of gates_mode — it is the one always-on
boundary that --gates does not toggle. On decline, --resume re-enters at
the gate, and the wave session branches survive on the remote thanks to
Hard Rule 19's push-before-cleanup. Recovery surface is documented inline.

Pin in tests/lib/main-merge-gate.test.mjs locks the always-on prose, the
event names, and the recovery-surface contract.
2026-05-04 07:55:41 +02:00
fa5b6153a6 feat(ultraplan-local): add --gates autonomy-control flag to all four pipeline commands
Single autonomy-control surface (--gates) added to ultrabrief, ultraresearch,
ultraplan, and ultraexecute. When present, sets gates_mode = true and
re-enables approval pauses at every phase boundary + every wave for
high-stakes runs. When absent (default in auto), the chain runs continuously
to the main-merge gate (which always pauses regardless of --gates — that
boundary is the one always-on safety stop).

ultrabrief:    pause after auto-mode confirmation; emit brief-approved event
ultraresearch: pause after each topic completes
ultraplan:     pause after Phases 5, 7, 9
ultraexecute:  pause after each wave's worktrees finish, before merge-back,
               AND before the main-merge gate (MAIN_MERGE_GATE)

All four commands invoke the autonomy-gate state machine via the CLI shim
node lib/util/autonomy-gate.mjs (built in S8). Test pin in
tests/lib/gates-flag-coverage.test.mjs locks the contract.

Also wires the brief-approved stats emission into ultrabrief Phase 5 auto
path (was the SC4 wiring requirement from plan-v2 Step 11).
2026-05-04 07:54:30 +02:00
bc2d167824 feat(ultraplan-local): mirror Phase 2.6 hardenings in headless-launch-template
Bring the launch template (used by /ultraplan-local --decompose) into
contract-parity with the Phase 2.6 wave executor hardenings shipped in the
previous commit:

- GIT_OPTIONAL_LOCKS=0 exported once at the top
- MAX_TURNS / MAX_BUDGET_USD env-overridable (default 50 / 5)
- Absolute SHARED_CONTEXT_FILE built from brief + architecture
- SAFETY_PREAMBLE prepended to every per-session prompt (GH #36071 +
  GH #52272 clarifications)
- Per-child --max-turns + --max-budget-usd + --append-system-prompt-file
- push-before-cleanup before merge AND in the cleanup_worktrees trap
- Three new template rules (16, 17, 18, 19) document the contract for
  session-decomposer

Pin in tests/lib/doc-consistency.test.mjs locks all required substrings
against future regressions.
2026-05-04 07:51:50 +02:00
b7dfe39293 feat(ultraplan-local): harden Phase 2.6 wave executor (11 sub-changes for plugin-in-monorepo + gitignored-state topology)
Phase 2.6 + Hard Rules + Phase 2.4 hardenings against the topology that
blocked S6 / S7 self-execution:

Phase 2.6 (multi-session orchestration):
  - NEW Step 2a-pre: build absolute SHARED_CONTEXT_FILE (brief + architecture)
    once per wave; introduce ULTRAEXECUTE_MAX_TURNS / ULTRAEXECUTE_MAX_BUDGET_USD
    overrides for long runs.
  - Step 2a: prefix every git worktree command with GIT_OPTIONAL_LOCKS=0
    (research/02 R2; GH #47721).
  - NEW Step 2a': copy gitignored project artifacts (brief.md, plan.md,
    research/) into each freshly-created worktree using PROJECT_SOURCE +
    PROJECT_REL so plugin-in-monorepo + gitignored-state topology works
    (brief Constraint 2).
  - Step 2b: prepend two safety preambles to every per-session prompt:
      (a) defense-in-depth headless-mode warning citing GH #36071
      (b) malware-reminder conditional clarification per GH #52272
    Honor `cwd:` field from Execution Strategy via SESSION_CWD; default
    is worktree root (backward-compatible). Add per-child --max-turns,
    --max-budget-usd, --append-system-prompt-file (research/06 R3+R4).
  - Step 2e: push branch BEFORE merge (research/02 R3 — converts
    unrecoverable branch loss into recoverable remote state).
  - Step 2f: prefix all worktree-remove / branch -d / worktree prune with
    GIT_OPTIONAL_LOCKS=0.
  - Step 4 cleanup: same GIT_OPTIONAL_LOCKS=0 treatment.

Hard Rules:
  - Hard Rule 15: extend exception to permit ~/.claude/projects/*/memory/
    writes when manifest declares memory_write: true (brief Constraint 3
    Option A — narrow opt-in for memory file edits).
  - Hard Rule 19 (new): push-before-cleanup formalized as a rule.

Phase 2.4: advisory hooks-fire precheck for CC version >= v2.1.117
  (research/04 D4 + R5; research/06 R1).

Test: tests/hooks/worktree-guard.test.mjs (6 tests) verifies the
pre-bash-executor and pre-write-executor hooks accept routine worktree
cleanup (Hard Rule 12) while still blocking the dangerous patterns
introduced by parallel orchestration.
2026-05-04 07:49:45 +02:00
3a365561cb feat(ultraplan-local): parallelize Phase 9 review with inline dedup
Strengthen single-message reinforcement for plan-critic + scope-guardian
parallel dispatch in commands/ultraplan-local.md Phase 9 and mirror in
agents/planning-orchestrator.md Phase 6. Reviewers now write structured JSON
to /tmp/{plan-critic,scope-guardian}-out.json which is merged via the
lib/review/plan-review-dedup.mjs CLI shim from S8.

The merged set lets us revise the plan once for duplicate findings instead
of twice. Source: research/05 R1 + R2.

Pin in tests/lib/doc-consistency.test.mjs locks both files against
single-message + dedup-helper regressions.
2026-05-04 07:43:50 +02:00
8d8d1033d6 feat(ultraplan-local): seal Opus-4.7 schema-drift defense in Phase 8
Inline STEP_HEADING_REGEX, FORBIDDEN_HEADING_REGEX, the canonical step+manifest
example, and the post-write plan-validator self-check directly into Phase 8 of
commands/ultraplan-local.md. This eliminates the dependency on Opus 4.7
implicitly loading agents/planning-orchestrator.md — the format contract now
travels with the command file itself.

Source: research/04 D5 + plan-v2 Step 7. Pin in tests/lib/doc-consistency.test.mjs
locks the substrings so future edits cannot silently regress the seal.
2026-05-04 07:41:48 +02:00
a8ae5b65f6 feat(ultraplan-local): add stats event-emit for autonomy lifecycle events
Step 6 of plan-v2 (ultra-pipeline-speedup).

lib/stats/event-emit.mjs (NEW)
  Atomic JSONL append to ${CLAUDE_PLUGIN_DATA}/ultraexecute-stats.jsonl.
  Every record carries:
    ts          : ISO-8601 timestamp (REQUIRED per SC4)
    event       : caller-supplied name
    known_event : true for { brief-approved, main-merge-gate, user_input },
                  false for everything else (still emitted — audit-complete)
    payload     : caller object (defaults to {})

  Stats failures NEVER block workflow: missing CLAUDE_PLUGIN_DATA, missing
  dir, mkdir failure, append failure → all return { written: false, reason }
  without throwing.

  CLI shim:
    node lib/stats/event-emit.mjs --event NAME [--payload JSON]
  Always exits 0 (telemetry is best-effort).

Tests: 12 (record-build + ISO-8601 ts + known/unknown distinction + silent
skip + dir-on-demand + CLI shim happy-path + bad-payload tolerance +
concurrent-append smoke).

[skip-docs]
2026-05-04 06:31:52 +02:00
eaeb68f317 feat(ultraplan-local): add plan-review-dedup helper for Phase 9 finding dedup
Step 5 of plan-v2 (ultra-pipeline-speedup).

lib/review/plan-review-dedup.mjs (NEW)
  Two-pass dedup:
    1. Exact match  — identical computeFindingId(file:line:rule_key) → merge.
    2. Jaccard ≥ 0.7 on text-token sets → merge near-duplicates.
  Provenance preserved in surviving finding's raised_by[] (which agents
  raised it). Reuses lib/parsers/jaccard.mjs + lib/parsers/finding-id.mjs.

  CLI shim:
    node lib/review/plan-review-dedup.mjs \
         --plan-critic /tmp/x.json --scope-guardian /tmp/y.json
  Missing inputs tolerated (single-agent review still works).

Tests: 10 (tokenize + threshold + 6 dedup-logic cases + 2 CLI shim).

[skip-docs]
2026-05-04 06:30:28 +02:00
65b8fbc16f feat(ultraplan-local): add autonomy-gate state machine + manifest schema extensions for skip_commit_check + memory_write
Step 4 of plan-v2 (ultra-pipeline-speedup).

lib/util/autonomy-gate.mjs (NEW)
  5-state machine {idle, gates_on, auto_running, paused_for_gate, completed}
  honoring the --gates flag intent. Re-entry to completed is idempotent.
  Includes CLI shim:
    node lib/util/autonomy-gate.mjs --state X --event Y [--gates true|false]
  → JSON: { ok, next_state | error }, exit 0 on success / 1 on invalid.

lib/parsers/manifest-yaml.mjs (EXTENDED)
  OPTIONAL_KEYS list adds skip_commit_check and memory_write — both boolean,
  default false when absent, MANIFEST_OPTIONAL_TYPE when non-boolean.
  Existing REQUIRED_KEYS contract untouched; existing 9 manifest tests
  still pass.

Tests: 19 (autonomy-gate) + 8 (manifest-schema-extensions) = 27 new.

[skip-docs]
2026-05-04 06:28:47 +02:00
491e726cf8 test(ultraplan-local): pin agent frontmatter contract (model + tools)
Pin the contract from plan-v2 Steps 1-3: every agents/*.md must declare
model: (opus|sonnet|haiku) AND (tools: or disallowedTools:). Orchestrators
(planning/research/review) must be opus and include the Agent tool;
non-orchestrators must not include Agent (no recursive swarming).

23 agents in scope; 5 pinning tests.

[skip-docs]
2026-05-04 06:26:08 +02:00
Kjell Tore Guttormsen
d58f6bf473 docs(ultraplan-local): add Handover 7 + doc-consistency pins for /ultracontinue
Adds Handover 7 (.session-state.local.json) section to HANDOVER-CONTRACTS.md
documenting the multi-session-resume contract:
- Producers: ultraexecute Phase 8/2.55/4 + helper command + future
  graceful-handoff v2.2 + pre-compact-flush refresh
- Consumer: /ultracontinue (read-only)
- Schema v1: schema_version, project, next_session_brief_path,
  next_session_label, status (5-value enum), updated_at
- Forward-compat: unknown top-level keys silently tolerated (drift-WARN)
- Path: .claude/projects/<project>/.session-state.local.json (gitignored)
- Failure modes mapped to validator error codes

Also updates the validator → handover map and Versioning + Stability
tables to include Handover 7.

Extends tests/lib/doc-consistency.test.mjs with three new pins:
1. HANDOVER-CONTRACTS.md contains Handover 7 section
2. session-state-validator.mjs exposes the standard CLI shim
3. CLAUDE.md mentions /ultracontinue-local

Adds the /ultracontinue-local row to the plugin CLAUDE.md commands table —
minimum viable to keep the existing 'CLAUDE.md commands table mentions
every commands/*.md file' iteration test green. Step 11 (Session 2b) will
expand to full README + CLAUDE.md narrative documentation.

Test suite: 182 → 185 (3 new doc-consistency pins, zero regressions).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 20:53:47 +02:00
Kjell Tore Guttormsen
282dcea518 feat(ultraplan-local): add session-state-validator + tests for /ultracontinue
Validator at lib/validators/session-state-validator.mjs:
- validateSessionStateObject(parsed, opts) — pure object validation
- validateSessionStateContent(jsonText, opts) — wraps JSON parse + validation
- validateSessionState(filePath, opts) — file-mode with existsSync guard
- CLI shim with --json output (errors→stderr, result→stdout, exit 0/1/2)
- Schema v1: schema_version, project, next_session_brief_path,
  next_session_label, status, updated_at
- Error codes: SESSION_STATE_PARSE_ERROR, SESSION_STATE_NOT_FOUND,
  SESSION_STATE_MISSING_FIELD, SESSION_STATE_INVALID_STATUS,
  SESSION_STATE_NOT_RESUMABLE (warning), SESSION_STATE_SCHEMA_MISMATCH,
  SESSION_STATE_INVALID_TIMESTAMP, SESSION_STATE_INVALID_PATH
- Forward-compat hard requirement: unknown top-level keys ignored —
  protects future graceful-handoff v2.2 dual-writes

Tests at tests/validators/session-state-validator.test.mjs — 15 subtests:
- happy path + 5 missing-field tests
- invalid status, completed warns NOT_RESUMABLE, schema mismatch, bad
  timestamp, malformed JSON, missing file
- fixture load (SC-1) + malformed fixture (SC-3)
- forward-compat: unknown keys ignored silently

167 → 182 tests, 0 fail.

Step 4 of /ultracontinue v3.3.0. Closes Session 1 of the execution
strategy (foundation: gitignore + util + fixtures + validator+tests).
2026-05-01 20:23:09 +02:00
Kjell Tore Guttormsen
9a285208d2 test(ultraplan-local): add session-state fixtures
Two fixtures for session-state-validator (Step 4):
- valid-in-progress.json — well-formed schema-v1 object
- malformed.json — truncated JSON for negative tests

Step 3 of /ultracontinue v3.3.0.
2026-05-01 20:21:50 +02:00
Kjell Tore Guttormsen
5c2911253b refactor(ultraplan-local): extract atomicWriteJson to lib/util
Three changes in one commit:

1. NEW lib/util/atomic-write.mjs — exports atomicWriteJson(path, obj),
   the canonical tmp+rename pattern. Reused by pre-compact-flush.mjs and
   (in subsequent steps) by the new session-state writer.

2. NEW tests/lib/atomic-write.test.mjs — 4 unit tests covering
   round-trip, no-orphan-tmp, overwrite-atomic, pretty-print formatting.

3. REFACTOR hooks/scripts/pre-compact-flush.mjs — replace the inline
   atomicWrite() with the imported atomicWriteJson(). Also fixes a
   pre-existing syntax error (leading whitespace + stray --resume token
   outside the comment block) that silently broke the hook from v3.1.0
   onward — PreCompact runtime is fail-open and swallowed the error.
   File reformatted with standard zero-indent JS.

163 → 167 tests, 0 fail.

Step 2 of /ultracontinue v3.3.0 (project 2026-05-01-ultracontinue).
2026-05-01 20:21:15 +02:00
Kjell Tore Guttormsen
600bde6a41 test(ultraplan-local): add SC3(b) source_findings structural test
Synthetic plan.md fixture with source_findings: block-style YAML list of 3
40-char hex IDs in frontmatter, plus minimal plan structure (Title +
Implementation Plan + 1 Step + Manifest). 3 tests verify:

1. plan-validator accepts a plan with source_findings (additive optional field)
2. frontmatter parser extracts source_findings as array of strings
3. each ID matches the 40-char lowercase hex format from finding-id.mjs

Closes the SC3(b) gap flagged by adversarial review (scope-guardian Gap 2).
LLM-level behavior (planner emitting source_findings) remains non-testable
without live invocation; this covers the structural contract.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 17:23:30 +02:00
Kjell Tore Guttormsen
e5d376b00a test(ultraplan-local): add review determinism integration test
3 integration tests using the run-A/run-B fixtures:
- Jaccard(A, B) ≥ 0.70 (SC4 brief threshold)
- IDs match 40-char hex shape (lib/parsers/finding-id.mjs format)
- no duplicate IDs within a single run

Tests the Jaccard PIPELINE; real-LLM determinism deferred to v1.1.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 17:21:42 +02:00
Kjell Tore Guttormsen
68a0e5aa3b test(ultraplan-local): add synthetic ultrareview determinism fixtures
review-run-A.md (5 findings) and review-run-B.md (6 findings, A ⊂ B) form a
known-Jaccard fixture pair: |A ∩ B| = 5, |A ∪ B| = 6, Jaccard = 5/6 = 0.833,
above the SC4 threshold of 0.70. IDs are real 40-char SHA1s computed via
lib/parsers/finding-id.mjs from realistic (file, line, rule_key) triplets.

Both fixtures pass review-validator --strict (frontmatter + body sections +
findings shape). Real-LLM determinism measurement deferred to v1.1.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 17:21:02 +02:00
Kjell Tore Guttormsen
6a6da69cea test(ultraplan-local): extend doc-consistency with 4 ultrareview pins
Modify "all four pipeline commands" → "all five" (adds /ultrareview-local).
Add 3 new pins: Handover 6 section in HANDOVER-CONTRACTS.md,
review-validator CLI shim, rule-catalogue 12-key size invariant.

11/11 doc-consistency tests pass.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 17:18:51 +02:00
Kjell Tore Guttormsen
d5a76ee938 feat(ultraplan-local): extend project-discovery with review.md 2026-05-01 16:43:08 +02:00
Kjell Tore Guttormsen
cfa375a37b feat(ultraplan-local): add ultrareview to arg-parser FLAG_SCHEMA 2026-05-01 16:42:01 +02:00
Kjell Tore Guttormsen
7fee5b4490 feat(ultraplan-local): extend brief-validator to accept type:ultrareview 2026-05-01 13:31:39 +02:00
Kjell Tore Guttormsen
021f87f89a feat(ultraplan-local): add lib/validators/review-validator.mjs 2026-05-01 13:30:43 +02:00
Kjell Tore Guttormsen
7ce852cb71 feat(ultraplan-local): add lib/parsers/jaccard.mjs 2026-05-01 13:28:44 +02:00
Kjell Tore Guttormsen
f5dbeb1f8e feat(ultraplan-local): add lib/parsers/finding-id.mjs (stable SHA1) 2026-05-01 13:28:05 +02:00
Kjell Tore Guttormsen
07c2c89fc6 feat(ultraplan-local): add lib/review/rule-catalogue.mjs (12 rule keys) 2026-05-01 13:27:29 +02:00
Kjell Tore Guttormsen
b787213ba8 chore(release): ultraplan-local v3.1.0
Quality program release. Spor 0+1+2+3 all delivered.

- 109 zero-dep tests gate fork-readiness
- 5 validators wired into 4 commands as CLI shims
- HANDOVER-CONTRACTS.md: single source of truth for 5 pipeline handovers
- PreCompact-hook (P0) closes progress.json drift; --resume now works
- Semantic plan-critic catches paraphrased deferred decisions
- examples/01-add-verbose-flag/: hand-calibrated end-to-end pipeline demo
- 4 hooks total (pre-bash, pre-write, session-title, post-bash-stats, pre-compact-flush)
- SECURITY.md + Extending-the-plugin docs

CC v2.1.x feature adoption: F8 (MCP_CONNECTION_NONBLOCKING),
F9 (sessionTitle), F3 (duration_ms), F12 (disableSkillShellExecution).
F2 (hook 'if'-field) deferred — universal protection wins.

Pre-flight verification:
- npm test → 109 pass
- plan-validator --strict templates/plan-template.md → READY
- plan-validator --strict tests/fixtures/plan-fase-narrative.md → FAIL (expected)
- grep smallCodebase|mediumCodebase|largeCodebase → 0 hits

Version bumped: package.json, plugin.json, README badge, root README,
root CLAUDE.md.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-01 06:31:42 +02:00