Fix/notify resolution hardening#112
Merged
Merged
Conversation
…verable webhooks Two real defects behind the "notify fails in worktrees" report (P0.8.5): - crypto.ResolveKeyPath auto-detected a project-local <contextDir>/.ctx.key and preferred it over the global key. That file is gitignored, so a fresh worktree resolved to a different key and decryption silently failed. Remove the tier: resolution is now key_path override > global, with project-local kept only as a degenerate fallback when no home dir exists (never auto-detected). Also a documented security antipattern (key next to ciphertext). - notify.Send swallowed every fire-path failure as a silent no-op. It now treats .notify.enc existence as the sole "configured" signal and warns (non-fatal) when a configured webhook cannot be delivered — bad/absent key, decrypt, marshal, or POST — while keeping legitimate silences (not configured, event not subscribed). LoadWebhook detects file absence via os.Stat + errors.Is, not os.IsNotExist, which does not unwrap the text-registry-wrapped error. Spec: specs/notify-resolution-hardening.md Signed-off-by: Jose Alekhinne <jose@ctx.ist>
`gitnexus analyze` injects a full "# GitNexus — Code Intelligence" block between <!-- gitnexus:start/end --> markers. It first landed in 6afb50d (a recall/core deletion commit) as an analyze side effect, not a deliberate choice, and has churned on every reindex since. The project already has a curated home for this: GITNEXUS.md, added deliberately in bf42b1f with a CLAUDE.md cross-reference. The injected blocks were pure duplication on top of it. Realign to the pre-injection canonical state: - AGENTS.md: back to the redirect-to-CLAUDE.md stub (its form since fda3c82) - CLAUDE.md: keep the Companion Tools pointer to GITNEXUS.md, drop the block Re-injection guard lives outside this repo: run analyze with --skip-agents-md so the global gitnexus hook stops rewriting these two files. Spec: specs/meta/chores.md Signed-off-by: Jose Alekhinne <jose@ctx.ist>
Follow-up to 8da165a: the marker-bounded removal of the GitNexus block from AGENTS.md/CLAUDE.md is mechanical, so capture a Phase CT task to automate it as `make strip-gitnexus`. Spec: specs/meta/chores.md Signed-off-by: Jose Alekhinne <jose@ctx.ist>
Deploying ctx with
|
| Latest commit: |
0961e50
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://ec004099.ctx-bhl.pages.dev |
| Branch Preview URL: | https://fix-notify-resolution-harden.ctx-bhl.pages.dev |
Land the ctx-dream design that has been in flight: a scheduled, standalone "dream" that only ever proposes (Option B), human-gated via serendipity, with v1 scoped to disciplined triage of the gitignored ideas/ folder. - specs/ctx-dream.md: the v1 spec, plus a sketched-not-contracted v2 section capturing the end-to-end pipeline (raw episodes -> evidence store -> dream pass -> typed durable artifacts), a cautionary-sibling comparison against the Hermes "Dreaming" design (un-gated autonomous promotion is the failure mode to avoid), the lifted attention-scoring rubric, and the quiet_minutes trigger gate. - .context/briefs/...-ctx-dream-disciplined-consolidator.md: the debated brief the spec consumes. - .context/TASKS.md: ctx-dream v1 task breakdown (guards, ledger/state, triage, review CLI + serendipity skill, executor, tests). Spec: specs/ctx-dream.md Signed-off-by: Jose Alekhinne <jose@ctx.ist>
Consolidation pass per the 3:1 discipline. LEARNINGS 157 -> 81 (18 merged entries) and DECISIONS 111 -> 56 (13 merged entries); every original is preserved verbatim under .context/archive/ and the indexes were rebuilt. No unique fact or rationale dropped — merges distill to bullets, originals are archived, not deleted. Includes the in-flight ctx-dream knowledge captured this cycle: the ctx-dream decision (kept standalone/legible) and the dream design principles (folded into a single "ctx-dream design principles" learning), so the dream knowledge rides with the consolidation that absorbed it. Also archives a handful of point-in-time/superseded entries (IMPLEMENTATION_PLAN refs, old key-migration specifics, Claude Code v2.1.69 internals, PR #27 merge-readiness, blog-first ordering). Spec: specs/consolidation-nudge-hook.md Signed-off-by: Jose Alekhinne <jose@ctx.ist>
… fields Claude Code >= 2.1.158 emits attributionMcpServer / attributionMcpTool (MCP invocation provenance) and >= 2.1.161 emits promptSource (prompt provenance). These were unknown to the importer, so `ctx journal import` and `ctx journal schema check` reported schema drift on every recent session — recurring noise that erodes the drift signal. Add the three fields to OptionalFields (versions read from the actual JSONL, not guessed) and pin all three in TestKnownField_PostV1FieldDrift so a future refactor can't silently drop them and reopen the drift. Spec: specs/fix-journal-schema-drift.md Signed-off-by: Jose Alekhinne <jose@ctx.ist>
…ased) ctx drift's checkSyncStaleness hardcodes cursor/cline/kiro and treats a missing synced output as stale, so a single-tool project (e.g. Claude only) is nagged to sync steering for editors it never uses — pure noise. Spec replaces the hardcoded trio with a presence-based set: a syncable tool is checked iff its native output already exists on disk. This serves both audiences with one mechanism — a multi-tool repo that tracks its outputs gets them enforced in every clone; a single-tool user who never synced sees nothing. Repo-side freshness moves to a wired sync-steering / check-steering make target. No new .ctxrc surface; the pre-existing unused steering.default_tools (a content-scoping concern) is left out of scope. Spec: specs/steering-sync-drift-respects-configured-tools.md Signed-off-by: Jose Alekhinne <jose@ctx.ist>
Generated by `ctx steering sync --all` from .context/steering/. This repo's dev team is multi-tool, so committing these outputs means a fresh clone has them present and the presence-based drift check enforces their freshness across all three tools (see the steering-sync-drift spec). Repo policy, not a feature requirement. Spec: specs/steering-sync-drift-respects-configured-tools.md Signed-off-by: Jose Alekhinne <jose@ctx.ist>
…steering Implements specs/steering-sync-drift-respects-configured-tools.md. checkSyncStaleness no longer hardcodes cursor/cline/kiro and no longer treats a missing output as stale — so a single-tool project (e.g. Claude-only) is no longer nagged to sync steering for editors it never uses. A syncable tool is now checked iff it is "in play": at least one of its native outputs already exists on disk. - internal/steering: add SyncableTools() (the cursor/cline/kiro set) and Synced(steeringDir, projectRoot, tool) (file-level presence via SafeStat, skipping tombstoned/excluded files). - internal/drift: checkSyncStaleness iterates SyncableTools() and skips any tool that is not Synced(). - Makefile: standalone `sync-steering` + `check-steering` (the latter wired into `audit`, run by `check`), both via `go run`. sync-steering is intentionally not a build prereq — steering outputs are repo-root artifacts, not embedded assets, so they must not be regenerated on every build. - Tests: Synced/SyncableTools units; drift cases for "unsynced tools not checked" (the headline fix) and "only synced tools checked". - Spec: corrected the build-wiring section to match (check in audit, sync standalone). Spec: specs/steering-sync-drift-respects-configured-tools.md Signed-off-by: Jose Alekhinne <jose@ctx.ist>
…r contract Resolve the ctx-dream v1 open questions ahead of implementation: - Executor is a documented contract, not a hardcoded assumption. cron `claude -p` is the reference executor (guards as PreToolUse hooks for free), but ctx owns an executor-agnostic Go core (dreams/ layout, state, ledger, proposal schema, guards as callable logic) so other harnesses can run the same dream. New Executor-contract section + decision record. - Dream is opt-in (not enabled by default); a `dream:` .ctxrc section gates it. Two user-facing docs required: a Claude Code enablement guide and an executor-contract reference for other harnesses (added to TASKS). - Serendipity review split into its own spec (specs/ctx-serendipity.md): the human garden-walk gate, accept/reject/amend, mechanical-vs- generative dispositions, ctx remind cadence, routing to archive / /ctx-spec / /ctx-blog. - Settled: merit defaults via the attention-scoring rubric (ranking only, never an auto-promote threshold); summary reuses the session model; Go package layout follows convention; proposals/ledger carry stable IDs so v2 supersession isn't foreclosed. Records the executor-contract architectural decision in DECISIONS.md. Spec: specs/ctx-dream.md Signed-off-by: Jose Alekhinne <jose@ctx.ist>
…ledger
The contracted Go core of ctx-dream (specs/ctx-dream.md), with no CLI,
skill, or executor yet — the safety substrate landed first, fully tested.
- internal/config/dream: proposal status/action enums, confidence,
source-status, ledger decision, notebook file names + validation
reason templates (config-housed, no magic strings).
- internal/dream: the data contract (Proposal, SourceState, LedgerEntry,
GuardDecision) plus the engine —
- guards: WriteScope (writes only under dreams//ideas/, or specs/ on
promote) and Leak (target must be git-ignored, except the promote
crossing) — executor-agnostic, so a Claude Code PreToolUse hook and a
raw-API tool executor enforce the same invariant.
- state: hash-based delta selection (the discipline clock) + JSON
persistence at dreams/state.json.
- ledger: append-only dreams/ledger.md + dedup-against-seen.
- validation referencing every enum value (the dead-export-safe fix).
- internal/err/dream + config/embed/text/err_dream.go + errors.yaml: the
error/text-registry ceremony for the above.
- internal/exec/git + config/git: CheckIgnore helper (maps git
check-ignore exit 0/1 to a bool, surfaces only real failures) — the
don't-leak primitive.
- config/dir: Dreams, Done directory constants.
Tests cover the guard allow/deny matrix (incl. tracked-path leak refusal
and the specs-promote crossing), state round-trip + delta selection, and
ledger append/readback + dedup.
Spec: specs/ctx-dream.md
Signed-off-by: Jose Alekhinne <jose@ctx.ist>
…ions The runnable Go surface on top of the v1 foundation (specs/ctx-dream.md). - internal/cli/dream: `ctx dream` (run a bounded pass) + review / accept / reject / amend subcommands, registered in the sessions command group. The pass resolves the root, ensures the gitignored dreams/ dir, runs the opt-in trigger gate (enabled + cadence + quiet-window, bypassable with --force), DeltaSelects ideas/**.md, takes an exclusive lock, invokes the configured executor (default `claude -p` with the ctx-dream skill + --max-turns/--model), FAILS LOUD with a failmark on a missing or failed executor, then validates proposals and persists state. - internal/dream: the disposition appliers — scan/delta, proposal read+pending (dedup-against-seen), and accept/reject/amend/backup. Every ideas/ mutation passes BOTH guards before any write; mechanical actions (archive→ideas/done/, mark-blog, keep) run in Go, generative ones (promote/merge) record intent and route to /ctx-serendipity. - internal/write/dream: all user-facing output. internal/exec/dream: executor lookup/run (keeps exec.* in internal/exec). internal/io: SafeTryLock/SafeUnlock (portable O_EXCL lock). - internal/rc: the `dream:` .ctxrc section (enabled/mode/max/cadence/ quiet_minutes/model/budget/executor) + schema; bootstrap registration; config/text/flag registry entries. Proposal on-disk contract: a single JSON array at dreams/<ts>/proposals.json. Spec: specs/ctx-dream.md Signed-off-by: Jose Alekhinne <jose@ctx.ist>
…tignore The harness wiring + cognition that makes v1 runnable, plus the human gate. - internal/assets/claude/skills/ctx-dream: the disciplined ideas/-triage skill (classify + ground against code/specs, emit provenance-bearing proposals into dreams/<ts>/proposals.json) — scoped to the spec's v1, not the broader draft. Bundles guard.sh, the PreToolUse hook that restricts a headless pass to writing under dreams/ (mirrors the Go WriteScope/Leak guards for the Claude Code executor path). - internal/assets/claude/skills/ctx-serendipity: the garden-walk review skill — drives ctx dream review/accept/reject/amend; mechanical dispositions apply instantly, generative (merge/promote) are done from the full source with backup-before-mutate (specs/ctx-serendipity.md). - docs/recipes/run-the-dream.md: opt-in enablement guide for Claude Code users (.ctxrc dream.enabled, cron entry, guard-hook settings, review). - docs/reference/dream-executor-contract.md: the contract for non-Claude- Code harnesses (bounded pass, structural guard enforcement, fail-loud, proposals-only-into-dreams/). - .gitignore: dreams/ (inherits ideas/'s privacy class; the don't-leak guard double-checks at write time). - TASKS.md: mark the completed ctx-dream v1 items. Spec: specs/ctx-dream.md Signed-off-by: Jose Alekhinne <jose@ctx.ist>
…d site Close the user-facing surface for ctx-dream per the CONVENTIONS "User-Facing Surface Completeness" checklist: - docs/cli/dream.md: per-command reference (the pass + review/accept/ reject/amend, flags, examples), linking the run-the-dream recipe and the executor-contract reference. - docs/cli/index.md: a `ctx dream` row in the Sessions table and the `dream:` block in the .ctxrc reference. - examples.yaml: example blocks for dream and its four subcommands (the desc.Example keys existed but had no entries, so --help showed none). - site/: `zensical build` rebuild so the published site includes the new dream CLI page, recipe, and executor-contract reference (built output is tracked; bundled with the docs change per convention). Recipe (docs/recipes/run-the-dream.md) and the executor-contract reference shipped with the feature commits. A Copilot-CLI skill mirror is intentionally not added: the sync maintains a curated subset and v1's reference executor is Claude Code (deferrable follow-up). Spec: specs/ctx-dream.md
…tifact tests Close the last ctx-dream v1 test task and harden the schema gate it exercises. - ProposalValid now also rejects a proposal with no target or empty evidence, not just unknown enums — enforcing the spec's "no evidence is not surfaced" provenance rule. New config reason/labels (FieldEvidence, FieldTargets, ReasonMissing). - TestCrashResume: a pass that crashes mid-way persists state only for completed sources; the next run reloads that committed state intact (atomic write — no torn file) and the discipline clock re-selects exactly the unprocessed + changed sources, skipping unchanged ones. - Corrupted-artifact regression corpus (testdata/corrupted-2605.12978.json, modeled on the arXiv 2605.12978 appendix): a well-formed proposal among corrupted ones (unknown status, stripped evidence, dropped target). TestCorruptedArtifactGate asserts only the provenance-bearing one survives; MalformedJSON asserts a structurally corrupt file errors (no panic / silent empty); Dedup asserts an already-decided artifact does not re-surface. Spec: specs/ctx-dream.md Signed-off-by: Jose Alekhinne <jose@ctx.ist>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A large, multi-concern bundle that accumulated on this branch. The
headline is ctx-dream v1 — a scheduled, opt-in "dream" that triages
the gitignored
ideas/folder into gated, human-reviewed proposals — andit ships alongside several independent hardening/hygiene changes that were
done in the same session.
main...HEAD: 315 files, +21,122 / −6,325 (inflated by the trackedsite/rebuild, the Copilot-skill mirror, and archived consolidationoriginals — see notes).
What's in this PR
🌙 ctx-dream v1 — sleep-time memory triage (headline)
A standalone, scheduled "dream" that only ever proposes (Option B):
it reads
ideas/, classifies each idea against the codebase and specs,and emits provenance-bearing disposition proposals (archive / merge /
promote / mark-blog / keep) into a gitignored
dreams/notebook. A humanreviews them in a ~15-minute "garden walk" (
/ctx-serendipity) andaccepts / rejects / amends. It never writes canonical memory and
never acts on a proposal without the human.
internal/dream): proposal/state/ledgertypes; the two structural guards (write-scope, don't-leak via
git check-ignore); hash-based delta selection (the "discipline clock");JSON state + append-only ledger with dedup-against-seen.
internal/cli/dream):ctx dream(gated, locked, fail-loudpass that invokes the executor) +
review/accept/reject/amend. Mechanical dispositions apply in Go with both guards on everyideas/write; generative ones (promote/merge) defer to the agentfrom the full source, backup-before-mutate.
ctx-dream(cognition) with a PreToolUseguard.sh, andctx-serendipity(the review gate).dream:.ctxrcsection gates it;nothing runs until
dream.enabled: true.claude -pis the reference, but any harness can implement the same bounded,
structurally-guarded, fail-loud pass (see
docs/reference/dream-executor-contract.md).specs/ctx-dream.md,specs/ctx-serendipity.md. Docs:docs/recipes/run-the-dream.md, the executor-contract reference, anddocs/cli/dream.md.🧭 Steering sync drift respects configured tools
ctx driftno longer hardcodes cursor/cline/kiro and no longer treats amissing synced output as stale — a single-tool project (e.g. Claude-only)
is no longer nagged to sync steering for editors it never uses. The check
is now presence-based (a tool is checked iff its native output
exists), with
make sync-steering/check-steeringfor repo-sidefreshness. Spec:
specs/steering-sync-drift-respects-configured-tools.md.🩹 Journal schema drift fix
Recognize Claude Code ≥ 2.1.158
attributionMcpServer/attributionMcpTooland ≥ 2.1.161promptSourceJSONL fields, soctx journal import/schema checkstop reporting drift on recentsessions. Pinned by a regression test.
🧹 Memory consolidation
Consolidated
LEARNINGS.md(157 → 81) andDECISIONS.md(111 → 56) intodenser entries; every original preserved verbatim under
.context/archive/.🔒 Notify resolution hardening (original branch purpose)
Dropped the project-local
.ctx.keyresolution tier and surfacedundeliverable webhooks.
📄 GitNexus block stripping
Stripped auto-injected GitNexus blocks from
AGENTS.md/CLAUDE.md.Testing
golangci-lint: 0issues; gofmt clean.
refusal and the specs-promote crossing), state round-trip + delta
selection, ledger append/dedup, disposition appliers, crash-resume
(atomic state survives a mid-pass crash; the delta resumes the rest),
and a corrupted-artifact regression corpus (after arXiv 2605.12978)
asserting the schema/dedup gate rejects faulty artifacts.
Enabling it (after merge)
sudo make install, then followdocs/recipes/run-the-dream.md:set
dream.enabled: true, add the cron entry and guard-hook settings,and review with
/ctx-serendipity.Notes / out of scope
one branch in a single working session. Happy to split if reviewing as
one PR is unwieldy.
ctx-dream/ctx-serendipityisintentionally deferred (the sync maintains a curated subset; v1's
reference executor is Claude Code).
consolidation pipeline are sketched-not-contracted in the spec and
out of scope for v1.
All commits are signed off (DCO).