Skip to content

feat: approved modelling and checkable quotes - #47

Draft
david-hudec-networg wants to merge 10 commits into
TALXIS:masterfrom
david-hudec-networg:feat/proposed-model-elements
Draft

feat: approved modelling and checkable quotes#47
david-hudec-networg wants to merge 10 commits into
TALXIS:masterfrom
david-hudec-networg:feat/proposed-model-elements

Conversation

@david-hudec-networg

@david-hudec-networg david-hudec-networg commented Sep 8, 2026

Copy link
Copy Markdown

This is the improvements PR. It proposes a language change and amends a
recorded principle, so it is kept apart from
#46, which is bug fixes and should not
wait on a design debate.

Stacked on #46, so it shows that PR's commits too until it merges. The three
commits here are the last three.

One thesis: a workspace should be able to tell you what in it has been
approved, and let you check a quote against what was actually read.
Today it
can do neither.


Where this came from

[@TomasProkop], reading the consulting plugin:

jestli uz bychom nemeli vynucovat entity/document mapping uz v insights,
protoze tam jsou nejaky random orders ktery jsou ambiguous a nedavaji smysl

nemuzes to tam nechat agenta najebat tisice zmen naraz … HITL u kazde zmeny,
approve/deny/modify

Both land, and the gap is measurable. On the engagement that prompted this, a
stakeholder confirmed 185 insights one at a time. The model was then derived
from them in a single pass of 41 elements — and that pass decided things the
evidence had not: that two roles named separately in the sources are one actor,
that three ways of starting a request converge on one process, and which of
three things a word meant, every time the sources used it for all three.

Every element carried a valid derivedFrom. Not one of those decisions had
been reviewed
, and nothing in the workspace could tell you so. Traceability
and approval are different guarantees and the language had a field for one.


1. reviewStatus — approval of the modelling decision

proposed, accepted or rejected, on every element type that can cite
evidence
: actors, entities, processes, steps, KPIs, value streams,
capabilities, hypothesis nodes, hypothesis trees and glossary terms.

Every one, because a rule that skips a type is a rule with a hole in it — and
the types most likely to be skipped are where the judgement is largest. Framing
the whole problem is a hypothesis tree. Deciding that three words the sources
use interchangeably name one thing is a glossary term, and getting it wrong
renames things across every other document. Those four types gain derivedFrom
too: approval without provenance records that somebody agreed and not what to.

Absent means not specified, and nothing more (P4.4). Reading silence as
accepted would manufacture the false comfort this exists to remove.

A rejected element is kept, not deleted. The record that a decision was
considered and turned down is what stops it being proposed again next quarter.

DD-012 answers the two rules this appears to cross. P1.4 assigns
proposed-versus-current to folders and git — but its "current/proposed" are
as-is and to-be states of a process, two models of a business rather than one
model awaiting sign-off; the collision is on the word. DD-011 rejected a
stored maturity because completeness is computable from what is present.
Approval is not: no amount of reading a model reveals whether a person agreed.

2. file — the text a quote can be checked against

P12.2 keeps information out of the workspace, on the grounds of size. That holds
for the artifact and not for its text. Five meeting transcripts are under 150KB;
the recordings are three orders of magnitude larger.

The schema already had both fields and they were not being used as intended.
url names the artifact, file is the text stored beside the workspace, and
validate now enforces what file always meant: a URL there is an error naming
url instead, and a path resolving to nothing is an error, because a dangling
pointer looks like filed evidence and is not.

The check found one on this repository. The example workspace declared a
transcript that had never been written — in the one place a reader looks to
learn the convention. It is written now.

Conversion stays out of UBML, and the pipeline records which converter it used,
because a quote that reads oddly may be the speaker or may be the converter.

3. ubml walk — the two halves reviewed together

walk next shows a claim beside the elements it proposes; walk set records
either half, the id saying which decision is being made. Reviewing a claim
without the element it would create approves the extraction and leaves the
interpretation unasked.

It shows the element in full. A reviewer asked to approve "a term, called X"
can only approve a name.

status gains deferred. proposed was carrying two meanings — nobody has
looked at this yet, and somebody looked and could not settle it. Deferring is an
answer: the reviewer reached the claim and decided not to decide, usually
because confirming it needs somebody who was not in the room.


Does it work

It was run to completion on the engagement above: 70 of 70 elements reviewed,
one at a time, 69 accepted and one rejected.

