@polycode-projects/the-mechanical-code-talker 2.3.1 → 2.5.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +131 -32
  2. package/bin/tmct.mjs +18 -91
  3. package/corpus/README.md +3 -3
  4. package/corpus/seon/README.md +1 -0
  5. package/corpus/tier2/generate.mjs +18 -18
  6. package/corpus/tier2/manifest.json +3 -3
  7. package/data/games/hanoi-3.txt +8 -2
  8. package/package.json +26 -8
  9. package/src/adapters/corpus-lanes.mjs +13 -0
  10. package/src/adapters/graph-build.mjs +5 -7
  11. package/src/adapters/import-closure.mjs +28 -0
  12. package/src/adapters/memory/blocks.mjs +5 -4
  13. package/src/adapters/memory/core.mjs +78 -5
  14. package/src/adapters/memory/shacl.mjs +12 -0
  15. package/src/adapters/providers/graph-service.mjs +12 -5
  16. package/src/adapters/tracked-files.mjs +17 -0
  17. package/src/domain/ask-vocab.mjs +2 -0
  18. package/src/domain/ask.mjs +225 -13
  19. package/src/domain/cli-verbs.mjs +201 -0
  20. package/src/domain/codegraph.mjs +142 -56
  21. package/src/domain/completions/graph-adapter.mjs +1 -1
  22. package/src/domain/completions/group.mjs +3 -17
  23. package/src/domain/completions/infer.mjs +4 -13
  24. package/src/domain/completions/rank.mjs +6 -19
  25. package/src/domain/grammar/lexicon-core.json +1 -1
  26. package/src/domain/hash.mjs +36 -13
  27. package/src/domain/interpret/fuzzy.mjs +7 -2
  28. package/src/domain/interpret/normalize.mjs +9 -0
  29. package/src/domain/interpret/strategies/keywords.mjs +19 -9
  30. package/src/domain/memory/capability.mjs +22 -3
  31. package/src/domain/memory/touched-facts.mjs +17 -0
  32. package/src/domain/module-paths.mjs +9 -0
  33. package/src/domain/persona/tiers.mjs +1 -1
  34. package/src/domain/planning.mjs +37 -0
  35. package/src/domain/prose.mjs +10 -2
  36. package/src/domain/relative-specifiers.mjs +12 -0
  37. package/src/domain/router/registry.mjs +3 -2
  38. package/src/domain/router/results.mjs +5 -18
  39. package/src/domain/seeded-random.mjs +33 -0
  40. package/src/domain/syllogise.mjs +10 -7
  41. package/src/domain/text-stats.mjs +31 -0
  42. package/src/services/chat.mjs +722 -184
  43. package/src/services/extract-facts.mjs +155 -0
  44. package/src/services/import-file.mjs +2 -2
  45. package/src/services/init.mjs +2 -2
  46. package/src/services/ledger-viz.mjs +6 -1
  47. package/src/services/sentences.mjs +26 -0
  48. package/src/surfaces/web/memory-ask-browser.bundle.js +11390 -360
  49. package/src/tools/graph-load.mjs +7 -1
  50. package/src/tools/readme-docs.mjs +113 -0
  51. package/src/tools/schema-docs.mjs +2 -2
  52. package/ROADMAP.md +0 -129
  53. package/corpus/namenet/generate.mjs +0 -309
  54. package/corpus/wordnet/generate.mjs +0 -332
  55. package/src/adapters/prose-tokens.mjs +0 -98
  56. package/src/adapters/wordnet-source.mjs +0 -70
  57. package/src/domain/corpus-matrix.mjs +0 -87
  58. package/src/domain/inflect.mjs +0 -67
  59. package/src/domain/licences.mjs +0 -68
  60. package/src/domain/markdown-links.mjs +0 -55
  61. package/src/domain/persona/codegen.mjs +0 -123
  62. package/src/domain/publish-gate.mjs +0 -41
  63. package/src/domain/schemaorg/turtle.mjs +0 -25
  64. package/src/domain/semcor/parse.mjs +0 -87
  65. package/src/domain/version-stamp.mjs +0 -36
  66. package/src/domain/wordnet/yaml.mjs +0 -133
package/README.md CHANGED
@@ -2,9 +2,8 @@
2
2
 
3
3
  `@polycode-projects/the-mechanical-code-talker`
4
4
 
5
- A pure-JS, **no-LLM**, offline, **$0** chatbot in the ELIZA/PARRY lineage:
6
- pattern-driven, best-efforts, and focused on software as its subject matter.
7
- It makes no model calls.
5
+ A pure-JS, **no-LLM**, offline, **$0** chatbot in the ELIZA/PARRY lineage.
6
+ It is pattern-driven and focused on software, and it makes no model calls.
8
7
 
9
8
  tmct turns natural language directly into a graph database. On first run it
10
9
  seeds an everyday **human-world persona**: people, places, objects, nature,
@@ -100,8 +99,12 @@ parts are real provenance receipts. Every fact tmct stores records where it
100
99
  came from and when (more on that below).
101
100
 
102
101
  The test suite replays every runnable example in this README against the
103
- live product, this transcript included. If the chat behavior ever drifts
104
- from the output above, the suite fails and says so.
102
+ live product, this transcript included. Every line shown must be a line the
103
+ product prints, in the order shown, so if the chat behavior drifts from the
104
+ output above, the suite fails and says so. Two blocks below are marked `skip=`
105
+ and never run: one would touch the network, the other needs an LLM judge.
106
+ `docs/public-examples.md` maps every example on every public surface to the
107
+ test that holds it.
105
108
 
106
109
  Point it at a codebase's graph and the same engine answers structural questions.
107
110
  `examples/mini-webapp` ships in this repo, so this runs as written:
@@ -160,7 +163,7 @@ Text that doesn't fit the grammar still gets the tolerant strategies. Nothing
160
163
  is rejected for being loose, fuzzy, or misspelled.
161
164
 
162
165
  On top of that base, tmct reads the shapes people actually use, and each one
163
- resolves to a real graph traversal or declines honestly:
166
+ resolves to a real graph traversal or declines cleanly:
164
167
 
165
168
  - everyday question forms: "what is Commit", "what's model.mjs for",
166
169
  "recent commits" as real dated history;
@@ -190,7 +193,7 @@ under a guard that proves the protected spans came through byte-for-byte.
190
193
 
191
194
  A frozen regression suite plays out full multi-turn dialogues built from these
192
195
  phrasings, from a single question up to a messy, typo-ridden real user.
193
- Tier-by-tier detail is in `HANDOVER.md` and `ROADMAP.md`.
196
+ Tier-by-tier detail is in `HANDOVER.md`.
194
197
 
