Skip to content

Commit 0e45d92

Browse files
chore(openspec): reconcile and archive the second-brain change; guard the next cut (Q5)
0.2.0 shipped the whole second-brain layer while its change sat at 0/19 tasks, unarchived, with a proposal still selling the withdrawn Obsidian-CLI adapter — an agent following docs/contributing.md found no capability spec and instructions to build something three families cut. Ruling: archive- and-reconcile, never archive fiction (ARBITRATION Q5). Reconciled BEFORE archiving: proposal.md's What Changes and Risks now match design D4/D12 (adapter withdrawn; the four keys it used are refused with a naming error); tasks.md records what actually happened — shipped items ticked, the adapter and daily_note struck, the per-lane verifier items replaced by the P2 council that actually reviewed the merged diff, and the owner prompt run ticked against its filled checklist (run 2026-09-04, Kiro CLI 2.21.0). Then openspec archive second-brain, which wrote the second-brain capability spec into openspec/specs/ and applied the two deltas. ADR-0010 is now Accepted (it shipped), here and in the index. The guard, so this cannot recur: check-release-consistency.py gains a --release mode wired into release-check via the new release-consistency-shipped recipe (NOT preflight — open changes are legal during a cycle; only shipping one is not). It fails when any directory under openspec/changes/ (archive/ excluded) has commits since the last tag and is neither archived nor carrying an explicit 'deferred: <reason>' in its .openspec.yaml, and it validates archive entries added since the last tag with the openspec CLI (soft-skip when absent, same convention as spec-check; scoped to NEW archives because a July archive predating the guard has unticked tasks nobody has evidence to reconcile). The always-on ADR check fails any ADR present in the last tag that still says Proposed. Positive controls, per this campaign's trap #1: setting ADR-0010 back to Proposed turns the always-on check red (proving it would have fired on 0.2.0); restore turns it green. The shipped-changes guard's control run follows in the next verification step, since it needs a committed change.
1 parent ea67c9b commit 0e45d92

14 files changed

Lines changed: 476 additions & 99 deletions

File tree

docs/adr/0010-second-brains-are-projections.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# ADR-0010 — Second brains are projections; plan Markdown is the source of truth
22

3-
**Status:** Proposed, 2026-09-03. Motivated by change `openspec/changes/second-brain/`
3+
**Status:** Accepted, 2026-09-04 (proposed 2026-09-03; shipped as `v0.2.0`; clause 1
4+
amended 2026-09-04). Motivated by change `openspec/changes/archive/2026-09-04-second-brain/`
45
(R-84, 0.2.0). Contract: `docs/architecture/second-brain.md`.
56

67
## Context

docs/adr/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,4 @@ the code and ask "why on earth is it done this way?" — it gets an ADR, and
3939
| [0007](0007-dev-only-vendored-assets.md) | Dev-only vendored assets live in git, not in the wheel | Accepted | `vendor/dev/` |
4040
| [0008](0008-retire-ttyd-entirely.md) | Retire ttyd entirely; the Web UI owns interactive sessions | Accepted | ttyd retirement stages 2-7 |
4141
| [0009](0009-one-session-authority.md) | The session-state file is the claim; the in-process slot is a cache | Proposed | M2 session-authority remediation |
42-
| [0010](0010-second-brains-are-projections.md) | Second brains are projections; plan Markdown is the source of truth | Proposed | `second-brain` |
42+
| [0010](0010-second-brains-are-projections.md) | Second brains are projections; plan Markdown is the source of truth | Accepted | `second-brain` |

openspec/changes/second-brain/.openspec.yaml renamed to openspec/changes/archive/2026-09-04-second-brain/.openspec.yaml

File renamed without changes.
File renamed without changes.

