Summary
set-field accepts an invocation that combines both of its documented, mutually exclusive forms — --option-id <id> and a positional value — and resolves it to an option that is neither inert nor the requested one. It exits 0. Nothing on stdout or stderr indicates a problem.
The severity is not the wrong write itself but its shape: the value that landed was a plausible sibling option, so it reads as intentional to a human reviewing the node afterwards. A no-op leaves a visible gap; this leaves a confident, wrong answer.
Observed
On a #task node whose ☑️ STATUS field (7mbhvC0_YEcA) has these options:
| Option |
Id |
✅ Completed |
gUMBCHgDKvj9 |
❌ Dropped |
-MG-UldK1Pn2 |
this argv:
set-field --field-id 7mbhvC0_YEcA --option-id gUMBCHgDKvj9 -- <nodeId> 7mbhvC0_YEcA "✅ Completed"
exited 0, and the field was left holding ❌ Dropped (-MG-UldK1Pn2) — not the requested gUMBCHgDKvj9.
Expected
Either the documented precedence is honoured (--option-id wins), or — better — the ambiguous invocation is rejected with a non-zero exit, since the README defines the two forms as alternatives rather than composable:
supertag set-field <nodeId> <attributeId> "value"
supertag set-field <nodeId> <attributeId> --option-id <optionId>
(README, "MUTATE — Edit Existing Nodes".) The option form takes no third positional, so supplying one alongside --option-id is a caller error that is currently absorbed rather than surfaced.
I'd argue rejection is the right fix rather than a documented precedence: any precedence rule still silently discards half of what the caller asked for, and the failure mode here is a wrong value written to a user's graph.
Minimal repro
# Pick any options-type field and two of its option ids.
supertag set-field --field-id <fieldId> --option-id <optionA> -- <nodeId> <fieldId> "<label of optionA>"
supertag read <nodeId> # field holds neither reliably; observed: a third option
Provenance — what I verified and what I didn't
Being explicit, because it bears on how you triage this:
- Verified. The argv above is exact — it is constructed by a wrapper whose source I control, and the resulting state was read back from the graph. The write was recorded as successful by the wrapper because the process exited
0.
- Not verified. I have not reproduced this by invoking the CLI directly at a shell, and I have not determined why
-MG-UldK1Pn2 was chosen. I am deliberately not asserting a mechanism (positional-beats-flag, label fuzzy-matching, index arithmetic) — the binary is compiled and I had no way to inspect the resolution path. The reproducible, actionable fact is that the combined invocation is accepted and does not honour --option-id.
I have since changed my wrapper to never emit a positional value alongside --option-id, which resolves it on my side. Filing because the ambiguous invocation is silently accepted for everyone.
Two smaller things found alongside
1. --field-id is undocumented. The README shows <attributeId> as a positional only, but --field-id <id> is accepted and is in practice the only reliable way to target a field — by name, set-field fails with NODE_NOT_FOUND against a field-scoped URL:
Resource not found: http://127.0.0.1:8262/nodes/<node>/fields/<FieldName>/content
Worth documenting, or making the name path work.
2. Dash-leading ids as flag values — unverified, flagging in case it's the same class. Tana option and node ids can begin with - (❌ Dropped above is -MG-UldK1Pn2). I already hit a confirmed instance of this class with positionals: a node id -P11YGvsvmBb passed as a bare positional produced error: unknown option '-P11YGvsvmBb' from the commander parser, which I work around by placing all positionals after --. I have not tested whether --option-id -MG-UldK1Pn2 (space form) hits the same parser behaviour — I moved to --option-id=-MG-UldK1Pn2 (equals form), which works. If the space form does mis-parse, then ❌ Dropped-style options are unsettable by id without the = spelling, which is worth a README note either way.
Environment
Summary
set-fieldaccepts an invocation that combines both of its documented, mutually exclusive forms —--option-id <id>and a positionalvalue— and resolves it to an option that is neither inert nor the requested one. It exits0. Nothing on stdout or stderr indicates a problem.The severity is not the wrong write itself but its shape: the value that landed was a plausible sibling option, so it reads as intentional to a human reviewing the node afterwards. A no-op leaves a visible gap; this leaves a confident, wrong answer.
Observed
On a
#tasknode whose☑️ STATUSfield (7mbhvC0_YEcA) has these options:✅ CompletedgUMBCHgDKvj9❌ Dropped-MG-UldK1Pn2this argv:
exited
0, and the field was left holding❌ Dropped(-MG-UldK1Pn2) — not the requestedgUMBCHgDKvj9.Expected
Either the documented precedence is honoured (
--option-idwins), or — better — the ambiguous invocation is rejected with a non-zero exit, since the README defines the two forms as alternatives rather than composable:(README, "MUTATE — Edit Existing Nodes".) The option form takes no third positional, so supplying one alongside
--option-idis a caller error that is currently absorbed rather than surfaced.I'd argue rejection is the right fix rather than a documented precedence: any precedence rule still silently discards half of what the caller asked for, and the failure mode here is a wrong value written to a user's graph.
Minimal repro
Provenance — what I verified and what I didn't
Being explicit, because it bears on how you triage this:
0.-MG-UldK1Pn2was chosen. I am deliberately not asserting a mechanism (positional-beats-flag, label fuzzy-matching, index arithmetic) — the binary is compiled and I had no way to inspect the resolution path. The reproducible, actionable fact is that the combined invocation is accepted and does not honour--option-id.I have since changed my wrapper to never emit a positional value alongside
--option-id, which resolves it on my side. Filing because the ambiguous invocation is silently accepted for everyone.Two smaller things found alongside
1.
--field-idis undocumented. The README shows<attributeId>as a positional only, but--field-id <id>is accepted and is in practice the only reliable way to target a field — by name,set-fieldfails withNODE_NOT_FOUNDagainst a field-scoped URL:Worth documenting, or making the name path work.
2. Dash-leading ids as flag values — unverified, flagging in case it's the same class. Tana option and node ids can begin with
-(❌ Droppedabove is-MG-UldK1Pn2). I already hit a confirmed instance of this class with positionals: a node id-P11YGvsvmBbpassed as a bare positional producederror: unknown option '-P11YGvsvmBb'from the commander parser, which I work around by placing all positionals after--. I have not tested whether--option-id -MG-UldK1Pn2(space form) hits the same parser behaviour — I moved to--option-id=-MG-UldK1Pn2(equals form), which works. If the space form does mis-parse, then❌ Dropped-style options are unsettable by id without the=spelling, which is worth a README note either way.Environment
v2.5.11(macOS, arm64), Tana Desktop Local API1.0.0, Tana1.523.0field_values) — that's the read path, this is the write path.