Skip to content

feat(semantic): Layer 2 — rules-based semantic viewer - #36

Merged
takeshiD merged 4 commits into
mainfrom
worktree-layer2-semantic-viewer
Jul 5, 2026
Merged

takeshiD merged 4 commits into
mainfrom
worktree-layer2-semantic-viewer

Conversation

@takeshiD

@takeshiD takeshiD commented Jul 4, 2026 •

Copy link
Copy Markdown
Owner

Layer 2 — Semantic viewer (rules-centric)

Implements Layer 2 from AGENTS.md §10, built on top of Layer 1's mdpeek-parser.
Turns markdown into a DocumentModel + SemanticPanel with deterministic rules only (no LLM):

markdown ─▶ mdpeek_parser::BlockTree ─▶ analyzer(rules) ─▶ DocumentModel ─▶ SemanticPanel

Lives in a new workspace crate crates/mdpeek-analyzer, matching Layer 1's fine-grained crate layout.

What's here

  • model (§4.2) — DocumentType, Classified<T>, BlockClass, DocumentModel, OutlineEntry, Task.
  • analyzer — doctype (frontmatter → filename → heading-set → content heuristics, confidence-scored), block_class (section propagation), code (intent sniffing: shell/json/yaml/toml/sql/http/diagram/diff/lang), table (columns + status-column detection, by re-reading the source lines), tasks (checkbox extraction).
  • links — mdpeek-parser folds inline links into block text, so Layer 2 re-parses once to recover hyperlinks with source ranges for DocumentModel.links.
  • panel — outline / TODO (task items + inline TODO·FIXME·XXX·HACK) / risk / open-questions side panel, every entry with a SourceRangeLink back to source. Not yet UI IR (that's Layer 3), per the roadmap.

Layer 2 deliverables (AGENTS.md)

  • ✅ DocumentModel
  • ✅ doctype inference (rules)
  • ✅ SourceRangeLink

Integration with Layer 1 (merged)

Layer 1 (#12–#20, now on main) split the project into fine-grained crates and added a SourceRange-aware BlockTree in mdpeek-parser. This branch merges main and integrates accordingly:

  • Dropped the duplicate SourceRange parser the original Layer 2 draft carried — the crate now consumes mdpeek_parser::BlockTree (this was the planned integration point).
  • Adapted to mdpeek-parser's API: BlockId(u64) content-stable ids, CodeBlock{language}, Item{task}, MetadataBlock as a block, no per-block byte_range (table analysis slices source by SourceRange line numbers), frontmatter() accessor.
  • src/main.rs merge conflict resolved by taking main's version — Layer 2 no longer lives in the binary.

Net diff vs main is just the new mdpeek-analyzer crate + its workspace registration.

Verification

  • cargo test --workspace — all pass (mdpeek-analyzer 40; Layer 1 crates unchanged & green).
  • cargo clippy --workspace --all-targets — clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_01QcBxPCWg3P2QwyqMGpTyfp

Add the Layer 2 "Semantic viewer (rules-centric)" from AGENTS.md §10 as a
self-contained `semantic` module. Turns markdown into a `DocumentModel` and a
`SemanticPanel` using deterministic rules only (no LLM):

  markdown -> parser::BlockTree -> analyzer(rules) -> DocumentModel -> SemanticPanel

- parser: SourceRange/LineIndex/BlockTree via pulldown-cmark into_offset_iter
- model: DocumentType, Classified<T>, BlockClass, DocumentModel (§4.2)
- analyzer: doctype (frontmatter/filename/heading heuristics), block_class,
  code intent, table semantics (status column), task extraction
- panel: outline / TODO / risk / open-questions side panel, each entry with a
  SourceRangeLink back to the source (not yet UI IR, per roadmap)

Deliverables per AGENTS.md Layer 2: DocumentModel, rules doctype inference,
SourceRangeLink.

Interference note: kept entirely additive under `src/semantic/` (only a single
`mod semantic;` line added to main.rs; no Cargo.toml/dep changes) so it does not
collide with the parallel Layer 1 workspace migration / SourceRange parser in
`layer1-sourcerange-parser`. On integration the `semantic::parser` foundation is
expected to be replaced by `mdpeek-core::parser::BlockTree`.

124 unit tests cover parsing, classification and panel building; clippy clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QcBxPCWg3P2QwyqMGpTyfp
@takeshiD
takeshiD marked this pull request as ready for review July 5, 2026 00:07
takeshiD and others added 3 commits July 5, 2026 12:58
Layer 1 (#12–#20) merged to main: workspace split into fine-grained crates
(mdpeek-gfm/parser/render-html/render-term/watcher/server) and a SourceRange-
aware BlockTree in mdpeek-parser.

Integrate Layer 2 on top of that foundation:

- Move the Layer 2 semantic analyser out of the `mdpeek` binary
  (src/semantic/) into a new workspace crate `crates/mdpeek-analyzer`,
  matching Layer 1's fine-grained crate layout.
- Delete the duplicate SourceRange parser (src/semantic/parser.rs); the crate
  now consumes `mdpeek_parser::BlockTree` (this was the planned integration
  point noted in the original Layer 2 PR).
- Adapt to mdpeek-parser's API: BlockId(u64) content-stable ids,
  CodeBlock{language}, Item{task}, MetadataBlock as a block, no per-block
  byte_range (table analysis now slices source by SourceRange line numbers),
  frontmatter() accessor.
- Add a `links` module: mdpeek-parser folds inline links into text, so Layer 2
  re-parses once to recover hyperlinks with source ranges for DocumentModel.
- Resolve src/main.rs conflict by taking main's version (Layer 2 no longer
  lives in the binary).

mdpeek-analyzer: 40 tests. Full workspace: all tests pass, clippy clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QcBxPCWg3P2QwyqMGpTyfp
Add a startup-loaded config switch for choosing between rules-based and
LLM-based generation, per AGENTS.md 論点 F/K.

- mdpeek-analyzer: new `generation` module with `GenerationStrategy`
  (RulesFirst/LlmFirst) + `GenerationConfig` policy and a `should_use_llm()`
  decision function the Layer 3 generator will consult per node:
    * llm disabled       -> never (strictly rules)
    * llm_first + enabled -> always prefer the LLM
    * rules_first        -> escalate only below `confidence_threshold` (0.6)
- binary `[llm]` config section: `enabled`, `strategy`, `confidence_threshold`,
  loaded at startup and mapped via `Config::generation_config()`.
- main: resolve the policy at startup; serve mode logs the effective policy
  (term mode left untouched so piped output stays clean).
- config.example.toml: document the `[llm]` section.

Verified at runtime: `strategy = "llm_first"` and `"rules_first"` (and the
disabled default) are picked up from config.toml and reflected in the startup
log. Workspace tests pass, clippy clean.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QcBxPCWg3P2QwyqMGpTyfp
…ODO closers

- Add docs/sample-design-doc.md exercising the rules-detectable structures
  (outline, task list, status table, mermaid/toml/http code fences, risks /
  open-questions sections, inline TODO, links).
- Add `cargo run -p mdpeek-analyzer --example analyze -- <file>` to print the
  rules-stage DocumentModel / SemanticPanel + code-block and table analyses.
- panel: strip trailing comment closers so `<!-- TODO: x -->` yields "x".

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QcBxPCWg3P2QwyqMGpTyfp
@takeshiD
takeshiD merged commit 0c37cb9 into main Jul 5, 2026
4 checks passed
@takeshiD
takeshiD deleted the worktree-layer2-semantic-viewer branch July 5, 2026 04:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant