Repository navigation
impl(dashboard): slice 3 — pluggable pages, DNS register, comments, session registry (#906) - #920
Conversation
…registry, comments store, page manifest - model: DnsEntry/DnsSection, DashComment/DashAuthor, SessionRecord; Provenance gains dns + registry facets - dns.ts: parse #902's register Markdown into renewal-sorted entries with active/earmarked/unused classification from the plan cell - registry.ts: session records from feed entries + Muse launch records, cumulative-token merge, comment author identities - comments.ts: file-backed dashboard comment store keyed by object ref, with validation and the orchestrator consumption contract - pages.ts: the page manifest (nav + dropdown render from it) - collector: embeds the DNS section (parsed from the register file) and registry records (sandbox OpenCode + Jules + Muse launches) - scripts/record-claude-launch.ts: the launch-record append helper
… API - nav and the page dropdown render from the src/pages.ts manifest; /pages lists the manifest itself - /dns renders #902's register: next renewal, renewing-soon spend, in-use / unused-but-earmarked / completely-unused views, full table - /sessions renders the identity registry grouped by source, with parent links and token totals; item pages list linked sessions - dashboard comments: threads keyed by object ref with unambiguous authorship (drew / muse / agent identities), two kinds visibly distinct (note vs message-to-Muse) plus post-as-GitHub-comment with an explicit target; 💬 badges on board/roadmap/session/tier cards; /discuss/<ref> for any object - API: /api/dns.json, /api/registry.json, GET+POST /api/comments.json, POST /api/comments, /api/comments/triage, /api/comments/github-result
- opencode-tools/session-identity.ts: a session reports its own
{ sessionId, parentId, agent, directory }; install.sh ships it
- test/slice3.test.ts: DNS parser + classification, registry
normalization/merge, comment store lifecycle + validation, page
manifest, slice-3 renders, the identity tool, and full HTTP flows
(82 tests total, all passing; tsc clean)
- README: views, pluggable-page recipe, comments + orchestrator
consumption contract, registry, env vars, layout
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 53 minutes. View limit details
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 9e74d953cb
ℹ️ 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".
| const tmp = `${this.file}.tmp-${process.pid}`; | ||
| await writeFile(tmp, JSON.stringify(data, null, 2)); | ||
| await rename(tmp, this.file); |
There was a problem hiding this comment.
Serialize comment-store persistence
When comment submissions or triage updates overlap, every persist() call writes to the same process-wide temporary path. One call can rename that file while another is still using it, causing the latter to fail with ENOENT even though its mutation is already visible in memory. Reproducing with 20 concurrent add() calls after loading the store produced 19 rejected operations; the HTTP handler reports these as failed submissions, encouraging duplicate retries. Serialize persistence so each acknowledged mutation is durably written without competing over the temporary file.
Useful? React with 👍 / 👎.
| async load(): Promise<void> { | ||
| if (this.loaded) return; | ||
| this.loaded = true; | ||
| try { | ||
| const parsed: unknown = JSON.parse(await readFile(this.file, "utf8")); |
There was a problem hiding this comment.
Await initialization before allowing concurrent store access
If a second request accesses the store while its first disk read is pending, loaded is already true, so that request proceeds against the empty array. An add() can then succeed before the original load replaces this.comments, removing the acknowledged comment from memory and allowing the next write to erase it from disk. With an existing empty store, concurrently calling all() and add() reproduced this loss; adding a second comment left only the second comment persisted. Cache and await the initialization promise so every caller waits for the same completed load.
Useful? React with 👍 / 👎.
| let list: DashComment[] = await commentsStore.all(); | ||
| if (object) list = list.filter((c) => c.objectRef === object); | ||
| if (kind) list = list.filter((c) => c.kind === kind); | ||
| if (state === "new") list = list.filter((c) => c.triageState === "new" || c.githubState === "pending"); |
There was a problem hiding this comment.
Keep failed GitHub posts available to the retry consumer
After a poster reports a transient failure through /api/comments/github-result, markGithubResult() changes the comment's state to failed, but this filter excludes it from the documented ?kind=github&state=new polling queue in README.md and the pending count. There is no endpoint that resets failed records to pending, so a poster following that consumption contract never receives the comment again, despite dashCommentHtml() telling the user that a fleet poster will retry. Keep failed, unposted comments available to the consumer or provide an explicit retry/reset flow.
Useful? React with 👍 / 👎.
Implements #906 in three workstreams, building on the slice-2 seam (data-driven nav, flat route chain, page + /api/*.json twin).
§1 Pluggable pages — DNS register first
src/pages.tsmanifest (PAGES): nav bar, the new Pages ▾ dropdown, and/pagesall render from it. Adding a page = manifest entry + render function + route branch (+ JSON twin). Recipe in the README./dns+/api/dns.json: the register (impl(dns-registry): recurring DNS backup job, renewal/cost tracking, dashboard view of the domain register #902's file) is parsed collector-side (src/dns.ts, keyed on the register's table header) into adnsfleet-feed section — no new sync path. Views: next renewal, renewing-soon (45d) spend, in-use / unused-but-earmarked / completely-unused (status read from the register's own Plan cell — matches its 3 / 18 / 19 split of 40), full table.§2 Comments on dashboard items
src/comments.ts— aggregator-local JSON file (atomic writes), keyed by object ref so threads survive republishes:gh:<owner/repo#N>,orch:<tierItem.id>,session:<id>, board ids, roadmap subjects.drew/muse/ agent identities from the registry; the API refuses authorless comments.triageState), post as GitHub comment (explicitgithubReftarget required at post time;githubStatepending → posted/failed with the resulting URL recorded).gh:refs),/discuss/<ref>for any object, 💬 count badges on board / roadmap / session / tier cards.GET /api/comments.json(object/kind/state filters + pending counts),POST /api/comments,POST /api/comments/triage,POST /api/comments/github-result.?kind=message&state=newand?kind=github&state=new, triages into its normal flow (post + report github-kind), then marks consumed via the triage endpoint. Notes are read on pickup, never polled.§3 Agent/session identity registry
src/registry.tsnormalizes all sources into durable records (file store, max-token merge): OpenCode laptop (live) + sandbox (feed, with per-session tokens read off the server), Jules (keeper state), Muse (launch records).scripts/record-claude-launch.tsappends a JSONL record at spawn; the collector carries it. Unrecorded Muse sessions stay invisible — the coverage note says which sources are wired, honestly./sessions+/api/registry.jsonrender the registry.opencode-tools/session-identity.ts: a session reports its own{ sessionId, parentId, agent, directory }; shipped by install.sh, installed on both hosts.Verification
tscclean, biome/prettier formatted.Refs #906. The DNS data pipeline itself stays with #902; the comments consumption lands in the orchestrator's contract via #899.
Need help on this PR? Tag
@codesmith-botwith what you need.