Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
100 changes: 100 additions & 0 deletions docs/audit-message-idents-vms-916.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
# Message-ident authenticity audit (vms-916)

**Item:** vms-916 — "real VMS message idents, no invented ones" (authenticity Tier-0).
**Requires:** operator sign-off (D3) to close.
**Method (clean-room Rule 8):** every ident is marked `VERIFIED` (grounded to public
VSI/HP OpenVMS documentation, cited) or `OVMX-design` (labelled as OVMX's own, under
facility `OVMX`, because OpenVMS has no authentic equivalent for the exact condition).
No ident is presented as VMS-authentic without a citation.

The clearly-invented idents lived in the DCL queue/submit command handlers
(`src/vmsdcl/dcl_cmd_process.c`, `src/vmsdcl/dcl_cmd_file.c`) as inline
`dcl_error(facility, sev, ident, text)` string literals — NOT in the
`known_codes[]` / `msg_db[]` catalogs, so `sys$getmsg`/`sys$putmsg` never emitted them.

---

## 1. Replacement table — invented → real VMS (VERIFIED)

| Site(s) | Invented (before) | Real VMS (after) | Provenance |
|---|---|---|---|
| SUBMIT / PRINT / SHOW QUEUE / SHOW ENTRY / SET ENTRY / SET QUEUE / DELETE-ENTRY queue-manager-unavailable path | `%<CMD>-E-QMANERR, queue manager initialization failed` | `%JBC-E-JOBQUEDIS, system job queue manager is not running` | JBC facility. VSI/HP OpenVMS *System Messages and Recovery Procedures Reference Manual* (JBC); corroborated by the queue-manager troubleshooting entries in the *OpenVMS System Manager's Manual* (Ch. "Managing the Queue Manager"), and field transcripts on comp.os.vms / HPE OpenVMS forum showing `%JBC-E-JOBQUEDIS, system job queue manager is not running`. This is the message a real system returns when a queue operation is attempted and the queue manager is not running — the exact user-visible condition OVMX's `ensure_queue_init()` failure stands for. |
| SUBMIT failure (`vmsq_submit` → `SS$_ITEMNOTFOUND`) | `%SUBMIT-E-SUBMITERR, failed to submit job to queue <q>` | `%JBC-E-NOSUCHQUE, no such queue - <q>` | JBC facility. Dominant failure of `vmsq_submit` is "target queue does not exist" (`find_queue_slot() < 0`). `%JBC-E-NOSUCHQUE, no such queue` is documented in the *OpenVMS System Manager's Manual* queue chapter and DCL Dictionary examples. |
| PRINT failure (same path) | `%PRINT-E-PRINTERR, failed to queue file to <q>` | `%JBC-E-NOSUCHQUE, no such queue - <q>` | As above. |
| SHOW QUEUE / SET QUEUE nonexistent-queue check | `%SHOW-E-NOSUCHQUE` / `%SET-E-NOSUCHQUE, no such queue - <q>` | facility corrected → `%JBC-E-NOSUCHQUE, no such queue - <q>` | The ident/text were already real; only the FACILITY was wrong. On VMS this condition is raised by the queue service and rendered under JBC, not the DCL command verb. |
| SET ENTRY / SHOW ENTRY entry-not-found | `%<CMD>-E-ENTNOTFND, entry <n> not found` | `%JBC-E-NOSUCHENT, no such entry` | JBC facility. See DELETE/ENTRY citation below. Emitted as a standalone primary line here; on VMS `JBC$_NOSUCHENT` renders identically (`F$MESSAGE`), the `%`-vs-`-` prefix being a primary/continuation positional detail, not part of the ident text. |
| DELETE/ENTRY entry-not-found | `%DELETE-E-ENTNOTFND, entry <n> not found` | two-line faithful chain: `%DELETE-W-SEARCHFAIL, error searching for <n>` + `-JBC-E-NOSUCHENT, no such entry` | Verbatim from the VSI/HP *OpenVMS DCL Dictionary*, DELETE/ENTRY entry (digiater.nl / HPE `9996pro_53.html`; VSI OpenVMS wiki DELETE/ENTRY): a DELETE/ENTRY of a completed/absent entry prints `%DELETE-W-SEARCHFAIL, error searching for 203` chained with `-JBC-E-NOSUCHENT, no such entry`. Severity of SEARCHFAIL is `W`. |
| DELETE/ENTRY & SET ENTRY & SET QUEUE missing required value | `%DCL-E-NOENTRY, missing entry number...` / `%SET-E-NOQUNAM, missing queue name` | `%DCL-W-INSFPRM, missing command parameters - supply all required parameters` | Real DCL parser message for an absent required parameter. VSI/HP *OpenVMS System Messages* (DCL facility): `%DCL-W-INSFPRM, missing command parameters - supply all required parameters`. Severity `W`. (On a real terminal DCL would prompt for the value; OVMX does not reach the CLD prompt on these paths, so it emits the batch-mode message.) |

