Skip to content

Make the interface answer the way the tools answer - #19

Merged
Elnazkarami merged 2 commits into
mainfrom
ndos-core
Sep 23, 2026
Merged

Elnazkarami merged 2 commits into
mainfrom
ndos-core

Conversation

@Elnazkarami

@Elnazkarami Elnazkarami commented Sep 23, 2026 •

Copy link
Copy Markdown
Owner

Follows #18, which is merged. Two things found by actually using the interface rather than assuming it worked.

The query page was giving a wrong answer

The page decided for itself which sessions matched, by comparing strings in the browser. A session whose species had never been entered compared unequal to mouse and was dropped — so it answered a question about missing evidence as though it were a question about contradicting evidence, and showed a cohort cleaner than the data supports.

That is the one mistake this project exists to prevent, and the page was making it.

It happened because the standard was implemented twice: once in Python, once in TypeScript. So the TypeScript is gone. The query runs where the rules live, and the page renders what comes back — matched, excluded, and cannot be ruled out — with the evidence that placed each session in its group.

On a real project:

considered 11 · matched 0 · excluded 0 · unresolved 11
"11 could not be ruled out because species was never entered."

The old page showed 0 of 11, which reads as none of these are mice. None of them are anything yet. Nobody has said.

Four endpoints, all read-only

open Read a JSON document by name, instead of making someone drag a file in — a workaround for a page that could not reach a disk
link Build a project's linked records in memory. table check --emit writes them to a file; nothing here needs that file to exist, so querying leaves the project untouched
check Check the metadata tables against each other — whether a procedure names an animal that exists. The entry form judges one value at a time and cannot see across three files
query The above

browse now offers files as well as folders, so a manifest is chosen the way a person refers to it: by name.

The other pages follow. Manifest opens from disk. Validate checks the tables a project already has, beside the form for entering what only a person knows. The home page no longer calls itself browser-only or promises that nothing leaves the browser — it reads drives now, and what it should promise is that nothing leaves the machine.

The progress the interface was meant to show

A scan reported a file count climbing towards nothing. progress asks for output on a terminal, which a page does not want — but it was also, silently, what decided whether the tree was walked up front to count the work. Passing progress=False and a callback, exactly what a page does, disabled the count and the estimate together.

before:  9,039/None files   39 MB/s   eta=None
after:   3,598/28,345 files 24 MB/s   eta=7.1s

One flag answering two questions, again. Three regression tests cover it; they fail with the fix reverted.

Also in here: picking a file rather than a folder returned a 500 showing the word ValueError to someone who had clicked the wrong thing — now a 400 in words. And the tab had no favicon, because the icon ships in the bundle but nothing referenced it.

Verified

Every page rendered in a real browser, headless: all four mount, every picker lists actual directories, and each endpoint answers over HTTP. A query nobody can parse comes back as words, not a stack trace.

353 → 364 tests. All ten CI jobs green.

Testing the interface against a real scan found three things.

A scan reported a file count that climbed towards nothing. `progress`
asks for output on a terminal, which the interface does not want, but it
was also -- silently -- what decided whether the tree was walked up front
to count the work. So passing `progress=False` and a callback, which is
exactly what a page does, disabled the count and the estimate together.
The page showed "9,039 files" with no total and no time left, on the
long scans that need both most. It now shows 3,598 of 28,345 and an ETA.

One flag was answering two questions again.

Picking a file rather than a folder returned a 500 and put the word
"ValueError" in front of someone who had simply clicked the wrong thing.
It is a 400 now, and says what is wrong in words.

And the page had no favicon: the icon ships in the bundle but nothing
referenced it, so the browser asked for /favicon.ico and the tab stayed
blank.

Verified in a real browser, headless: the page mounts, the folder picker
calls the server and lists actual directories, a scan runs to completion
with live progress, and a conformance check comes back with findings.
Every guard still refuses -- no token, wrong token, foreign Origin,
foreign Host.

350 -> 353 tests.
The query page decided for itself which sessions matched, by comparing
strings in the browser. A session whose species had never been entered
compared unequal to "mouse" and was dropped -- so the page answered a
question about missing evidence as though it were a question about
contradicting evidence, and showed a cohort cleaner than the data
supports. That is the one mistake this project exists to prevent, and
the page was making it.

It was making it because the standard was implemented twice: once in
Python, once in TypeScript. So the query now runs where the rules live.
The page sends constraints and renders what comes back: matched,
excluded, and cannot be ruled out, each session carrying the evidence
that placed it there, plus the diagnosis the command line prints -- "11
could not be ruled out because species was never entered."

On a real project that reads 0 matched, 0 excluded, 11 unresolved. The
old page would have shown "0 of 11", which reads as "none of these are
mice". None of them are anything yet. Nobody has said.

Four endpoints, all read-only:

  open    read a JSON document by name, rather than making someone drag
          a file onto the page -- a workaround for a page that could not
          reach a disk, which this one can
  link    build a project's linked records in memory. `table check
          --emit` writes them to a file; nothing here needs that file to
          exist, so querying a project leaves it untouched
  check   check the metadata tables against each other -- whether a
          procedure names an animal that exists. The entry form judges
          one value at a time and cannot see across three files
  query   the above

And browse can now offer files as well as folders, so a manifest is
chosen the way a person refers to it: by name.

The other pages follow. Manifest opens a file from disk. Validate checks
the tables a project already has, beside the form for entering what only
a person knows. The home page no longer calls itself browser-only or
promises that nothing leaves the browser: it reads drives now, and what
it should promise is that nothing leaves the machine.

Verified in a browser, headless: all four pages mount, every picker
lists real directories, and each endpoint answers over HTTP. A query
nobody can parse comes back as words, not a stack trace.

353 -> 364 tests.
@Elnazkarami Elnazkarami changed the title Ndos core Make the interface answer the way the tools answer Sep 23, 2026
@Elnazkarami
Elnazkarami merged commit 7e39d44 into main Sep 23, 2026
20 checks passed
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