The review changed the model rather than ratifying it. Two entities turned out
to be one thing in two roles. A process was split, because a monthly invoice is
not a late step in one customer's request. A step left the model entirely
because it happens outside the application. One glossary entry claimed the
sources named a thing they never mention. One was rejected outright as a
platform concern a business twin has no reason to carry — and kept, with the
reason, so it is not proposed again.

None of that was visible before the elements were walked one at a time. That is
the argument.

Every defect the run exposed is fixed in these commits rather than described in
a skill: block finding that assumed a fixed indent, a parent inheriting its
children's state, a template-literal escape resolved before RegExp saw it,
elements that state themselves in term or text rather than name, a
confirmation line that counted the wrong thing, and a hypothesis tree with no id
type — writable and validatable, but impossible to reference.

npm test: 293 passed, 3 skipped.

david-hudec-networg and others added 6 commits September 7, 2026 19:54
Each is independent of the others and of anything else; together they are what
can be fixed without touching how templates are generated.

The hypotheses tree used an {id, text, ...} node and array children where the
schema wants HY-keyed maps. The process wrote an id property inside the item,
where the ID is the key and Process declares none. Both scaffolds were teaching
a shape the bundled validator refuses, which is worse than being merely broken:
the natural reading is that the schema is stricter than the docs, so you hand-
write around a validator that was right.

The entities schema set templateDefaults.entities.type to "business-object".
Entity has no type property and sets additionalProperties: false, so that one
default was enough on its own to keep every scaffolded entities document
invalid.

Verified: hypotheses and process now scaffold and validate clean. entities
still fails on an unrelated defect - the generated templates carry no property
information at all - which is the next change in this series.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This is the defect behind most of the invalid scaffolds. One line in
transformTemplateData:

    properties: [],          // every section, every type

TemplateSection never carried properties and the transform hardcoded an empty
list, so TEMPLATE_DATA held nothing for anything. The scaffolder's default path
builds an item from section.properties.filter(required), which is always empty,
and writes a bare key:

    terms:
      TM01000:

TM01000: with an empty body parses as null, not an object, and validate rejects
a file add has just written. The types that looked healthy were the ones with a
hand-written example in items.ts; nothing else stood between the generator and
the output.

Extraction now finds the schema for one item of a section - patternProperties
for an ID-keyed map, items for a sequence, either inline or behind a $ref into
types/ - and records name, type, description, required, enum values and default.
resolveRef returns null rather than throwing on a shape it does not recognise,
so an unfamiliar reference degrades to the previous behaviour instead of
breaking generation.