openspec/changes/second-brain/proposal.md renamed to openspec/changes/archive/2026-09-04-second-brain/proposal.md

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,10 @@ Three constraints shape the answer:
2929
- **An Obsidian backend** writing projections into `<vault>/<folder>/`
3030
(`Study/Plans/<plan_id>.md`, `Study/Today.md`): atomic, idempotent, refusing
3131
any target outside the vault or lacking StudyLoop's `studyloop:` frontmatter
32-
marker. The official Obsidian CLI is an opt-in adapter that degrades to the
33-
file writer whenever the app is not answering.
32+
marker. Plain files and nothing else: an official-Obsidian-CLI adapter was
33+
built and withdrawn before release (design D4), and the four config keys it
34+
used (`use_cli`, `vault_name`, `template`, `daily_note`) are refused with an
35+
error naming them rather than silently ignored (design D12).
3436
- **A `studyloop brain` command group**`status`, `publish`, `pull`, `enable`,
3537
`template` — lazily registered, each with `--json`.
3638
- **A once-only wind-down offer**: the protocol offers a publish exactly once,
@@ -88,9 +90,10 @@ Three constraints shape the answer:
8890
- **Writes into a learner's real files.** Mitigated by the ownership marker, the
8991
vault-boundary refusal, atomic replace, and a test suite that cannot resolve
9092
the real vault at all.
91-
- **The Obsidian CLI grammar is unversioned.** Mitigated by keeping it an
92-
optional adapter behind a probe: a grammar change costs one file and degrades
93-
to plain files meanwhile.
93+
- **The Obsidian CLI grammar is unversioned.** Resolved by withdrawal: the
94+
opt-in adapter was built, reviewed and removed before release (design D4);
95+
plain files carry the whole feature, and its four config keys are refused
96+
with an error naming them.
9497
- **A learner edits a projection and loses the edit.** Accepted and documented:
9598
edits are replaced on the next publish with a warning, and personal notes
9699
belong in the sibling `.notes.md` file that StudyLoop only ever reads.

openspec/changes/second-brain/specs/cli-surface/spec.md renamed to openspec/changes/archive/2026-09-04-second-brain/specs/cli-surface/spec.md

File renamed without changes.

openspec/changes/second-brain/specs/configuration-and-secrets/spec.md renamed to openspec/changes/archive/2026-09-04-second-brain/specs/configuration-and-secrets/spec.md

File renamed without changes.

openspec/changes/second-brain/specs/second-brain/spec.md renamed to openspec/changes/archive/2026-09-04-second-brain/specs/second-brain/spec.md

