feat(hint): H2 Phase B — per-form keying + the three exemplars (ADR-0053)

The first exemplar (`add 1:n relationship`) showed per-node keying is
too coarse for multi-form commands, so revise the mechanism to per-form.

- CommandNode `hint_id: Option<&str>` -> `hint_ids: &[&str]` (mirrors
  usage_ids); hint_key_for_input_in_mode reuses a factored-out
  pick_form_key (shared digit/m:n/suffix form disambiguation with
  usage_key_for_input_in_mode)
- wire INSERT + ADD (all four forms) with hint_ids
- author the three approved exemplars: hint.cmd.insert,
  hint.cmd.add_relationship, hint.err.foreign_key.child_side
  (what/example/concept) + keys.rs registration
- revise ADR-0053 D3 to per-form; record clause-concept hints as a
  deferred extension (issue #37); update README + plan
- +5 tests; 2488 pass / 1 ignored, clippy clean
This commit is contained in:
claude@clouddev1
2026-06-15 12:18:41 +00:00
parent 050b36391e
commit 4a5fd1b5c1
11 changed files with 292 additions and 109 deletions
+20 -11
View File
@@ -968,7 +968,7 @@ pub static DROP: CommandNode = CommandNode {
shape: DROP_SHAPE,
ast_builder: build_drop,
help_id: Some("ddl.drop"),
hint_id: None,
hint_ids: &[],
usage_ids: &[
"parse.usage.drop_table",
"parse.usage.drop_column",
@@ -982,7 +982,16 @@ pub static ADD: CommandNode = CommandNode {
shape: ADD_SHAPE,
ast_builder: build_add,
help_id: Some("ddl.add"),
hint_id: None,
// Per-form (ADR-0053 D3): every form is listed so the form-word
// disambiguation resolves correctly; forms without an authored
// block yet fall back to tier-2 at render. `add_relationship` is
// authored as a Phase-B exemplar.
hint_ids: &[
"add_column",
"add_relationship",
"add_index",
"add_constraint",
],
usage_ids: &[
"parse.usage.add_column",
"parse.usage.add_relationship",
@@ -995,7 +1004,7 @@ pub static RENAME: CommandNode = CommandNode {
shape: RENAME_COLUMN,
ast_builder: build_rename_column,
help_id: Some("ddl.rename"),
hint_id: None,
hint_ids: &[],
usage_ids: &["parse.usage.rename_column"],};
pub static CHANGE: CommandNode = CommandNode {
@@ -1003,7 +1012,7 @@ pub static CHANGE: CommandNode = CommandNode {
shape: CHANGE_COLUMN,
ast_builder: build_change_column,
help_id: Some("ddl.change"),
hint_id: None,
hint_ids: &[],
usage_ids: &["parse.usage.change_column"],};
// =================================================================
@@ -1364,7 +1373,7 @@ pub static CREATE: CommandNode = CommandNode {
shape: CREATE_TABLE,
ast_builder: build_create_table,
help_id: Some("ddl.create"),
hint_id: None,
hint_ids: &[],
usage_ids: &["parse.usage.create_table"],};
// =================================================================
@@ -1433,7 +1442,7 @@ pub static CREATE_M2N: CommandNode = CommandNode {
shape: CREATE_M2N_SHAPE,
ast_builder: build_create_m2n,
help_id: Some("ddl.create_m2n"),
hint_id: None,
hint_ids: &[],
usage_ids: &["parse.usage.create_m2n"],
};
@@ -1864,7 +1873,7 @@ pub static SQL_CREATE_TABLE: CommandNode = CommandNode {
shape: Node::Subgrammar(&super::sql_create_table::SQL_CREATE_TABLE_SHAPE),
ast_builder: build_sql_create_table,
help_id: Some("ddl.sql_create_table"),
hint_id: None,
hint_ids: &[],
usage_ids: &["parse.usage.sql_create_table"],
};
@@ -1884,7 +1893,7 @@ pub static SQL_DROP_TABLE: CommandNode = CommandNode {
shape: SQL_DROP_TABLE_SHAPE,
ast_builder: build_sql_drop_table,
help_id: Some("ddl.sql_drop_table"),
hint_id: None,
hint_ids: &[],
usage_ids: &["parse.usage.sql_drop_table"],
};
@@ -1904,7 +1913,7 @@ pub static SQL_DROP_INDEX: CommandNode = CommandNode {
shape: SQL_DROP_INDEX_SHAPE,
ast_builder: build_sql_drop_index,
help_id: Some("ddl.sql_drop_index"),
hint_id: None,
hint_ids: &[],
usage_ids: &["parse.usage.sql_drop_index"],
};
@@ -1986,7 +1995,7 @@ pub static SQL_CREATE_INDEX: CommandNode = CommandNode {
shape: SQL_CREATE_INDEX_SHAPE,
ast_builder: build_sql_create_index,
help_id: Some("ddl.sql_create_index"),
hint_id: None,
hint_ids: &[],
usage_ids: &["parse.usage.sql_create_index"],
};
@@ -2545,7 +2554,7 @@ pub static SQL_ALTER_TABLE: CommandNode = CommandNode {
shape: SQL_ALTER_TABLE_SHAPE,
ast_builder: build_sql_alter_table,
help_id: Some("ddl.sql_alter_table"),
hint_id: None,
hint_ids: &[],
usage_ids: &["parse.usage.sql_alter_table"],
};