Three things fell out of reading the schema properly. Reference placeholders
were always AC#####, whatever the field accepts, so a scaffolded step link
failed its own pattern check; the prefix now comes from the referenced
definition's own pattern, StepRef declaring ^ST\d{5,}$. Required array and
object properties were filled with the string 'TODO'. And section ID prefixes
were matched with [A-Z]{2}, so roiAnalyses (ROI#####) became RO#####.

Sequence sections are still written as maps after this; that is the next commit.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
links and glossary categories are YAML sequences in the schema, and the
scaffolder had one way of emitting a section, so it wrote them as maps keyed by
an ID that does not belong there.

They now scaffold as an empty list with the item shape in comments, rather than
as a sample row. A links item requires from and to, and any value there points
at step IDs the user has not created yet, so a populated sample fails
cross-reference validation the moment it is written. An empty list validates and
the comment still teaches the shape - including the correct reference prefix,
which the previous commit made available.

With this, every document type add can create scaffolds a document validate
accepts.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Asserts the property that was missing the whole time: scaffold a document of
each type, then validate the workspace it landed in.

It can fail. Rebuilt from pre-fix sources, all 13 cases fail; with the series
applied, all 13 pass.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three defects compounding, all of which made the answer wrong without saying so.

It wrote its own answer back to the cache, so asking what the next id would be
consumed it. Three calls in a row gave three answers, each higher. A query that
mutates the state it reports has no honest use.

writeIdStats kept only the larger of the cached and the supplied value, so a
scan could never lower a stale entry - which is precisely what syncids exists to
do. Reported "AC: 1020 -> 11" and wrote nothing.

And minStart was applied even when ids already existed, so a workspace numbered
from AC00001 was told its next actor was AC01000. That floor is documented as
the starting number for add templates; applying it to a continuation query
leaves a 989-wide hole and two disjoint ranges in one document.

The consequence was a command that printed Highest: AC00008 and Next ID: AC01020
one line apart and meant both. Following it numbers a model from another
branch's high-water mark.

Tests cover all three: the query is idempotent, a scan can lower a cached value,
and a continuation continues.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every other element type could cite the insights behind it. Strategy could not,
so a strategy document's provenance was prose the validator never saw - the one
document in a workspace where the pipeline's guarantee did not hold, and no way
to tell from inside it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@david-hudec-networg david-hudec-networg changed the title feat: model elements record whether their modelling decision was approved feat: make a workspace auditable - approved modelling, checkable quotes Sep 8, 2026
david-hudec-networg added a commit to david-hudec-networg/skills that referenced this pull request Sep 8, 2026
The skill said to verify a source's file pointer by hand when a source is added.
TALXIS/ubml#47 validates it, so the instruction was the workaround-in-prose this
plugin has been removing all along - it just happened to be describing a gap we
had since closed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Which insight is next, in the order the material was produced, with the source
text beside the claim and a position counter. And recording the answer once a
human has given one.

It stops at bookkeeping on purpose. Reading a reviewer's reply, judging whether
an ambiguous answer counts, noticing that a correction changed the meaning
rather than the wording - none of that is a CLI's job. The payload and the state
are mechanical; the judgement is not.

set rewrites one line rather than reserialising. A workspace is a document a
human is reading: its comments, its quoting and its line breaks are content, and
round-tripping them through the serializer would rewrite a file underneath the
reviewer. Tests cover it - one line changes, a comment survives, and setting a
status and setting it back returns the original bytes.

A restatement means a claim repeated from a source already walked, so it points
at an insight belonging to an earlier source. Counting every related link
instead would tell a reviewer "15 insights, 13 restating" on a workspace where
almost nothing restated - worse than silence, because the map exists so they can
pace themselves.

The ordering, the labelled blocks, evidence before claim, position ahead of
identity and the ID last were all prose in the consulting plugin's
validate-insights skill. They are assertions here now.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@david-hudec-networg
david-hudec-networg force-pushed the feat/proposed-model-elements branch 2 times, most recently from 447f8d1 to e4133c9 Compare September 8, 2026 07:11
david-hudec-networg added a commit to david-hudec-networg/skills that referenced this pull request Sep 8, 2026
U6 is fixed in TALXIS/ubml#47: walk next shows the elements a claim proposes and
walk set records either half. The skill described that format in prose because
the tool could not do it. It points at the command now.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@david-hudec-networg david-hudec-networg changed the title feat: make a workspace auditable - approved modelling, checkable quotes feat: approved modelling and checkable quotes Sep 8, 2026
@david-hudec-networg
david-hudec-networg force-pushed the feat/proposed-model-elements branch 9 times, most recently from ec35432 to 0c00113 Compare September 8, 2026 18:09
…oved

DD-008 gave elements `derivedFrom`, which closed traceability. It did not close
approval, and the two are different guarantees.

Running the pipeline end to end showed the gap. A stakeholder confirmed 185
insights one at a time; the model was then derived from them in a single pass of
41 elements, and that pass decided things the evidence had not - that two roles
named separately in the sources are one actor, that three ways of starting a
request converge on one process, and which of three things a word meant every
time the sources used it for all three. Every element carried a valid
`derivedFrom`. Not one of those decisions had been reviewed, and nothing in the
workspace could tell you so.

`reviewStatus` is `proposed`, `accepted` or `rejected`, on every element type
that can cite evidence. Every one: actors, entities, processes, steps, KPIs,
value streams, capabilities, hypothesis nodes, hypothesis trees and glossary
terms. A rule that skipped a type would be a rule with a hole in it, and the
types most likely to be skipped are the ones where the judgement is largest -
framing the problem, and deciding that three words name one thing.

Value streams, capabilities, hypothesis trees and glossary terms gain
`derivedFrom` too, because approval without provenance records that somebody
agreed and not what they agreed to.

A hypothesis node and tree already carry `status`, which reports whether the
hypothesis is turning out to be true. That is a different question from whether
anybody agreed to model it, and both are worth asking, so both fields are
present and the schema says which is which.

**Absent means not specified, and nothing more** (P4.4). Claiming that silence
means accepted would manufacture exactly the false comfort this decision exists
to remove, and P4.4 forbids it in its own words. Tooling that gates on approval
looks for an explicit `accepted`; tooling that surfaces unreviewed work looks
for an explicit `proposed`.

A rejected element is kept, not deleted. The record that a decision was
considered and turned down is what stops it being proposed again next quarter -
the same reasoning as a `disputed` insight.

DD-012 records the decision and answers the two rules it appears to cross. P1.4
assigns proposed-versus-current to folders and git, but its "current/proposed"
are as-is and to-be states of a process, two models of a business rather than
one model awaiting sign-off; the collision is on the word. DD-011 rejected a
stored `maturity` because completeness is computable from what is present -
approval is not, and no amount of reading a model reveals whether a person
agreed with it.
P12.2 says the workspace catalogs where information lives, not the information,
and names transcripts among what stays out. Its rationale is size, and that
holds for the artifact but not for its text.

A source entry exists so a claim can be checked against what was read. In one
engagement that check could not be made: the workspace pointed at a document
editable in place, so the evidence could drift under the model, and all five
sources held a URL in `file` - a property documented as a path relative to the
declaring document. Both validated cleanly.

Five meeting transcripts are under 150KB. The recordings they came from are
three orders of magnitude larger. The size argument was about the wrong noun.

The schema already had both fields, so nothing is added: `url` names the
artifact, `file` is the text stored beside the workspace, and `validate` now
enforces what `file` always meant. A URL there is an error naming `url`
instead; a path resolving to nothing is an error, because a dangling pointer
looks like filed evidence and is not. A source with no `file` stays valid - a
corridor conversation has no artifact.

Conversion stays out of UBML. Which tool gets text out of a document or a
recording depends on the format and is solved elsewhere; the pipeline picks, and
records which in `notes`, because a quote that reads oddly may be the speaker or
may be the converter and a reader cannot tell without being told.

The example workspace gains the transcript it always claimed to have. It
declared a `file` that was never written, which the new check caught on its own
repository - a dangling pointer in the one place a reader looks to learn the
convention.

DD-013 amends P12.2 in place. The cost it accepts is that source text moves into
git, and that is not a boundary the repo had already crossed: in that engagement
185 insights quote about 40,000 selected characters, while the transcripts hold
everything nobody chose to extract. Reach and erasure are both worse in git than
in a document store, so storing source text is a per-workspace decision the
workspace states, not a language-level default.
The tool recorded an insight's status and left the element's `reviewStatus` to
prose in a skill, which is the workaround-in-markdown this work has otherwise
been removing.

`walk next` now shows the elements a claim proposes, and `walk set` records
either half: the id says which decision is being made, so an insight takes
`validated`, `disputed` or `deferred` and an element takes `accepted` or
`rejected`. Reviewing a claim without the element it would create approves the
extraction and leaves the interpretation unasked, which is the failure the
change exists to stop.

It shows the element in full. A reviewer asked to approve "a term, called X"
can only approve a name; the definition, the attributes, what it relates to and
which claims it rests on were all still in the file. Every property is listed,
nested ones included, prose set as prose and ids picked out, so the answer is
about the content.

An insight can be reviewed and still not resolved, so `status` gains `deferred`.
`proposed` was carrying two meanings - nobody has looked at this yet, and
somebody looked and could not settle it. The walk reads the first, so a claim
held open on purpose is offered again every time and the review cannot get past
it. Deferring is an answer: the reviewer reached the claim and decided not to
decide, usually because confirming it needs somebody who was not in the room.
It is not `disputed`, which says the claim is contested.

A hypothesis tree gains an id type. Every prefix comes from a ref definition and
there was none for HT, so a tree could be written and validated but never
referenced, and anything resolving an id fell through to "element".

Elements carrying any `reviewStatus` are addressable, not only proposed ones: a
reviewer who accepts by mistake has to be able to say so. `next` still offers
only the unanswered.

Five defects came out of running it against a real workspace rather than a
fixture. A step lives inside a process, so the block finder cannot assume a
fixed indent, and a block must end at the next element id at any depth or a
parent inherits its children's state. An escape inside a template literal is
resolved before RegExp sees it. Not everything states itself in `name` - a
glossary entry uses `term`, a hypothesis node uses `text`. And the confirmation
line counted insights after an element was set, so the number never moved and
the command read as a no-op.
@david-hudec-networg
david-hudec-networg force-pushed the feat/proposed-model-elements branch from 0c00113 to 823165e Compare September 8, 2026 19:13
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