**Facility note:** `JBC` (Job Controller) is the OpenVMS facility that owns queue/batch/print
condition values (`$JBCMSGDEF`). Routing these through `JBC` — rather than the DCL command
verb — is what a real system does: the verb's handler calls `$SNDJBC`/`$GETQUI`, which return
JBC condition values, and the handler `PUTMSG`s them.

## 2. OVMX-design idents (LABELLED — never presented as VMS)

These conditions have no VMS-authentic ident for the exact OVMX code path, so they are
emitted under facility `OVMX` (OVMX's customer-facility convention — see
`src/libvms/include/ovmx_status.h` and `sys_msg.c` `facility_name()`), so no reader can
mistake them for a SYSTEM/JBC condition.

| Site | Ident (after) | Why OVMX-design |
|---|---|---|
| SET ENTRY / SHOW ENTRY / DELETE-ENTRY, non-numeric entry value | `%OVMX-E-IVENTNUM, invalid entry number - <s>` | On real VMS a non-numeric `/ENTRY=` value is rejected by the CLD command parser (a `%CLI-`/`%DCL-` parse-time diagnostic), a path OVMX's hand-rolled handler does not reproduce. Rather than borrow a real ident whose exact wording/facility for this case is not documented, the OVMX validation error is labelled as OVMX's own. |
| SET QUEUE /STOP,/START,/PAUSE state-change write fault | `%OVMX-E-QUESETERR, failed to <op> queue <q>` | Reached only after the queue is confirmed to exist, i.e. an internal queue-database write/lock fault with no VMS-authentic analogue (VMS's queue state is held by the JOB_CONTROL process, not a flat file). Labelled OVMX-design. |

## 3. Success-message idents — FLAGGED for a follow-up (out of scope here)

The queue commands' SUCCESS lines use `%<CMD>-S-<ident>` idents that diverge from real
VMS, which prints plain, unprefixed text (e.g. `Job MYJOB (queue SYS$BATCH, entry 4)
started on SYS$BATCH` — VSI/HP OpenVMS DCL Dictionary, SUBMIT). Affected:
`%SUBMIT-S-SUBMITTED`, `%PRINT-S-QUEUED`, `%SET-S-MODIFIED`, `%SET-S-QUEMOD`,
`%DELETE-S-DELETED`.

These were **not changed in this PR** because (a) the item's Tier-0 target and anchors are
the ERROR idents, and (b) two currently-green gated tests key on this success FORMAT
(`tests/dcl/test_queue.sh`, `tests/dcl/test_print_submit_coverage.sh`), so changing the
success-line shape is a coordinated UX change that must update those tests in the same
commit. **Recommendation:** file a follow-up item to render queue success lines in the
plain VMS form and migrate the two tests together. This is a divergence in success-line
FORMAT, not a wrong error ident — a lower-severity, separable concern.

## 4. Broader catalog — already provenance-complete (no change needed)

- `src/libvms/status.c` `known_codes[]` (read by `sys$getmsg`/`sys$putmsg`): every row is
a real SS$_/RMS$_ condition; several carry `ORACLE-PINNED` provenance comments
(`vms-6a7`, `vms-68c`, `vms-9fc`, `vms-2a8`, DUPLNAM, ILLIOFUNC, …). The only non-VMS
rows are the four `OVMX$_` conditions, already carrying the customer-defined bit and
rendered under facility `OVMX`.
- `src/vmsdcl/dcl_messages.c` `msg_db[]`: DCL/COPY/DELETE/DIRECT/RMS/SYSTEM/SET/… idents
matching documented VMS message idents.
No invented ident presented as VMS-authentic remains in these catalogs.

## 5. Declaration repointing & citation apparatus (task item #3)

- **`sys_msg.c` OVMX-USERSPACE declarations already cite the live owner `vms-916`**
(`sys$getmsg (vms-916)`, `sys$putmsg (vms-916)`) — not the closed `vms-5b4`. The
`rd vms-5b4` text in the file header is the shared *register-header* line present in
every `src/libvms/syssvc/sys_*.c` and `src/vmsrms/rms_*.c` file; it names the item that
BUILT the register/gate, not a per-service citation. No repointing was required.
- **`tracking/rd-citations.tsv` + `tools/gen_rd_citations.py` no longer exist** — the
citation-ledger apparatus was torn down by operator ruling `vms-dc7` (2026-08-06; see
the note in top-level `CMakeLists.txt` where `rd_citations_fresh`/`gen_rd_citations.py`
are recorded as removed). There is nothing to regenerate; recreating it would revert an
operator ruling.

## 6. Test evidence

`tests/dcl/test_queue_messages.sh` (added) drives the three real failure paths and asserts
the REAL VMS text is emitted and the invented idents are GONE:
- queue manager unavailable → `%JBC-E-JOBQUEDIS`
- SUBMIT/PRINT to a nonexistent queue → `%JBC-E-NOSUCHQUE`
- DELETE/ENTRY of a nonexistent entry → `%DELETE-W-SEARCHFAIL` + `-JBC-E-NOSUCHENT`
- `EXPECT_NOT` guards for `QMANERR`, `SUBMITERR`, `PRINTERR`, `ENTNOTFND`.

## Sources (public OpenVMS documentation)

- VSI OpenVMS *System Messages and Recovery Procedures Reference Manual* (M–Z), docs.vmssoftware.com.
- VSI/HP OpenVMS *DCL Dictionary* — DELETE/ENTRY and SUBMIT entries (digiater.nl mirror `9996pro_53.html`; VSI OpenVMS wiki DELETE/ENTRY).
- *OpenVMS System Manager's Manual* — Managing the Queue Manager (sysworks/mi.infn.it mirrors).
- Field transcripts confirming `%JBC-E-JOBQUEDIS, system job queue manager is not running` (HPE OpenVMS community; comp.os.vms).
19 changes: 15 additions & 4 deletions src/vmsdcl/dcl_cmd_file.c
Original file line number Diff line number Diff line change
Expand Up @@ -1490,24 +1490,35 @@ int cmd_delete(struct dcl_command *cmd)
if (dcl_has_qualifier(cmd, "ENTRY")) {
const char *entry_str = dcl_qualifier_value(cmd, "ENTRY");
if (!entry_str || !entry_str[0]) {
dcl_error("DCL", 2, "NOENTRY", "missing entry number with /ENTRY");
dcl_error("DCL", 0, "INSFPRM",
"missing command parameters - supply all required parameters");
return SS$_BADPARAM;
}
char *endptr;
long entry_val = strtol(entry_str, &endptr, 10);
if (endptr == entry_str || *endptr != '\0' || entry_val <= 0) {
dcl_error("DCL", 2, "BADENTRY", "invalid entry number - %s", entry_str);
dcl_error("OVMX", 2, "IVENTNUM", "invalid entry number - %s", entry_str);
return SS$_BADPARAM;
}
uint32_t entry_id = (uint32_t)entry_val;
int qsts = ensure_queue_init();
if (!(qsts & 1)) {
dcl_error("DELETE", 2, "QMANERR", "queue manager initialization failed");
dcl_error("JBC", 2, "JOBQUEDIS", "system job queue manager is not running");
return qsts;
}
qsts = vmsq_delete_entry(entry_id);
if (!(qsts & 1)) {
dcl_error("DELETE", 2, "ENTNOTFND", "entry %u not found", entry_id);
/* Faithful two-line VMS rendering: a DELETE/ENTRY of a nonexistent
* entry prints the command-facility primary chained with the JBC
* secondary, exactly as the VSI OpenVMS DCL Dictionary DELETE/ENTRY
* example shows (see docs/audit-message-idents-vms-916.md):
* %DELETE-W-SEARCHFAIL, error searching for <n>
* -JBC-E-NOSUCHENT, no such entry
* The '-' continuation prefix is VMS's, not '%', so it is emitted
* directly rather than through dcl_error() (which always writes a
* primary '%' line). */
dcl_error("DELETE", 0, "SEARCHFAIL", "error searching for %u", entry_id);
fprintf(stderr, "-JBC-E-NOSUCHENT, no such entry\n");
return qsts;
}
printf("%%DELETE-S-DELETED, entry %u deleted\n", entry_id);
Expand Down
61 changes: 39 additions & 22 deletions src/vmsdcl/dcl_cmd_process.c
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,23 @@ int cmd_wait(struct dcl_command *cmd)
return SS$_NORMAL;
}
/*
* Queue message idents (vms-916, authenticity Tier-0). The queue/submit
* commands below emit REAL VSI OpenVMS message idents from the JBC (Job
* Controller / queue) facility, NOT the invented QMANERR/SUBMITERR/PRINTERR/
* ENTNOTFND idents that used to sit here. Grounded to public VSI OpenVMS
* documentation (clean-room Rule 8); the ident-by-ident table with citations
* is docs/audit-message-idents-vms-916.md. Summary:
* queue manager unavailable -> %JBC-E-JOBQUEDIS, system job queue manager
* is not running
* no such queue -> %JBC-E-NOSUCHQUE, no such queue
* no such queue entry -> %JBC-E-NOSUCHENT, no such entry
* (DELETE/ENTRY chains %DELETE-W-SEARCHFAIL)
* missing required parameter -> %DCL-W-INSFPRM, missing command parameters
* Two idents have no VMS-authentic equivalent and are LABELLED OVMX-design so
* no reader mistakes them for VMS: %OVMX-E-IVENTNUM (a non-numeric entry value,
* which real VMS rejects in the CLD parser OVMX does not reach here) and
* %OVMX-E-QUESETERR (an internal queue-state write fault).
*
* Queue initialization helper — ensures QMAN$MASTER.DAT exists and
* default queues (SYS$BATCH, SYS$PRINT) are created.
* Called lazily on first queue command.
Expand Down Expand Up @@ -156,7 +173,7 @@ int cmd_submit(struct dcl_command *cmd)

int sts = ensure_queue_init();
if (!(sts & 1)) {
dcl_error("SUBMIT", 2, "QMANERR", "queue manager initialization failed");
dcl_error("JBC", 2, "JOBQUEDIS", "system job queue manager is not running");
return sts;
}

Expand Down Expand Up @@ -212,8 +229,7 @@ int cmd_submit(struct dcl_command *cmd)
uint32_t entry_id = 0;
sts = vmsq_submit(queue_name, upper_name, user, &entry_id);
if (!(sts & 1)) {
dcl_error("SUBMIT", 2, "SUBMITERR", "failed to submit job to queue %s",
queue_name);
dcl_error("JBC", 2, "NOSUCHQUE", "no such queue - %s", queue_name);
return sts;
}

Expand Down Expand Up @@ -259,7 +275,7 @@ int cmd_print(struct dcl_command *cmd)

int sts = ensure_queue_init();
if (!(sts & 1)) {
dcl_error("PRINT", 2, "QMANERR", "queue manager initialization failed");
dcl_error("JBC", 2, "JOBQUEDIS", "system job queue manager is not running");
return sts;
}

Expand Down Expand Up @@ -305,8 +321,7 @@ int cmd_print(struct dcl_command *cmd)
uint32_t entry_id = 0;
sts = vmsq_submit(queue_name, upper_name, user, &entry_id);
if (!(sts & 1)) {
dcl_error("PRINT", 2, "PRINTERR", "failed to queue file to %s",
queue_name);
dcl_error("JBC", 2, "NOSUCHQUE", "no such queue - %s", queue_name);
return sts;
}

Expand All @@ -333,7 +348,7 @@ int cmd_show_queue(struct dcl_command *cmd)
{
int sts = ensure_queue_init();
if (!(sts & 1)) {
dcl_error("SHOW", 2, "QMANERR", "queue manager initialization failed");
dcl_error("JBC", 2, "JOBQUEDIS", "system job queue manager is not running");
return sts;
}

Expand All @@ -350,7 +365,7 @@ int cmd_show_queue(struct dcl_command *cmd)
struct vms_queue qinfo;
sts = vmsq_show_queue(queue_name, &qinfo);
if (!(sts & 1)) {
dcl_error("SHOW", 2, "NOSUCHQUE", "no such queue - %s", queue_name);
dcl_error("JBC", 2, "NOSUCHQUE", "no such queue - %s", queue_name);
return sts;
}

Expand Down Expand Up @@ -423,35 +438,36 @@ int cmd_set_entry(struct dcl_command *cmd)
{
int sts = ensure_queue_init();
if (!(sts & 1)) {
dcl_error("SET", 2, "QMANERR", "queue manager initialization failed");
dcl_error("JBC", 2, "JOBQUEDIS", "system job queue manager is not running");
return sts;
}

/* Entry number is params[1] (params[0] is "ENTRY") */
if (cmd->param_count < 2 || cmd->params[1][0] == '\0') {
dcl_error("SET", 2, "NOENTRY", "missing entry number");
dcl_error("DCL", 0, "INSFPRM",
"missing command parameters - supply all required parameters");
return SS$_BADPARAM;
}

char *endptr;
long entry_val = strtol(cmd->params[1], &endptr, 10);
if (endptr == cmd->params[1] || *endptr != '\0' || entry_val <= 0) {
dcl_error("SET", 2, "BADENTRY", "invalid entry number - %s", cmd->params[1]);
dcl_error("OVMX", 2, "IVENTNUM", "invalid entry number - %s", cmd->params[1]);
return SS$_BADPARAM;
}
uint32_t entry_id = (uint32_t)entry_val;

if (dcl_has_qualifier(cmd, "HOLD")) {
sts = vmsq_hold_entry(entry_id);
if (!(sts & 1)) {
dcl_error("SET", 2, "ENTNOTFND", "entry %u not found", entry_id);
dcl_error("JBC", 2, "NOSUCHENT", "no such entry");
return sts;
}
printf("%%SET-S-MODIFIED, entry %u set to HOLD\n", entry_id);
} else if (dcl_has_qualifier(cmd, "RELEASE")) {
sts = vmsq_release_entry(entry_id);
if (!(sts & 1)) {
dcl_error("SET", 2, "ENTNOTFND", "entry %u not found", entry_id);
dcl_error("JBC", 2, "NOSUCHENT", "no such entry");
return sts;
}
printf("%%SET-S-MODIFIED, entry %u released\n", entry_id);
Expand All @@ -473,7 +489,7 @@ int cmd_show_entry(struct dcl_command *cmd)
{
int sts = ensure_queue_init();
if (!(sts & 1)) {
dcl_error("SHOW", 2, "QMANERR", "queue manager initialization failed");
dcl_error("JBC", 2, "JOBQUEDIS", "system job queue manager is not running");
return sts;
}

Expand All @@ -486,7 +502,7 @@ int cmd_show_entry(struct dcl_command *cmd)
char *endptr;
long entry_val = strtol(cmd->params[1], &endptr, 10);
if (endptr == cmd->params[1] || *endptr != '\0' || entry_val <= 0) {
dcl_error("SHOW", 2, "BADENTRY", "invalid entry number - %s",
dcl_error("OVMX", 2, "IVENTNUM", "invalid entry number - %s",
cmd->params[1]);
return SS$_BADPARAM;
}
Expand All @@ -495,7 +511,7 @@ int cmd_show_entry(struct dcl_command *cmd)
struct vms_queue_entry entry;
sts = vmsq_show_entry(entry_id, &entry);
if (!(sts & 1)) {
dcl_error("SHOW", 2, "ENTNOTFND", "entry %u not found", entry_id);
dcl_error("JBC", 2, "NOSUCHENT", "no such entry");
return sts;
}

Expand Down Expand Up @@ -579,13 +595,14 @@ int cmd_set_queue(struct dcl_command *cmd)
{
int sts = ensure_queue_init();
if (!(sts & 1)) {
dcl_error("SET", 2, "QMANERR", "queue manager initialization failed");
dcl_error("JBC", 2, "JOBQUEDIS", "system job queue manager is not running");
return sts;
}

/* Queue name is params[1] (params[0] is "QUEUE") */
if (cmd->param_count < 2 || cmd->params[1][0] == '\0') {
dcl_error("SET", 2, "NOQUNAM", "missing queue name");
dcl_error("DCL", 0, "INSFPRM",
"missing command parameters - supply all required parameters");
return SS$_BADPARAM;
}

Expand All @@ -595,28 +612,28 @@ int cmd_set_queue(struct dcl_command *cmd)
struct vms_queue qinfo;
sts = vmsq_show_queue(queue_name, &qinfo);
if (!(sts & 1)) {
dcl_error("SET", 2, "NOSUCHQUE", "no such queue - %s", queue_name);
dcl_error("JBC", 2, "NOSUCHQUE", "no such queue - %s", queue_name);
return sts;
}

if (dcl_has_qualifier(cmd, "STOP")) {
sts = vmsq_set_queue_status(queue_name, VMSQ_STATUS_STOPPED);
if (!(sts & 1)) {
dcl_error("SET", 2, "QMANERR", "failed to stop queue %s", queue_name);
dcl_error("OVMX", 2, "QUESETERR", "failed to stop queue %s", queue_name);
return sts;
}
printf("%%SET-S-QUEMOD, queue %s stopped\n", queue_name);
} else if (dcl_has_qualifier(cmd, "START")) {
sts = vmsq_set_queue_status(queue_name, VMSQ_STATUS_STARTED);
if (!(sts & 1)) {
dcl_error("SET", 2, "QMANERR", "failed to start queue %s", queue_name);
dcl_error("OVMX", 2, "QUESETERR", "failed to start queue %s", queue_name);
return sts;
}
printf("%%SET-S-QUEMOD, queue %s started\n", queue_name);
} else if (dcl_has_qualifier(cmd, "PAUSE")) {
sts = vmsq_set_queue_status(queue_name, VMSQ_STATUS_PAUSED);
if (!(sts & 1)) {
dcl_error("SET", 2, "QMANERR", "failed to pause queue %s", queue_name);
dcl_error("OVMX", 2, "QUESETERR", "failed to pause queue %s", queue_name);
return sts;
}
printf("%%SET-S-QUEMOD, queue %s paused\n", queue_name);
Expand Down
Loading
Loading