195
198
  ## How it guides you
196
199
 
@@ -353,8 +356,13 @@ Goal (inferred): Plan a move sequence from the current state to the goal (7 move
353
356
  ```
354
357
 
355
358
  "next" executes one move at a time, writing each board state into memory as
356
- facts; the final step re-reads those facts and confirms the goal from them,
357
- never assuming success. The search is genuine and domain-general: the test
359
+ facts stamped with the step that produced them ("disk-1@step1 rests on peg-c",
360
+ sourced to the plan). The final step re-reads the store and confirms the goal
361
+ from those written facts, never assuming success. The stamp is what makes each
362
+ step a separate record; a question about the piece itself ("where does disk-1
363
+ rest?", "is disk-1 clear?") reads the current board — the latest step's facts,
364
+ not every step at once. The search is
365
+ domain-general: the test
358
366
  suite teaches Towers of Hanoi purely as sentences for 1 to 8 disks and
359
367
  asserts the plan is exactly 2^n − 1 moves every time, and a second game
360
368
  (`crates.txt`, stacking crates with different rules and a two-goal
@@ -417,14 +425,15 @@ nudges you to ground one side first. Quantified teaching stores the
417
425
  quantifier ("some functions are risky" … "how many functions are risky" →
418
426
  "A few."), and "how many facts are there" counts the store back.
419
427
 
420
- Teaching doesn't have to be typed, either. `npm run extract:facts` (from a
421
- clone) runs a plain text file through the same recognizer the chat's teach
422
- lane uses. Sentences the recognizer grounds become fact rows; everything
423
- else is skipped and counted, never paraphrased:
428
+ Teaching doesn't have to be typed, either. `tmct extract` runs a plain text
429
+ file through the same recognizer the chat's teach lane uses. Sentences the
430
+ recognizer grounds become fact rows; everything else is skipped and counted,
431
+ never paraphrased. Add `--repo <abs>` to write them into that repo's own
432
+ memory; without it nothing on disk is mutated and the facts print as JSONL:
424
433
 
425
434
  ```bash cwd=repo
426
435
  printf 'We deployed redis last week. a cache is a kind of store. Why was it slow?\n' > /tmp/notes.txt
427
- node scripts/extract-facts-from-text.mjs /tmp/notes.txt
436
+ node bin/tmct.mjs extract /tmp/notes.txt
428
437
  ```
429
438
 
430
439
  ```output
@@ -537,13 +546,13 @@ provenance record. Most of its flags choose what gets seeded and where config is
537
546
  [--corpus <id|path>] also seed a corpus — a tier-2 manifest id (aws|python|java|
538
547
  general) or a jsonl file path — opt-in, offline, $0
539
548
  [--ontology <name|path>] activate+seed an ontology bundle (a recognized name or a path)
540
- [--lexicon <name|path>] activate a lexicon bundle (recognized name or a path;
549
+ [--lexicon <name|path>] activate a lexicon bundle (recognized name or a path;
541
550
  merged read-time, never seeded — see mergedLexiconExtra)
542
551
  [--graph <path>] set graph_file/graph_files in tmct.toml (repeatable)
543
552
  [--config <path>] write to an alternate tmct.toml location
544
553
  [--detect] suggest a tier-2 corpus from the repo's manifests
545
554
  (pyproject.toml → python, pom.xml → java); never seeds unasked
546
- [--with-persona <name>] write an explicit [extensions]/[bias] preset into tmct.toml
555
+ [--with-persona <name>] write an explicit [extensions]/[bias] preset into tmct.toml
547
556
  ("code" — today's implicit default, made explicit)
548
557
  [--persona-size <medium|large>] grow the default "human" persona's fact count
549
558
  beyond Small (the default): "medium" activates
@@ -564,7 +573,7 @@ already set up. Its `--graph` flag works differently from the others: it appends
564
573
  tmct import [--repo <abs>] activate+seed into an ALREADY-initialized repo (any
565
574
  [--corpus <id|path>] combination of these flags in one call). --graph is a
566
575
  [--ontology <name|path>] DIFFERENT operation from the others: it APPENDS to
567
- [--lexicon <name|path>] tmct.toml's graph_files array (multi-graph growth),
576
+ [--lexicon <name|path>] tmct.toml's graph_files array (multi-graph growth),
568
577
  [--graph <path>] never an extensions-bundle activation.
569
578
  [--file <definition.txt>] teach a plain-text definition file sentence by
570
579
  sentence (# lines are comments); any declined
@@ -573,12 +582,24 @@ already set up. Its `--graph` flag works differently from the others: it appends
573
582
  [--config <path>]
574
583
  ```
575
584
 
585
+ `tmct extract` is the document route into memory described under "Teach it"
586
+ above — the same teach recognizer, reading a file instead of your typing:
587
+
588
+ ```output:help:extract
589
+ tmct extract <text-file> read a plain text file's sentences through the chat's own
590
+ [--file <text-file>] teach recognizer and keep the facts it grounds; every
591
+ other sentence is skipped and counted, never paraphrased
592
+ [--repo <abs>] write the facts into that repo's own tmct memory; without
593
+ it nothing on disk is mutated and the facts print as JSONL
594
+ [--out <file.jsonl>] write that JSONL to a file instead of stdout
595
+ ```
596
+
576
597
  `tmct extend --validate` checks a third-party extension pack's declared resources
577
598
  before you switch any repo's `tmct.toml` over to it:
578
599
 
579
600
  ```output:help:extend
580
601
  tmct extend --validate <dir> validate a third-party extension pack's declared
581
- [--config <path>] resources (corpus/lexicon/templates) before activating
602
+ [--config <path>] resources (corpus/lexicon/templates) before activating
582
603
  it in any repo's tmct.toml; exits non-zero on failure
583
604
  ```
584
605
 
@@ -586,9 +607,9 @@ before you switch any repo's `tmct.toml` over to it:
586
607
  inference" above:
587
608
 
588
609
  ```output:help:syllogise
589
- tmct syllogise [--repo <abs>] speculative inference (offline maintenance job): forward-
610
+ tmct syllogise [--repo <abs>] speculative inference (offline maintenance job): forward-
590
611
  [--depth <n>] [--budget <n>] chain the memory's rdfs:subClassOf closure, materialising
591
- [--config <path>] bounded, low-trust, retractable entailed facts (never on the chat path)
612
+ [--config <path>] bounded, low-trust, retractable entailed facts (never on the chat path)
592
613
  ```
593
614
 
594
615
  `tmct viz` renders the memory graph as the ledger explorer — a single,
@@ -596,11 +617,11 @@ self-contained HTML file you can open in a browser:
596
617
 
597
618
  ```output:help:viz
598
619
  tmct viz [--repo <abs>] write one self-contained HTML page: the memory graph as a
599
- [--focus <term>] readable ledger of fact-sentences around one focus term,
600
- [--term <word>] with segments, a two-hop minimap, and an in-page chat dock
601
- [--limit <n>] that answers from the embedded graph. Focuses on the newest
602
- [--output <path>] taught fact's subject by default (--focus <term> or
603
- [--config <path>] --term <word> override it); --output defaults to
620
+ [--focus <term>] readable ledger of fact-sentences around one focus term,
621
+ [--term <word>] with segments, a two-hop minimap, and an in-page chat dock
622
+ [--limit <n>] that answers from the embedded graph. Focuses on the newest
623
+ [--output <path>] taught fact's subject by default (--focus <term> or
624
+ [--config <path>] --term <word> override it); --output defaults to
604
625
  ledger.html in the cwd; --limit caps the embedded fact
605
626
  rows; --term resolves via the same normalization chat uses.
606
627
  ```
@@ -927,7 +948,7 @@ node bin/tmct.mjs cli tmct_untested '{"repo_path":"examples/mini-webapp"}'
927
948
  ## The repository interface
928
949
 
929
950
  tmct is not an indexer, so it consumes a graph through a typed contract any
930
- producer can implement. That contract is first-class: a **versioned (1.0.0),
951
+ producer can implement. That contract is first-class: a **versioned (1.1.0),
931
952
  OWL-grounded, machine-readable service definition** (`docs/repository-interface.md`
932
953
  plus a JSON schema) of every service, its arguments, result types, and error
933
954
  contract. The interface returns a miss as a normal value. It never throws to
@@ -942,6 +963,19 @@ service. The LLM agent stays outside tmct, as the no-LLM ethos requires.
942
963
 
943
964
  ## Measuring it
944
965
 
966
+ What the 2.0.3 cycle measured, on 2026-07-16. Each figure links to its method
967
+ and carries, in the same row, the caveat that changes what it means. The full
968
+ tables, judge scores, and transcripts are in the linked write-ups.
969
+
970
+ | What it does | Result (2.0.3) | Read the number with this | Method |
971
+ |---|---|---|---|
972
+ | Multi-hop entailment | 219/219 chat cases and 80/80 kernel cases, 0% fabrication, all six bands pass | 50 of the 219 greens (23%) are graded against a declared floor, not the classical answer. INF-C2's 20/20 grades that the engine answers contradictory memory without fabricating, never that it detects the clash. | `BENCHMARK_INFERENCE_2.0.3.md` |
973
+ | Tool-call planning | 56/56 cases, 100% plan-completion, 100% result-completion, 0% hallucination, every rung A0→C2 | Goal driver. All 11 C2 cases pass, so the ladder now has more headroom than the case set exercises. | `BENCHMARK_AGENT_2.0.3.md` |
974
+ | Groundedness | Every answer carries a source, and an empty graph reports itself empty (`bootstrap-empty` 2.000/2). Judge-scored groundedness 1.857/2 over 98 cases. | The 1.857 is judged (`claude-haiku-4-5-20251001`, `judge-prompt-v1`) at N=1 over 9 of 23 construction shapes, so read it as indicative. The judge runs in the offline eval harness, never in the product. | `BENCHMARK_CEFR_ENGLISH_2.0.3.md` |
975
+ | Abstention (the honest miss) | 0% fabrication across 299 inference rows and 0% hallucination across 168 agent rows | Structural, not a tuned threshold. tmct abstains because nothing matched, so the rows test a property of a no-model design rather than a score. | `BENCHMARK_INFERENCE_2.0.3.md`, `BENCHMARK_AGENT_2.0.3.md` |
976
+ | Determinism | Byte-identical on rerun, 0 verdict changes across 299 inference rows against the prior cycle, a 109-case replay in 877ms at $0 per turn | A property of the no-model pipeline. | `BENCHMARK_INFERENCE_2.0.3.md`, `CAPABILITIES_2.0.3.md` |
977
+ | Dialogue robustness (role and polarity) | An adversarial persona sweep could not force a single role or polarity inversion in 55 probes — active/passive, forward/reverse, negation and the converse trap all compiled to the correct canonical shape | The same five-frame sweep (~200 probes) surfaced 25 dialogue dead-ends, eight of them confidently wrong, all from words dropped before the parser rather than from the reasoning. | `BENCHMARK_CONVERSATION_2.0.3.md` |
978
+
945
979
  Three offline benchmark rigs live in a clone (they are not in the npm
946
980
  package). Each replays a committed case set through the real product and
947
981
  writes graded rows you can diff between runs:
@@ -960,7 +994,7 @@ bench-smoke lane replays:
960
994
  ```bash cwd=repo
961
995
  node chatbench/run.mjs --stamp smoke --only g-a1-naming-1 --out /tmp/chatbench-smoke
962
996
  node infbench/generate-cases.mjs --out /tmp/infbench-cases.jsonl
963
- node infbench/run.mjs --cases /tmp/infbench-cases.jsonl --only inf-a1-lookup-subClassOf-001 --stamp smoke --out /tmp/infbench-smoke
997
+ node infbench/run.mjs --cases /tmp/infbench-cases.jsonl --only inf-1-lookup-subClassOf-001 --stamp smoke --out /tmp/infbench-smoke
964
998
  node agentbench/run.mjs --stamp smoke --driver stub --only ab-a0-describe-widget --out /tmp/agentbench-smoke
965
999
  ```
966
1000
 
@@ -971,9 +1005,6 @@ one place an LLM is allowed, never the product:
971
1005
  npm run chatbench:judge -- --product /tmp/chatbench-smoke/product.jsonl
972
1006
  ```
973
1007
 
974
- The headline numbers and their conditions live in the `BENCHMARK_*.md`
975
- write-ups.
976
-
977
1008
  ## Security and supply chain
978
1009
 
979
1010
  tmct is $0 to run and meant to be trusted offline, so the supply chain is
@@ -992,8 +1023,76 @@ cross-version-stable fact-id contract has exactly one definition.
992
1023
  tmct began as a whole-package lift of the seonix chat surface (v0.1.0, then
993
1024
  published as `@polycode-projects/mct`), and was then reshaped. The LLM
994
1025
  fallback, the code-extraction stack, and the MCP server were all removed. The
995
- naming, license, and memory model were reset to the vision above. See
996
- `ROADMAP.md` for the phase plan.
1026
+ naming, license, and memory model were reset to the vision above. See the
1027
+ `PLAN_*.md` design docs for what's planned next.
1028
+
1029
+ ## Standards and bibliography
1030
+
1031
+ tmct's vocabulary is grounded in published standards where they exist, and says where they don't.
1032
+ Each alignment below is a triple in `ontology/tmct-core.ttl` and a test in
1033
+ `test/adapters/grammar-ontology.test.mjs`. `docs/references/` holds an entry per source: the
1034
+ edition, the retrieval date, the terms tmct uses, and what could not be verified.
1035
+ `PLAN_NORMATIVE.md` holds the reconciliation, one verdict per term.
1036
+
1037
+ ### The data model
1038
+
1039
+ | source | edition | what tmct uses it for |
1040
+ |---|---|---|
1041
+ | [W3C OWL 2 Primer](https://www.w3.org/TR/owl2-primer/) · [Profiles](https://www.w3.org/TR/owl2-profiles/) | Recommendation, 2012-12-11 | The triple model. The grammar emits `rdfs:subClassOf`, `owl:Restriction`, `owl:someValuesFrom`, `owl:disjointWith` and cardinality axioms. The inference engine implements OWL 2 RL/RDF rules and uses their names: `scm-sco`, `cax-sco`, `cax-dw`, `cls-svf1`, `scm-svf1`. |
1042
+ | [RDF 1.1 Semantics](https://www.w3.org/TR/rdf11-mt/) | Recommendation, 2014-02-25 | Facts are reified statements. Appendix D.1 endorses reification for provenance, which is what tmct uses it for. [RDF 1.2](https://www.w3.org/TR/rdf12-concepts/) (Candidate Recommendation, 2026-04-07) reclassifies that vocabulary as legacy and points new systems at triple terms and `rdf:reifies`. tmct has not moved, and `docs/references/schemas/rdf-reification-and-rdf-star.md` says why. |
1043
+ | [W3C PROV-O](https://www.w3.org/TR/prov-o/) | Recommendation, 2013-04-30 | Provenance. A fact's source links sit under `prov:wasInfluencedBy`; a fact cleaned from a raw utterance is a `prov:wasDerivedFrom`; a session is a `prov:Activity` and the utterances in it are `prov:Entity`s it generated. |
1044
+ | [W3C SKOS](https://www.w3.org/TR/skos-reference/) | Recommendation, 2009-08-18 | Read, and mostly not used. `skos:related` needs `skos:Concept` at both ends, and tmct's corpus terms are bare strings. `docs/references/schemas/skos.md` records what a concept-identity pass would need. |
1045
+ | [SEON](http://se-on.org/) `code.owl` | 2012/02 | Code-graph vocabulary: `seon:hasSuperType`, `seon:containsCodeEntity`, `seon:declaresMethod`, `seon:invokesMethod` and 15 more. Where SEON has no term, tmct coins under its own `mgx:` prefix rather than borrowing SEON's. |
1046
+
1047
+ ### Language
1048
+
1049
+ | source | edition | what tmct uses it for |
1050
+ |---|---|---|
1051
+ | [Attempto Controlled English](http://attempto.ifi.uzh.ch/site/docs/) | ACE 6.7, 2013 | The controlled-English fragment. tmct implements 9 of ACE's declarative sentence patterns. |
1052
+ | Kuhn, "A Survey and Classification of Controlled Natural Languages" | *Computational Linguistics* 40(1), 2014 | Where ACE sits among controlled languages. |
1053
+ | [ConceptNet](https://github.com/commonsense/conceptnet5/wiki/Relations) | slice pins 5.7.0 | The commonsense corpus. 25 relations are mirrored into `mgx:` and each cites its `/r/` origin. |
1054
+ | Damerau, *CACM* 7(3), 1964 · Levenshtein, *Soviet Physics Doklady* 10(8), 1966 | — | Fuzzy matching. `fuzzy.mjs` implements **Optimal String Alignment** — restricted Damerau-Levenshtein, which allows adjacent transposition but edits no substring twice. |
1055
+
1056
+ ### Reasoning and planning
1057
+
1058
+ | source | edition | what tmct uses it for |
1059
+ |---|---|---|
1060
+ | Fikes & Nilsson, "STRIPS" | *Artificial Intelligence* 2(3–4), 1971 | The action model: operator, precondition, effect. |
1061
+ | McDermott et al., PDDL | Yale CVC TR-98-003, 1998 | The action-rule vocabulary. |
1062
+ | Doyle, "A Truth Maintenance System" | *Artificial Intelligence* 12(3), 1979 | Justification and premise. tmct records which rule entailed a fact; it does not yet record which facts fed the rule. |
1063
+ | Meszaros, *xUnit Test Patterns* | Addison-Wesley, 2007 | The test-double taxonomy — stub, spy, mock, fake, dummy — and the fixture patterns. `docs/references/testing-vocabulary.md` records where tmct's own tiers depart from the standard taxonomy, and that "blast radius" is an ops metaphor for what the literature calls Regression Test Selection. |
1064
+ | Aristotle, *Prior Analytics* I.1 (24b18–20) · Bobzien, "Ancient Logic", *SEP* | — | **Why the command is called `syllogise`.** The word is used in the older, broader sense of *sullogismos* — Aristotle's own definition is "discourse in which, certain things being stated, something other than what is stated follows of necessity", with no mention of three terms or two premises, and the Stoics used the same word for a system in which modus ponens is a *sullogismos*. Two of tmct's rules are the narrow thing exactly: `scm-sco` is **Barbara**, `cax-sco` is the **Socrates syllogism**. The others reach past term logic. The operation's own names are **forward chaining** and **materialisation**, and the code uses those. |
1065
+
1066
+ ### Storage
1067
+
1068
+ | source | edition | what tmct uses it for |
1069
+ |---|---|---|
1070
+ | Jensen et al., "A Consensus Glossary of Temporal Database Concepts" | *SIGMOD Record* 23(1), 1994 | The time vocabulary. `mgx:utteranceTs` is valid time; `mgx:createdAt` is a transaction-time start. tmct is **not** bitemporal: `mgx:updatedAt` is an audit stamp, so tmct cannot answer what it believed last Tuesday. |
1071
+ | RFC 9923, "The FNV Non-Cryptographic Hash Algorithm" | Informational, 2026 | FNV hashes the narrow non-fact-id pools (paraphrase keys, per-URL source ids, corpus dedupe). Fact ids are content-addressed with a **64-bit truncation of SHA-256**, so a fact id is collision-resistant at tmct's corpus sizes; tmct is still **not** a Merkle tree and offers no tamper-evidence. |
1072
+ | Green, Karvounarakis, Tannen, "Provenance Semirings" | PODS 2007 | The distinction tmct's docs keep: it records source annotation and PROV-style attribution, not how-provenance. |
1073
+
1074
+ ### Measuring it
1075
+
1076
+ | source | edition | what tmct uses it for |
1077
+ |---|---|---|
1078
+ | Council of Europe, CEFR — Companion volume | 2020, ISBN 978-92-871-8621-8 | The band labels A1–C2 the chat benchmark grades against. CEFR measures what a *person* can do communicatively; grading the difficulty of *prompts* by band is tmct's adaptation, not a CEFR-validated use. The band descriptions in `chatbench/GRADED.md` are tmct's own prose. |
1079
+ | Reiter, "On Closed World Data Bases" | *Logic and Data Bases*, Plenum, 1978, pp. 55–76 | Both halves of the honest miss. The planner's operator model is **closed-world**, which is what makes a plan checkable. The chat layer is **open-world**: it will not read "no matching rule" as "the answer is no". |
1080
+ | Chow, "On optimum recognition error and reject tradeoff" | *IEEE Trans. Information Theory* 16(1), 1970 | Prior art for the goal. The literature calls a refusal **abstention**, or selective prediction, and Chow's reject option is its root. Those methods threshold a confidence score; tmct has none, and abstains because nothing matched — which is why the row above names the mechanism. |
1081
+ | Ji et al., "Survey of Hallucination in Natural Language Generation" | *ACM Computing Surveys* 55(12), 2023 | Groundedness, and what tmct is avoiding by having no model to hallucinate with. |
1082
+
1083
+ ### Where no standard fits
1084
+
1085
+ - **Trust.** PROV records who said a thing, not whether to believe them, and no W3C Recommendation
1086
+ covers trust. `mgx:trustScore` and its inputs are tmct's own. Candidate literature: Artz & Gil,
1087
+ "A survey of trust in computer science and the Semantic Web", *Journal of Web Semantics* 5(2),
1088
+ 2007.
1089
+ - **Negation.** tmct negates with its own `mgxneg:` prefix, which applies to any predicate.
1090
+ `owl:disjointWith` would over-claim, since "john is not a man" denies one membership rather than
1091
+ a class axiom, and OWL 2's `negativePropertyAssertion` needs a reified shape the flat JSON store
1092
+ has no room for.
1093
+ - **Dialogue acts.** tmct has no intent vocabulary. ISO 24617-2 (SemAF) is the standard for one, and
1094
+ `docs/references/schemas/iso-24617-2-dialogue-acts.md` maps tmct's behaviour onto it so that if
1095
+ one is built it uses the standard's names.
997
1096
 
998
1097
  ## Licensing
999
1098
 
package/bin/tmct.mjs CHANGED
@@ -26,7 +26,13 @@
26
26
  // tmct began as a whole-package lift of an earlier chat surface (see README
27
27
  // provenance): internal module filenames and symbols were kept to preserve the
28
28
  // shape and the green test suite. See README.md for what tmct is and
29
- // deliberately is NOT, and ROADMAP.md for where it is going.
29
+ // deliberately is NOT, and the PLAN_*.md docs for where it is going.
30
+
31
+ // The verb list itself is data (src/domain/cli-verbs.mjs) and both the Usage
32
+ // block below and the unknown-invocation line read it, so a new verb is one
33
+ // entry rather than two edits that drift. It is pure and imports nothing, so a
34
+ // static import here costs `tmct --help` nothing.
35
+ import { renderUsage, unknownInvocationMessage } from "../src/domain/cli-verbs.mjs";
30
36
 
31
37
  const HELP = `tmct — The Mechanical Code Talker
32
38
 
@@ -34,94 +40,7 @@ A tolerant, offline, $0 chat that guides you toward precision queries about a
34
40
  software repository. No model calls; no codebase index of its own.
35
41
 
36
42
  Usage:
37
- tmct interactive chat (the headline surface)
38
- tmct chat [--repo <abs>] chat over a specific repo's graph
39
- [--graph <path>] explicit graph file (repeatable — multiple graphs merge;
40
- see src/adapters/graph-merge.mjs); wins over --repo/TMCT_GRAPH_FILE/tmct.toml
41
- [--config <path>] an alternate tmct.toml location (a file or a directory)
42
- [--ephemeral] read the graph but write nothing back (demo/read-only)
43
- [--prompt "<text>"] one-shot: run the prompt's sentences as turns and print
44
- the final answer (teach state first, trigger last)
45
- [--render blocks] with --prompt: when the final turn produced a plan,
46
- write it as a self-contained animated page
47
- [--output <path>] the rendered page's path (default plan.html)
48
- [--narrate] start with narrate mode on — a verbose, developer-facing
49
- trace of decision points/matched pattern/results/goal per
50
- turn, appended under a "--- narrate ---" marker (also
51
- TMCT_NARRATE=1; toggle mid-session with /narrate on|off)
52
- [--plain] force the plain readline shell (the default when
53
- stdin/stdout is not a terminal)
54
- [--memory-backend <default|memory|sqlite>] storage backend for taught facts this
55
- session (CLI flag > TMCT_MEMORY_BACKEND env > tmct.toml's
56
- [memory] backend > "default", the flat .tmct/ JSON file)
57
- tmct memory [--repo <abs>] what tmct remembers: facts, utterances, sessions,
58
- [--config <path>] folded blocks (the /memory chat command, from the shell)
59
- [--verbose]
60
- tmct init [--repo <abs>] initialize a repo for tmct (default: cwd): .tmct/,
61
- [--force] tmct.toml, .tmct/TOOLS.md (the cold-tool catalog),
62
- tier-1 corpus seed, provenance record
63
- [--corpus <id|path>] also seed a corpus — a tier-2 manifest id (aws|python|java|
64
- general) or a jsonl file path — opt-in, offline, $0
65
- [--ontology <name|path>] activate+seed an ontology bundle (a recognized name or a path)
66
- [--lexicon <name|path>] activate a lexicon bundle (recognized name or a path;
67
- merged read-time, never seeded — see mergedLexiconExtra)
68
- [--graph <path>] set graph_file/graph_files in tmct.toml (repeatable)
69
- [--config <path>] write to an alternate tmct.toml location
70
- [--detect] suggest a tier-2 corpus from the repo's manifests
71
- (pyproject.toml → python, pom.xml → java); never seeds unasked
72
- [--with-persona <name>] write an explicit [extensions]/[bias] preset into tmct.toml
73
- ("code" — today's implicit default, made explicit)
74
- [--persona-size <medium|large>] grow the default "human" persona's fact count
75
- beyond Small (the default): "medium" activates
76
- human-medium.jsonl (~1,608 facts total), "large" also
77
- activates human-large.jsonl (~13,600 facts total,
78
- with genuine multi-hop hypernym chains) — additive
79
- size tiers of the SAME bundle, not separate personas
80
- [--memory-backend <default|memory|sqlite>] write tmct.toml's [memory] backend
81
- (same flag name as \`tmct chat\`) — a later \`tmct chat\`
82
- in this repo picks it up with no flag needed
83
- tmct import [--repo <abs>] activate+seed into an ALREADY-initialized repo (any
84
- [--corpus <id|path>] combination of these flags in one call). --graph is a
85
- [--ontology <name|path>] DIFFERENT operation from the others: it APPENDS to
86
- [--lexicon <name|path>] tmct.toml's graph_files array (multi-graph growth),
87
- [--graph <path>] never an extensions-bundle activation.
88
- [--file <definition.txt>] teach a plain-text definition file sentence by
89
- sentence (# lines are comments); any declined
90
- sentence exits non-zero with the sentence named
91
- [--memory-backend <default|memory|sqlite>] same knob as \`tmct init\`
92
- [--config <path>]
93
- tmct extend --validate <dir> validate a third-party extension pack's declared
94
- [--config <path>] resources (corpus/lexicon/templates) before activating
95
- it in any repo's tmct.toml; exits non-zero on failure
96
- tmct syllogise [--repo <abs>] speculative inference (offline maintenance job): forward-
97
- [--depth <n>] [--budget <n>] chain the memory's rdfs:subClassOf closure, materialising
98
- [--config <path>] bounded, low-trust, retractable entailed facts (never on the chat path)
99
- tmct viz [--repo <abs>] write one self-contained HTML page: the memory graph as a
100
- [--focus <term>] readable ledger of fact-sentences around one focus term,
101
- [--term <word>] with segments, a two-hop minimap, and an in-page chat dock
102
- [--limit <n>] that answers from the embedded graph. Focuses on the newest
103
- [--output <path>] taught fact's subject by default (--focus <term> or
104
- [--config <path>] --term <word> override it); --output defaults to
105
- ledger.html in the cwd; --limit caps the embedded fact
106
- rows; --term resolves via the same normalization chat uses.
107
- tmct serve [--repo <abs>] run the Anthropic Messages API-compatible endpoint
108
- [--host <h>] [--port <n>] (POST /v1/messages) over the graph — a deterministic,
109
- [--graph <path>] no-LLM "model" a tool-loop client can call; $0 usage.
110
- [--config <path>] Defaults: host 127.0.0.1, port 8787. Ctrl+C to stop.
111
- tmct plan "<request>" the capability router: compose/execute read-only graph-
112
- [--repo <abs>] query tool calls for a compound or maintenance-goal
113
- [--graph <path>] request ("of the modules impacted by X, which are
114
- [--config <path>] untested", "what most needs a test") — a real STRIPS/
115
- [--tools <a,b,...>] PDDL planner (src/domain/router/*), never a guessed call.
116
- [--json] Prints the grounded step sequence + composed answer,
117
- or an honest "no plan found". --tools restricts the
118
- declared toolset; --json prints the full loop result.
119
- tmct cli <tool> '{…}' invoke a graph tool directly (carry-over, de-emphasized)
120
- [--repo <abs>] the repo to answer from; the payload's "repo_path" says
121
- [--graph <path>] the same thing. --graph names the graph file outright
122
- [--config <path>] (repeatable), --config an alternate tmct.toml
123
- tmct cli digest '{…}' architecture map + per-module context bundles
124
- tmct --help show this help
43
+ ${renderUsage()}
125
44
 
126
45
  On a terminal, chat opens the full-screen TUI; piped input gets the plain shell.
127
46
  In chat: /help lists slash-commands; /exit leaves. Session log → <repo>/.tmct/session-<id>.log.
@@ -1117,6 +1036,15 @@ async function main() {
1117
1036
  return;
1118
1037
  }
1119
1038
 
1039
+ if (mode === "extract") {
1040
+ // `tmct extract` — run a text file's sentences through the chat's own teach
1041
+ // recognizer and keep what it grounds. Lazily imported: it pulls the whole
1042
+ // chat stack, which `tmct --help` and chat startup must not pay for.
1043
+ const { main: extractFacts } = await import("../src/services/extract-facts.mjs");
1044
+ await extractFacts(process.argv.slice(3));
1045
+ return;
1046
+ }
1047
+
1120
1048
  if (mode === "viz") {
1121
1049
  // `tmct viz` — the ledger explorer: one self-contained HTML page rendering
1122
1050
  // the memory graph as readable fact-sentences around a focus term, with
@@ -1336,8 +1264,7 @@ async function main() {
1336
1264
 
1337
1265
  // An unknown mode gets the instructive usage line and exit 2. (A bare invocation
1338
1266
  // never lands here — the argv splice above rewrote it to `chat`.)
1339
- process.stderr.write(`tmct: unknown invocation "${process.argv.slice(2).join(" ")}". ` +
1340
- "Use `chat`, `memory`, `init`, `import`, `extend --validate`, `syllogise`, `serve`, `plan`, `cli digest …`, or `cli <tool> …`.\n");
1267
+ process.stderr.write(unknownInvocationMessage(process.argv.slice(2).join(" ")));
1341
1268
  process.exit(2);
1342
1269
  }
1343
1270
 
package/corpus/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # corpus/ — committed corpus data
2
2
 
3
- The corpuses tmct ships so that an **empty** tmct still has a vocabulary
4
- (ROADMAP Phase 2). Everything here is plain, diffable data; the loaders live
3
+ The corpuses tmct ships so that an **empty** tmct still has a vocabulary.
4
+ Everything here is plain, diffable data; the loaders live
5
5
  in `src/adapters/corpus/`. Related committed data lives in `data/` (response templates
6
- + the SE phrase book — items 4+7).
6
+ + the SE phrase book).
7
7
 
8
8
  ## The tiering policy (tier-1 / tier-2 / tier-3)
9
9
 
@@ -20,6 +20,7 @@ CC-BY-SA like the ConceptNet slice.
20
20
  |------|-------|-------|
21
21
  | `concepts.jsonl` | relation facts, byte-identical shape to `corpus/conceptnet/slice.jsonl` | 399 facts |
22
22
  | `definitions.jsonl` | `{ "term", "definition", "sense": "software" }`, one per line | 288 definitions |
23
+ | `relations.jsonl` | `{ "relation", "definition", "sense": "software" }`, one per line — what each edge kind means, so "what does imports mean" answers without per-repo seeding | 9 relations |
23
24
  | `LICENSE-NOTICE` | MPL-2.0 provenance for this directory | — |
24
25
 
25
26
  ### `concepts.jsonl` — same shape as the ConceptNet slice
@@ -241,7 +241,7 @@ export const CORPUSES = {
241
241
  ],
242
242
  },
243
243
 
244
- // PLAN_SEED.md — the default "human-world" persona (the operator's own
244
+ // The default "human-world" persona (the operator's own
245
245
  // framing: SEON+ConceptNet's code-domain bias was never the only sensible
246
246
  // default; this is the general-knowledge seed set that REPLACES it as the
247
247
  // default active bundle, per src/services/extensions.mjs's builtinExtensions()).
@@ -252,20 +252,20 @@ export const CORPUSES = {
252
252
  // IsA/HasA/UsedFor/CapableOf/etc. facts; Schema.org's vocabulary
253
253
  // (Apache-2.0) supplies `human-base`'s top-level category classes and
254
254
  // `human-bridge`'s showcase connection between the two independently-built
255
- // taxonomies (PLAN_SEED.md §8) — both hand-authored in homage to their
255
+ // taxonomies — both hand-authored in homage to their
256
256
  // source's real class shape, never copied verbatim (SEON's own
257
- // LICENSE-NOTICE discipline). 9 clumps, Small tier (PLAN_SEED.md §3):
257
+ // LICENSE-NOTICE discipline). 9 clumps, Small tier:
258
258
  // human-base (scaffolding, always first), 7 content clumps, human-bridge
259
259
  // (the cross-ontology showcase). "Breadth over depth" throughout, per the
260
260
  // operator's explicit instruction — flat one-hop IsA facts, no gender/
261
261
  // kinship taxonomy, no formal role hierarchy.
262
262
  human: {
263
263
  kind: "domain",
264
- description: "The default human-world persona (PLAN_SEED.md): everyday people, places, objects, nature, time/events, body/food and mind vocabulary, hand-curated from Open English WordNet (CC-BY-4.0) and bridged to Schema.org's (Apache-2.0) top-level classes — replaces the code-domain SEON+ConceptNet default.",
264
+ description: "The default human-world persona: everyday people, places, objects, nature, time/events, body/food and mind vocabulary, hand-curated from Open English WordNet (CC-BY-4.0) and bridged to Schema.org's (Apache-2.0) top-level classes — replaces the code-domain SEON+ConceptNet default.",
265
265
  // Every noun/verb/adjective this corpus's facts depend on, so a live
266
266
  // sentence built from the SAME curated vocabulary ("a man has a hat") can
267
267
  // actually parse — src/domain/grammar/lexicon-core.json carries the real
268
- // entries (PLAN_SEED.md §4's "two vocabulary surfaces", gated
268
+ // entries (a second vocabulary surface, gated
269
269
  // independently); this list is the --verify drift-guard's source of
270
270
  // truth (below), not a second copy of the lexicon file itself.
271
271
  lexicon: {
@@ -351,9 +351,9 @@ export const CORPUSES = {
351
351
  // ---- human-base (scaffolding, ~18 facts) — the top-level category
352
352
  // classes, `rdfs:subClassOf` children of a "schema thing" concept
353
353
  // representing Schema.org's real `:Thing` root (hand-authored in
354
- // homage to schema.org/Thing's shape — PLAN_SEED.md §5 — never a
354
+ // homage to schema.org/Thing's shape, never a
355
355
  // verbatim copy of Schema.org's own class definitions/comments).
356
- // Always active regardless of tier (PLAN_SEED.md §3).
356
+ // Always active regardless of tier.
357
357
  ["schema_person", "/r/IsA", "schema_thing"],
358
358
  ["schema_place", "/r/IsA", "schema_thing"],
359
359
  ["schema_object", "/r/IsA", "schema_thing"],
@@ -681,8 +681,8 @@ export const CORPUSES = {
681
681
  ["smile", "/r/CapableOf", "show_happiness"], ["smile", "/r/PartOf", "a_face"],
682
682
  ["silence", "/r/HasProperty", "quiet"], ["silence", "/r/CapableOf", "calm_the_mind"],
683
683
 
684
- // ---- human-bridge (~10 facts) — the cross-ontology showcase
685
- // (PLAN_SEED.md §8): a WordNet-side root/common term paired with its
684
+ // ---- human-bridge (~10 facts) — the cross-ontology showcase:
685
+ // a WordNet-side root/common term paired with its
686
686
  // Schema.org-inspired counterpart from human-base, above. scm-sco
687
687
  // (src/domain/syllogise.mjs, unmodified) proves a chain spanning both
688
688
  // sources once a WordNet-side ⊑-chain reaches one of these —
@@ -700,20 +700,20 @@ export const CORPUSES = {
700
700
  ],
701
701
  },
702
702
  // Medium tier — INCREMENTAL facts beyond Small (corpus/tier2/human.jsonl) only
703
- // (PLAN_SEED.md §3's tier-selection design: Small/Medium/Large are SIZES of
703
+ // (Small/Medium/Large are SIZES of
704
704
  // one bundle, not separate corpus ids — this file holds only what Medium
705
705
  // ADDS beyond the previous tier). Built by scripts/build-persona-tiers.mjs
706
706
  // from the same two locally-cloned WordNet source files as Small
707
707
  // (~/projects/globalwordnet/english-wordnet/src/yaml/), automatically
708
708
  // curated: candidate words ranked by WordNet sense-count (a commonness
709
- // proxy, PLAN_SEED.md §12), restricted to each word's own TOP senses (not
709
+ // proxy), restricted to each word's own TOP senses (not
710
710
  // some rare/slang meaning that happens to live in this domain), obscure/
711
711
  // archaic/offensive/pharmaceutical content excluded via a definition-text
712
712
  // blocklist plus an explicit word denylist, reviewed by hand before being
713
713
  // spliced in here (scripts/apply-persona-tiers.mjs). Medium stays flat, one hop per word, same style as Small.
714
714
  "human-medium": {
715
715
  kind: "domain",
716
- description: "The Medium tier of the default human-world persona (PLAN_SEED.md): incremental facts beyond Small only — activated alongside \"human\" via --persona-size medium, never active by default.",
716
+ description: "The Medium tier of the default human-world persona: incremental facts beyond Small only — activated alongside \"human\" via --persona-size medium, never active by default.",
717
717
  lexicon: {
718
718
  nouns: [
719
719
  // human-core (+186 words: people, family, common roles)
@@ -1800,20 +1800,20 @@ export const CORPUSES = {
1800
1800
  },
1801
1801
 
1802
1802
  // Large tier — INCREMENTAL facts beyond Medium (corpus/tier2/human-medium.jsonl) only
1803
- // (PLAN_SEED.md §3's tier-selection design: Small/Medium/Large are SIZES of
1803
+ // (Small/Medium/Large are SIZES of
1804
1804
  // one bundle, not separate corpus ids — this file holds only what Large
1805
1805
  // ADDS beyond the previous tier). Built by scripts/build-persona-tiers.mjs
1806
1806
  // from the same two locally-cloned WordNet source files as Small
1807
1807
  // (~/projects/globalwordnet/english-wordnet/src/yaml/), automatically
1808
1808
  // curated: candidate words ranked by WordNet sense-count (a commonness
1809
- // proxy, PLAN_SEED.md §12), restricted to each word's own TOP senses (not
1809
+ // proxy), restricted to each word's own TOP senses (not
1810
1810
  // some rare/slang meaning that happens to live in this domain), obscure/
1811
1811
  // archaic/offensive/pharmaceutical content excluded via a definition-text
1812
1812
  // blocklist plus an explicit word denylist, reviewed by hand before being
1813
- // spliced in here (scripts/apply-persona-tiers.mjs). Large's own facts walk real multi-hop hypernym chains (up to 4 hops, PLAN_SEED.md §3's own "surgeon ⊑ doctor ⊑ … ⊑ person" example) wherever WordNet's real structure supports it, not a flat one-hop-per-word cap.
1813
+ // spliced in here (scripts/apply-persona-tiers.mjs). Large's own facts walk real multi-hop hypernym chains (up to 4 hops, e.g. "surgeon ⊑ doctor ⊑ … ⊑ person") wherever WordNet's real structure supports it, not a flat one-hop-per-word cap.
1814
1814
  "human-large": {
1815
1815
  kind: "domain",
1816
- description: "The Large tier of the default human-world persona (PLAN_SEED.md): incremental facts beyond Medium only — activated alongside \"human\" via --persona-size large, never active by default.",
1816
+ description: "The Large tier of the default human-world persona: incremental facts beyond Medium only — activated alongside \"human\" via --persona-size large, never active by default.",
1817
1817
  lexicon: {
1818
1818
  nouns: [
1819
1819
  // human-core (+1469 words: people, family, common roles)
@@ -14881,8 +14881,8 @@ export async function fetchCorpus(url, expectedSha) {
14881
14881
 
14882
14882
  /**
14883
14883
  * Alignment drift-guard for a corpus entry that declares an optional
14884
- * `lexicon` sub-key (today: only `human` — PLAN_SEED.md §4's "two vocabulary
14885
- * surfaces" seam): the corpus fact set and the ACE parser's closed-set
14884
+ * `lexicon` sub-key (today: only `human` — the two-vocabulary-surfaces
14885
+ * seam): the corpus fact set and the ACE parser's closed-set
14886
14886
  * vocabulary (src/domain/grammar/lexicon-core.json) are two SEPARATE files, gated
14887
14887
  * independently, so nothing stops them drifting apart over time. Two
14888
14888
  * directions, both real (mirroring conceptnet-map.toml's own "slice relation
@@ -61,7 +61,7 @@
61
61
  {
62
62
  "id": "human",
63
63
  "kind": "domain",
64
- "description": "The default human-world persona (PLAN_SEED.md): everyday people, places, objects, nature, time/events, body/food and mind vocabulary, hand-curated from Open English WordNet (CC-BY-4.0) and bridged to Schema.org's (Apache-2.0) top-level classes — replaces the code-domain SEON+ConceptNet default.",
64
+ "description": "The default human-world persona: everyday people, places, objects, nature, time/events, body/food and mind vocabulary, hand-curated from Open English WordNet (CC-BY-4.0) and bridged to Schema.org's (Apache-2.0) top-level classes — replaces the code-domain SEON+ConceptNet default.",
65
65
  "source": {
66
66
  "kind": "curated",
67
67
  "tool": "corpus/tier2/generate.mjs"
@@ -75,7 +75,7 @@
75
75
  {
76
76
  "id": "human-medium",
77
77
  "kind": "domain",
78
- "description": "The Medium tier of the default human-world persona (PLAN_SEED.md): incremental facts beyond Small only — activated alongside \"human\" via --persona-size medium, never active by default.",
78
+ "description": "The Medium tier of the default human-world persona: incremental facts beyond Small only — activated alongside \"human\" via --persona-size medium, never active by default.",
79
79
  "source": {
80
80
  "kind": "curated",
81
81
  "tool": "corpus/tier2/generate.mjs"
@@ -89,7 +89,7 @@
89
89
  {
90
90
  "id": "human-large",
91
91
  "kind": "domain",
92
- "description": "The Large tier of the default human-world persona (PLAN_SEED.md): incremental facts beyond Medium only — activated alongside \"human\" via --persona-size large, never active by default.",
92
+ "description": "The Large tier of the default human-world persona: incremental facts beyond Medium only — activated alongside \"human\" via --persona-size large, never active by default.",
93
93
  "source": {
94
94
  "kind": "curated",
95
95
  "tool": "corpus/tier2/generate.mjs"
@@ -5,8 +5,14 @@
5
5
  # the goal is that every disk rests on peg-c. solve it.
6
6
  #
7
7
  # Variations, each stretching a different direction:
8
- # scale — first teach: "disk-4 is a disk. disk-3 is smaller than disk-4."
9
- # start all four on peg-a, same goal. 15 moves (2^4 - 1).
8
+ # scale — first teach: "disk-4 is a disk."
9
+ # then: "disk-1 is smaller than disk-4. disk-2 is smaller than disk-4.
10
+ # disk-3 is smaller than disk-4."
11
+ # then: "disk-1 rests on disk-2. disk-2 rests on disk-3. disk-3 rests on
12
+ # disk-4. disk-4 rests on peg-a." — same goal. 15 moves (2^4 - 1).
13
+ # Every smaller-than pair is taught: the relation is stored as given and
14
+ # is not chased transitively, so disk-3 < disk-4 alone leaves disk-1 and
15
+ # disk-2 with no legal move onto disk-4 and no plan exists.
10
16
  # any start — disk-1 rests on peg-b. disk-2 rests on peg-c. disk-3 rests on peg-a.
11
17
  # the goal is that every disk rests on peg-c. solve it.
12
18
  # other goal — same start, "the goal is that every disk rests on peg-b. solve it."