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
28 changes: 14 additions & 14 deletions docs/DirectiveGrammarSpec.md
Original file line number Diff line number Diff line change
Expand Up @@ -333,11 +333,10 @@ Rules:

- must contain at least one non-whitespace character;
- may contain spaces and punctuation;
- is opaque payload: directive keywords, conjunctions, and multiple sentences
inside `VALUE` are not inspected as embedded directives;
- is opaque for semantic interpretation: the grammar does not infer meaning
from ordinary words or sentence content inside `VALUE`;
- has no quote-aware or escape-aware subgrammar;
- a separate canonical directive beginning on a new line is still rejected as
a compound attempt under Section 7.5.
- is subject to the compound-attempt rule in Section 7.5.

Canonical meaning:

Expand Down Expand Up @@ -455,23 +454,24 @@ contains more than one attempted directive clause. This includes inputs such
as:

- `use docker and prohibit peanuts`
- `set premise project deadline is Friday and use docker` is one premise directive; `VALUE` is
opaque and may contain policy words or conjunctions.
- `set premise project deadline is Friday and use docker`
- `set premise deployment target is staging, then use cautious rollout`
- `clear state then set premise new project`

This rule is lexical and grammar-level. It is not a semantic conflict rule.

Premise `VALUE` is payload rather than a policy identity. The grammar does not
inspect embedded directive words, conjunctions, or sentence boundaries inside
it. A separate canonical directive beginning on a new line is still treated as
a compound attempt. `ITEM` operands retain the compound-detection behavior
described above.
For any operand-bearing directive, a recognized directive starter at a token
boundary within the operand makes the full input a compound attempt, even when
ordinary whitespace is the only separator. This applies to premise `VALUE` and
policy `ITEM` operands; no `and`, `then`, punctuation, or newline is required.
It does not interpret natural-language meaning.

Examples:

- no_directive: `"use docker and prohibit peanuts"`
- directive-shaped invalid: `set premise users use SSO`
- directive-shaped invalid: `change premise to users prohibit password authentication`
- directive-shaped invalid: `use "docker and prohibit peanuts"`
- canonical directive: `set premise "use docker and prohibit peanuts"`
- directive-shaped invalid: `set premise "use docker and prohibit peanuts"`

## 8. Parsed Meaning and Semantic Boundary

Expand Down Expand Up @@ -773,7 +773,7 @@ source material for later conformance fixtures.
| `use docker and prohibit peanuts` | directive-shaped invalid input | none | compound attempt |
| `clear state then set premise project` | directive-shaped invalid input | none | compound attempt |
| `use "docker and prohibit peanuts"` | directive-shaped invalid input | none | quotes do not protect embedded directive text |
| `set premise "use docker and prohibit peanuts"` | canonical directive | set premise | premise `VALUE` is opaque payload, including quote characters |
| `set premise "use docker and prohibit peanuts"` | directive-shaped invalid | none | quotes do not protect embedded directive text |

## 12. Invariants

Expand Down
29 changes: 2 additions & 27 deletions src/context_compiler/grammar.py
Original file line number Diff line number Diff line change
Expand Up @@ -353,18 +353,6 @@ def _contains_multiple_canonical_directives(text: str) -> bool:
return False


def _contains_multiple_premise_directives(text: str) -> bool:
"""Report premise compounds without inspecting opaque premise payload text."""
first_start = _match_canonical_directive_start(text, 0)
if first_start is None:
return False

for index, character in enumerate(text[first_start:], start=first_start):
if character == "\n" and _match_canonical_directive_start(text, index + 1) is not None:
return True
return False