File renamed without changes.
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# Implementation Tasks
2+
3+
Three lanes, each on its own branch and worktree, each with a disjoint file set
4+
enforced by `packages/studyloop/tests/fixtures/lane_ownership.yaml`. Lane **m7**
5+
(core) and lane **m9** (process artefacts) ran in parallel; lane **m8** (xTiles
6+
stage 1) started once both had merged into the integration branch.
7+
8+
Every item was red-first: a failing test on concrete data, then the code, then
9+
`env -u VIRTUAL_ENV just preflight` as the per-item gate, with docs and the
10+
changelog landing in the same commit as the behaviour they describe. Each item
11+
names the evidence subdirectory that holds its `00-dod.md`, `01-red.txt`,
12+
`02-green.txt`, `03-gate.txt` and `05-docs.diff`; the roots are
13+
`reviews/2026-09-03-second-brain/evidence/m7/`, `…/m9/` and `…/m8/`.
14+
15+
Reconciled 2026-09-04 before archiving, per the review ruling
16+
(`reviews/2026-09-04-second-brain-review/ARBITRATION.md` Q5): ticks record what
17+
shipped in 0.2.0, strikes record what was cut, and the per-lane verifier items
18+
are replaced by the review that actually happened.
19+
20+
## Lane m7 — core (`lane/m7-second-brain-core`)
21+
22+
- [x] **Foundation commit.** Repoint the lane-ownership guard's merge base to an
23+
ordered tuple of integration branches with an env override, map lanes
24+
m7/m8/m9, add the `live_obsidian` marker and deselect it by default in
25+
both `pyproject.toml` files, and add the vault-isolation fixture plus the
26+
session-finish hook that fails the run if the real vault changed.
27+
_Evidence: `00-foundation/`._
28+
- [x] **Protocol, config and the null path.** `SecondBrain` protocol with its
29+
exact-method guard, `SecondBrainConfig`, `NullBackend`, the xTiles
30+
stage-1 object, `brain status` and `brain publish --plan`, and the
31+
optionality tests (`sys.modules`, directory-tree snapshot, CLI output).
32+
_Evidence: `T1/`._
33+
- [x] **Heading constants.** Extract the plan-Markdown heading constants in
34+
`planning/markdown.py` so the projection renderer reads them instead of
35+
re-deriving the same strings a second time. _Evidence: `T3a/`._
36+
- [x] **Obsidian backend.** Plan and Today projections, the atomic
37+
vault-boundary writer with the ownership marker and content hash,
38+
backlinks behind a lazy import with a warn-once fallback, and due-card
39+
extraction shared with the review service. ~~The opt-in CLI adapter with
40+
its probe and fallback~~ — built, reviewed and **withdrawn before
41+
release** (design D4); its four config keys (`use_cli`, `vault_name`,
42+
`template`, `daily_note`) are refused with an error naming them (D12).
43+
_Evidence: `T2/`._
44+
- [x] **Templates as package data.** Ship the Obsidian templates under
45+
`studyloop/data/templates/obsidian/`, add the drift guard that keeps them
46+
in step with the renderer, assert they carry no ownership marker, and
47+
implement `brain template`. _Evidence: `T3/`._
48+
- [x] **Full command group and integration points.** The rest of the `brain`
49+
group (`pull`, `enable`), the `config init` follow-up, the doctor check,
50+
the once-only wind-down offer, and the regenerated agent manifest.
51+
~~`daily_note`~~ — cut with the adapter; never shipped. _Evidence: `T4/`._
52+
- [x] **Obsidian half of the guide.** `docs/second-brain.md`, the touched pages,
53+
the mkdocs entry, and the docs-drift guards that make a stale sentence a
54+
red test. _Evidence: `T6a/`._
55+
- [x] **Verification.** ~~Independent per-lane verifier in a clean worktree~~
56+
replaced by the P2 review council on the merged diff (SIGNOFF-P2): a
57+
four-family independent review of the shipped layer, arbitrated in
58+
`reviews/2026-09-04-second-brain-review/ARBITRATION.md`, with the static
59+
checks (no module-level provider import, no `Path.home()` in the package,
60+
vault untouched by the suite) carried by always-on tests instead of a
61+
one-off verifier.
62+
- [x] **Sign-off and merge** into the integration branch; shipped as `v0.2.0`.
63+
64+
## Lane m9 — process artefacts (`lane/m9-second-brain-spec`)
65+
66+
- [x] **ADR-0010.** Record that second brains are projections and that the plan
67+
Markdown is the source of truth, with the rejected alternatives
68+
(two-way sync, an xTiles client now, writing into `AgentMemory/`, an
69+
environment-variable provider override, a web-UI button), and add the
70+
index row in `docs/adr/README.md`. Clause 1 amended 2026-09-04 to the
71+
rule the code obeys (`studyloop plan …` is the plan's only writer).
72+
_Evidence: `T7/`._
73+
- [x] **Contract page.** `docs/architecture/second-brain.md`: the ten clauses
74+
with the check that proves each one, plus the `.gitignore` exception that
75+
makes the page trackable under the `docs/architecture/*` deny rule.
76+
_Evidence: `T7/`._
77+
- [x] **OpenSpec change.** This directory: proposal, design with the D1–D13
78+
decision table and the alternatives, the new `second-brain` capability
79+
spec, and the deltas to `configuration-and-secrets` and `cli-surface`.
80+
_Evidence: `T7/`._
81+
- [x] **Gates.** `just spec-check`, `just docs`, `just lint`, `just typecheck`,
82+
the lane-ownership guard on this branch, and the hygiene grep proving no
83+
absolute path, account name or commit hash reached a public file.
84+
_Evidence: `T7/`._
85+
- [x] **Sign-off and merge** into the integration branch — via the P2 council
86+
on the merged diff (SIGNOFF-P2), not a per-lane verifier.
87+
88+
## Lane m8 — xTiles stage 1 (`lane/m8-xtiles-stage1`)
89+
90+
- [x] **The shared wind-down skill.** One skill body, self-gated on
91+
`provider: xtiles` plus a connected `xtiles` MCP server, installed into
92+
every detected harness by `studyloop install agents`, with the harness
93+
wrappers, the agent-instruction paragraphs and a regenerated manifest.
94+
_Evidence: `T5/`._
95+
- [x] **xTiles half of the guide.** The provider section of
96+
`docs/second-brain.md`, the three prompts, and the sources rows.
97+
Reworded post-run per ARBITRATION Q2/N1–N4/N6 (planner tile not task;
98+
no board-view promise; skip the Review task when nothing is due).
99+
_Evidence: `T6b/`._
100+
- [x] **Owner prompt run.** Run 2026-09-04 by the owner in Kiro CLI 2.21.0
101+
against a real xTiles Plus account — not Claude Code, and the docs say
102+
so. P1/P1b and P3 wrote what they describe; P2 created the project but
103+
not the board or the visible page structure it promised. Filled
104+
checklist and redacted transcript:
105+
`reviews/2026-09-03-second-brain/evidence/m8/xtiles-prompts/`.
106+
- [x] **Verification.** ~~Preflight, docs-drift guards and hygiene grep rerun
107+
by an independent verifier~~ — replaced by the P2 council on the merged
108+
diff (SIGNOFF-P2).
109+
- [x] **Sign-off**, integration gate, review council, and owner merge and tag
110+
(`v0.2.0`, 2026-09-04).

openspec/changes/second-brain/tasks.md

Lines changed: 0 additions & 91 deletions
This file was deleted.

0 commit comments

Comments
 (0)