Skip to content

feat(denkraum): split ideas and question import onto the store (DR-04c-2) - #674

Merged
mergify[bot] merged 3 commits into
mainfrom
claude/dr-04c2-denkraum-ideas-questions
Oct 8, 2026
Merged

mergify[bot] merged 3 commits into
mainfrom
claude/dr-04c2-denkraum-ideas-questions

Conversation

@Cuarroc

@Cuarroc Cuarroc commented Oct 8, 2026 •

Copy link
Copy Markdown
Owner

Der Denkraum kann jetzt auf dem neuen Speicherkern auch Ideen (mit Kategorie und Priorität) und importierte Fragen speichern, genauso wie im bisherigen Stand P1.
Damit sind alle Speicher-Operationen aus P1 übernommen und über eine einzige Datei store.mjs erreichbar, auf der Server und Befehlszeile (DR-06) aufbauen.
Server, Befehlszeile und Oberfläche folgen in eigenen Paketen; zwei Fremdprüfungen und Roots Abnahme stehen noch aus.

Report

Package: DR-04c-2 (Z1), parent ticket 55ea21ce. It is the second half of the DR-04c split announced in #671, under Root decision 14:00Z (Option A, msg-0muzlobgi). Owner: DR-03/04 session (Claude claude-opus-5-5[1m]).

What changed (3 new files, 152 ALL)

  • tools/denkraum/store/ledger.mjs (68): class LedgerStore extends ProgressStore with putIdea and putQuestion, moved from P1 592b309d lines 348–382 and 392–415.
    • diff of those P1 lines against ledger.mjs lines 9–67 shows exactly 2 hunks, both this.#change( → this.change(.
    • Neither operation uses the root agent id. The P1 migrate in between (383–391) is already the DR-03 core's migrate.
  • tools/denkraum/store.mjs (2): re-export of the P1 public surface. From store/model.mjs: DeskError, latestAnswer, projectQuestionPriority, compareQuestions, migrateState. DeskStore = LedgerStore. This is the proof's 2-line store.mjs with the class name of this chain. The root id stays injected with no default (D2), so P1 callers that relied on the hardcoded constant must pass rootAgentId.
  • tools/denkraum/store/ledger.test.mjs (82): 5 tests, synthetic ids only.
    • Ideas: revision 1 → incoming progress, a pending outbox entry, an inbox entry and a delivered event with contentRevision. Category is trimmed. Priority is kept. Unchanged metadata carries over to revision 2 and can be reset in revision 3.
    • Idea refusals: replay vs conflicting reuse 409; stale 409; unknown 404; category 81 chars / non-string 400 (80 ok); unknown priority 400; expectedRevision without id 400; empty title 400. Nothing is written. V1 ledger 409.
    • Questions: create; update only with the current expectedRevision (missing or stale 409; for a new id 409); createdAt is kept. An import with requestId replays its result, and conflicting reuse gives 409 with no write. An invalid question gives 400.
    • Questions bound to an idea: the current idea revision is required (unknown 404, outdated 409).
    • Surface: the store.mjs export names equal the P1 export names, DeskStore === LedgerStore, and every P1 operation is on that class.

Evidence