def _starts_with_directive_family(text: str) -> bool:
for token, require_space_or_end in _DIRECTIVE_FAMILY_STARTS:
if (
Expand Down Expand Up @@ -473,12 +461,7 @@ def _validate_operand_constraints(kind: DirectiveKind, operands: Mapping[str, st

def _validate_rendered_canonical_shape(kind: DirectiveKind, operands: Mapping[str, str]) -> None:
rendered = _serialize_canonical_directive(kind, MappingProxyType(dict(operands)))
contains_compound = (
_contains_multiple_premise_directives(rendered)
if kind in {DirectiveKind.SET_PREMISE, DirectiveKind.CHANGE_PREMISE}
else _contains_multiple_canonical_directives(rendered)
)
if contains_compound:
if _contains_multiple_canonical_directives(rendered):
raise ValueError(f"Operands do not produce a canonical {kind.value} directive.")


Expand All @@ -497,15 +480,7 @@ def decompose_directive(text: str) -> CanonicalDirective | InvalidDirectiveSynta
return None
if not _starts_with_directive_family(trimmed_text):
return None
premise_directive = _match_directive_token(
trimmed_text, 0, _SET_PREMISE_START, require_space_or_end=True
) or _match_directive_token(trimmed_text, 0, _CHANGE_PREMISE_START, require_space_or_end=True)
contains_compound = (
_contains_multiple_premise_directives(trimmed_text)
if premise_directive is not None
else _contains_multiple_canonical_directives(trimmed_text)
)
if contains_compound:
if _contains_multiple_canonical_directives(trimmed_text):
return _invalid_directive_syntax(DirectiveSyntaxFailure.COMPOUND_DIRECTIVE)

normalized = _normalized_for_matching(trimmed_text)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"id": "grammar_decompose_change_premise_compound_rejected",
"kind": "grammar",
"action": {
"fn": "decompose_directive",
"text": "change premise to vegetarian and use docker"
},
"expected": {
"directive": {
"kind": "invalid_directive_syntax",
"failure": "compound_directive",
"directive_kind": null,
"missing_operand": null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"id": "grammar_decompose_change_premise_use_compound_rejected",
"kind": "grammar",
"action": {
"fn": "decompose_directive",
"text": "change premise to deployment target is staging, then use cautious rollout"
},
"expected": {
"directive": {
"kind": "invalid_directive_syntax",
"failure": "compound_directive",
"directive_kind": null,
"missing_operand": null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"id": "grammar_decompose_change_premise_users_prohibit_password_authentication_compound_rejected",
"kind": "grammar",
"action": {
"fn": "decompose_directive",
"text": "change premise to users prohibit password authentication"
},
"expected": {
"directive": {
"kind": "invalid_directive_syntax",
"failure": "compound_directive",
"directive_kind": null,
"missing_operand": null
}
}
}

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"id": "grammar_decompose_set_premise_clear_premise_compound_rejected",
"kind": "grammar",
"action": {
"fn": "decompose_directive",
"text": "set premise clear premise before release"
},
"expected": {
"directive": {
"kind": "invalid_directive_syntax",
"failure": "compound_directive",
"directive_kind": null,
"missing_operand": null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"id": "grammar_decompose_set_premise_clear_state_compound_rejected",
"kind": "grammar",
"action": {
"fn": "decompose_directive",
"text": "set premise clear state before starting"
},
"expected": {
"directive": {
"kind": "invalid_directive_syntax",
"failure": "compound_directive",
"directive_kind": null,
"missing_operand": null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"id": "grammar_decompose_set_premise_compound_rejected",
"kind": "grammar",
"action": {
"fn": "decompose_directive",
"text": "set premise concise replies and change premise to formal tone"
},
"expected": {
"directive": {
"kind": "invalid_directive_syntax",
"failure": "compound_directive",
"directive_kind": null,
"missing_operand": null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"id": "grammar_decompose_set_premise_prohibit_compound_rejected",
"kind": "grammar",
"action": {
"fn": "decompose_directive",
"text": "set premise users may prohibit unsafe operations"
},
"expected": {
"directive": {
"kind": "invalid_directive_syntax",
"failure": "compound_directive",
"directive_kind": null,
"missing_operand": null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"id": "grammar_decompose_set_premise_remove_policy_compound_rejected",
"kind": "grammar",
"action": {
"fn": "decompose_directive",
"text": "set premise cleanup requires remove policy docker"
},
"expected": {
"directive": {
"kind": "invalid_directive_syntax",
"failure": "compound_directive",
"directive_kind": null,
"missing_operand": null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"id": "grammar_decompose_set_premise_reset_policies_compound_rejected",
"kind": "grammar",
"action": {
"fn": "decompose_directive",
"text": "set premise reset policies after migration"
},
"expected": {
"directive": {
"kind": "invalid_directive_syntax",
"failure": "compound_directive",
"directive_kind": null,
"missing_operand": null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"id": "grammar_decompose_set_premise_use_compound_rejected",
"kind": "grammar",
"action": {
"fn": "decompose_directive",
"text": "set premise we must use gaap"
},
"expected": {
"directive": {
"kind": "invalid_directive_syntax",
"failure": "compound_directive",
"directive_kind": null,
"missing_operand": null
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"id": "grammar_decompose_set_premise_users_use_sso_compound_rejected",
"kind": "grammar",
"action": {
"fn": "decompose_directive",
"text": "set premise users use SSO"
},
"expected": {
"directive": {
"kind": "invalid_directive_syntax",
"failure": "compound_directive",
"directive_kind": null,
"missing_operand": null
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@
"input": "set premise vegetarian and use docker",
"expected": {
"decision": {
"kind": "update",
"changed": true
"kind": "no_directive"
},
"state": {
"premise": "vegetarian and use docker",
"premise": null,
"policies": {},
"version": 2
}
Expand Down
Loading
Loading