Step Command / site Result
RED on base e35500c server worktree 14:07:00Z, test file only, node --test --test-name-pattern='an idea revision starts incoming progress|store.mjs exposes the P1 surface' tools/denkraum/store/ledger.test.mjs Node exit 1, ERR_MODULE_NOT_FOUND for ledger.mjs (new module); log sha256 e83f5f50bc1f8217…
GREEN local node --test tools/denkraum/store/ledger.test.mjs; npm run test:denkraum (Windows) exit 0, 5/5; exit 0, 61/61, hygiene 19 files 0 findings
D1 split = P1 behaviour (scratch, not committed) frozen P1 siblings (unchanged store, progress, patches, priority, question-import, free-answer, sender, api, server tests) + P1 ideas.test.mjs + this chain's model/core/answers/delivery/progress/ledger. The shim store.mjs is now 4 lines: DeskStore extends LedgerStore, only injecting the root id, no P1 code left. Run: node --test --test-concurrency=1 *.test.mjs exit 0, 101/101
Commit + hooks server, CARGO_TARGET_DIR=~/targets/slot5, CARGO_BUILD_JOBS=2, foreground ssh_exec 83ca797 precommit exit 0 (14:07:56–14:08:10Z)
prepush server bash scripts/ci/gates.sh lane prepush on 83ca797 exit 0, 14:08:27–14:09:57Z, 22 gates gruen, rust-suite nextest 1873 run / 1873 passed / 7 skipped; log sha256 784e723272e468af…
red-first server bash scripts/ci/red-first.sh exit 0; both new trailers red/absent at merge base 7e3a7af, green at the head
push git push + git ls-remote 14:10:19Z PA_PREPUSH=light git push -u after the full prepush on the same head, exit 0; git ls-remote 14:11:03Z = 83ca797c0002d820d0ad704365cc455f9701e0b7; #671 branch unchanged at e35500c
R669-O1 merge-forward server git merge --no-ff of d45d610 (#671), no rebase (Root order) merge d17c1a6 brings only delivery.mjs/delivery.test.mjs (+18/−3), no conflict, no change of this package's files; trailer No-Test (fix is red-first tested in dc34cae). prepush exit 0 14:33:27–14:35:01Z, nextest 1873 / 1873 passed / 7 skipped, log sha256 592e59e50b862cad…; red-first exit 0; git ls-remote 14:36:18Z = d17c1a6c08e307dbbbcd4d9fc8d273f56cb7190c. D1 composition rerun with the fixed delivery.mjs: 101/101
R671-O1 merge-forward server git merge --no-ff of 5d31ef5 (#671), no rebase merge 39bc839 brings only progress.mjs/progress.test.mjs (+16/−3), no conflict, trailer No-Test. prepush exit 0 14:48:37–14:50:06Z, nextest 1873 / 1873 passed / 7 skipped, log sha256 bc00ae050790cb24…; red-first exit 0; git ls-remote 14:51:09Z = 39bc8390f87e9e5dc0d490bf1e97ac138bdb2fcc. D1 composition with the fixed progress.mjs: 101/101

Limits (unchanged, not solved here)

  • The ponytail: comment in putIdea is copied from P1 unchanged. Request replay scans the whole history, part of the open F-01 bounds question.
  • Serialization per store instance only (R661-02). F-01 open.

Review

Tier A. OpenAI R1 on 83ca797: approve, no finding.
At head 39bc839:

  • OpenAI delta (gpt-6-astra, review-drdelta-openai-r2): an independent probe confirmed rootless local saves and replays, no receipts and no notifications; verdict approve.
  • Google R1 (Gemini 3.1 Pro, review-dr-google-r1-671-674-676): approve.

The inherited R669-O1 remainder goes to follow-up DR-04B-FU (PLAN, merged in #695). Root acceptance: 2026-10-08 19:24Z.

ID Source Severity Finding Disposition
R671-O1 sibling check Root (same class as R669-O1/R671-O1) – Does putIdea or putQuestion answer with success without a root id (replay or empty path)? No defect. Both never read receipts or attest the root; they are local saves as in P1, and the automatic delivery of a saved idea fails closed in the store (R669-O1). No code change in this package, so no red test; the R669-O1 and R671-O1 fixes arrive by merge.

NICHT ABGEDECKT

  • The frozen P1 test files are not in the repo yet (DR-07). They still need rootAgentId passed, because the P1 constant is gone (D2). The 101/101 holds only with the scratch shim.
  • No HTTP/CLI (DR-06a/06b), no ENV default for the root id, no UI, no usability claim. F-01 and R661-02 stay open in the DR-03 parent acceptance.
  • Gate block of this run: Linux half only. The #[cfg(windows)] tests (run_in_pty, npm_shim, ConPTY, DPAPI) and the Windows arms of clippy are not covered. Browser smoke, frontend build and workflow gates run only in lane linux. External services are not checked by any gate. The Windows verdict comes from the merge queue.

🤖 Generated with Claude Code

…c-2)

Move putIdea and putQuestion from the frozen P1 DeskStore (lines
348-382 and 392-415) into tools/denkraum/store/ledger.mjs as LedgerStore
extends ProgressStore. The only change is this.#change( to this.change(;
neither operation uses the root agent id.

tools/denkraum/store.mjs re-exports the P1 surface (DeskError,
latestAnswer, projectQuestionPriority, compareQuestions, migrateState and
DeskStore = LedgerStore), so the server and CLI in DR-06 can import one
store with every operation. The root agent id stays injected (D2).

Test-First: tools/denkraum/store/ledger.test.mjs::an idea revision starts incoming progress and a pending outbox entry and keeps its metadata
Test-First: tools/denkraum/store/ledger.test.mjs::store.mjs exposes the P1 surface with every operation on one store

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Brings dc34cae (V2 pending, inbox and delivery require the root id even
on an empty ledger) up the DR-04/DR-06 stack. Merge, no rebase, as
ordered by Root; no conflict, no code change of this package.

No-Test: merge commit only; the fix is red-first tested in dc34cae (delivery.test.mjs R669-O1)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Brings 5d31ef5 (progress and patch replays check the root id first) up
the DR-04/DR-06 stack. Merge, no rebase, as ordered by Root; no
conflict, no code change of this package.

No-Test: merge commit only; the fix is red-first tested in 5d31ef5 (progress.test.mjs R671-O1)

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Base automatically changed from claude/dr-04c1-denkraum-progress to main October 8, 2026 17:43
@Cuarroc
Cuarroc marked this pull request as ready for review October 8, 2026 19:23
@Cuarroc Cuarroc added the review-ok Pipeline: review disposition complete, no open high finding label Oct 8, 2026
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-08T19:32:16.233413Z 39bc839 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@mergify mergify Bot mentioned this pull request Oct 8, 2026
30 of 46 tasks

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 39bc8390f8

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

ensure(old || input.expectedRevision === undefined, 'Frage fehlt für diese Revision. Erst neu laden.', 409);
ensure(!old || input.expectedRevision === old.revision, 'Frage wurde inzwischen geändert. Erst neu laden.', 409);
if (old?.recommendationDetail && q.sourceRef && !sameRef(old.sourceRef, q.sourceRef) && q.recommendationDetail === undefined) q.recommendationDetail = undefined;
const next = { ...old, ...q, revision: (old?.revision ?? 0) + 1, createdAt: old?.createdAt ?? now(), updatedAt: now() };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Reuse one timestamp when creating a question

When the system clock advances between these consecutive now() calls, a newly created question receives different createdAt and updatedAt values, while the new regression test explicitly requires them to be equal (ledger.test.mjs:55). This makes the test timing-dependent and can represent a brand-new record as already updated; capture one timestamp and use it for both fields on creation.

Useful? React with 👍 / 👎.

}
ensure(old || input.expectedRevision === undefined, 'Frage fehlt für diese Revision. Erst neu laden.', 409);
ensure(!old || input.expectedRevision === old.revision, 'Frage wurde inzwischen geändert. Erst neu laden.', 409);
if (old?.recommendationDetail && q.sourceRef && !sameRef(old.sourceRef, q.sourceRef) && q.recommendationDetail === undefined) q.recommendationDetail = undefined;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Remove cleared recommendation details before returning

When an imported update changes sourceRef on a question that already has recommendationDetail and omits replacement details, this assignment creates an own recommendationDetail: undefined property in next. The initial putQuestion result therefore has that property, but JSON persistence drops it and a requestId replay returns an object without it, so direct-store callers receive a structurally different replay result; remove the property rather than assigning undefined, or normalize the result before returning it.

Useful? React with 👍 / 👎.

const index = state.questions.findIndex(x => x.id === q.id); const old = state.questions[index];
requireCurrentSource(state, { ...old, ...q });
const detail = q.priorityDetail ?? old?.priorityDetail;
if (detail?.sourceRefs.length) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Handle omitted legacy priority source lists

When an existing question has a legacy priorityDetail without sourceRefs, which is accepted because validateQuestion defaults omitted reference lists to [] (model.mjs:157-170), an update that omits replacement priority details selects that raw stored object and this .length access throws an untyped TypeError. Consequently, an otherwise valid legacy ledger cannot update the question and an HTTP caller would receive an internal error instead of a DeskError; normalize the inherited detail or treat a missing sourceRefs as an empty list.

Useful? React with 👍 / 👎.

@mergify mergify Bot added the queued label Oct 8, 2026
@mergify
mergify Bot merged commit 6e6a84a into main Oct 8, 2026
8 checks passed
@mergify
mergify Bot deleted the claude/dr-04c2-denkraum-ideas-questions branch October 8, 2026 19:45
@mergify

mergify Bot commented Oct 8, 2026

Copy link
Copy Markdown
Contributor

Merge Queue Status

  • ✅ Entered queue — 2026-10-08 19:31 UTC · Rule: default · triggered by merge protections
  • ✅ Checks passed · on draft merge queue: checking #674 on main (32d70a7) #710
  • ✅ Merged — 2026-10-08 19:46 UTC · at 6e6a84acfecca521dacba3ab0723ea48239bdba1 · merge

This pull request spent 14 minutes 14 seconds in the queue, including 13 minutes 56 seconds running CI.

Required conditions to merge
  • check-success = gates (linux)
  • check-success = gates (windows)
  • check-success = red-first
  • github-review-approved [🛡 GitHub repository ruleset rule main-pr-required-checks]
  • label != do-not-merge
  • any of [🛡 GitHub repository ruleset rule main-pr-required-checks]:
    • check-success = @github-actions/gates (linux)
    • check-neutral = @github-actions/gates (linux)
    • check-skipped = @github-actions/gates (linux)
  • any of [🛡 GitHub repository ruleset rule main-pr-required-checks]:
    • check-success = @github-actions/gates (windows)
    • check-neutral = @github-actions/gates (windows)
    • check-skipped = @github-actions/gates (windows)
  • any of [🛡 GitHub repository ruleset rule main-pr-required-checks]:
    • check-success = @github-actions/red-first
    • check-neutral = @github-actions/red-first
    • check-skipped = @github-actions/red-first
  • any of [🛡 GitHub repository ruleset rule main-pr-required-checks]:
    • check-neutral = @mergify/Mergify Merge Protections
    • check-skipped = @mergify/Mergify Merge Protections
    • check-success = @mergify/Mergify Merge Protections

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

review-ok Pipeline: review disposition complete, no open high finding

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant