diff --git a/docs/reference/help.json b/docs/reference/help.json index 4e8bf2e..c5f0d50 100644 --- a/docs/reference/help.json +++ b/docs/reference/help.json @@ -515,7 +515,7 @@ }, { "key": "credits", - "what": "credits billed (0 on a cached hit)" + "what": "credits the run billed (a cached hit echoes the original run's bill; nothing new is billed \u2014 see cached)" }, { "key": "tier", @@ -685,7 +685,7 @@ }, { "key": "credits", - "what": "credits billed (0 on a cached hit)" + "what": "credits the run billed (a cached hit echoes the original run's bill; nothing new is billed \u2014 see cached)" }, { "key": "tier", diff --git a/src/ade_cli/help.py b/src/ade_cli/help.py index 2f33319..e7f7bf6 100644 --- a/src/ade_cli/help.py +++ b/src/ade_cli/help.py @@ -172,7 +172,8 @@ ("job_item_id", "store key every other verb takes"), ("environment", "resolved environment"), ("version", "resolved parse model version"), - ("credits", "credits billed (0 on a cached hit)"), + ("credits", "credits the run billed (a cached hit echoes the " + "original run's bill; nothing new is billed — see cached)"), ("tier", "service tier the run was billed at"), ("page_count", "pages parsed"), ("failed_pages", "1-indexed pages the server could not parse"), @@ -197,7 +198,8 @@ ("parse_job_item_id", "the parse it references (absent for markdown)"), ("environment", "resolved environment"), ("version", "resolved extract model version"), - ("credits", "credits billed (0 on a cached hit)"), + ("credits", "credits the run billed (a cached hit echoes the " + "original run's bill; nothing new is billed — see cached)"), ("tier", "service tier the run was billed at"), ("extraction", "THE RESULT: the schema-shaped object, verbatim"), ("fields", "number of leaf fields"), diff --git a/tests/test_extract.py b/tests/test_extract.py index 09ad4cd..d1f97ba 100644 --- a/tests/test_extract.py +++ b/tests/test_extract.py @@ -101,6 +101,26 @@ def test_same_item_and_schema_twice_is_one_submit_total(cli, document, schema_fi assert len(extract_posts(cli)) == 1 +def test_cached_extract_echoes_the_original_bill(cli, document, schema_file): + # Same contract as parse: the free cached hit reports the original + # run's bill next to cached=true, never a zero. + parse_id = parse_doc(cli, document) + first = complete_extract( + cli, parse_id, "--schema", str(schema_file), + result=extract_result(total_credits=1.1), + ) + + again = cli.invoke( + "extract", parse_id, "--schema", str(schema_file), "--json", env=AUTH_ENV + ) + + payload = json.loads(again.stdout) + assert first["credits"] == 1.1 + assert payload["cached"] is True + assert payload["credits"] == 1.1 # the original bill, never zeroed + assert payload["tier"] == first["tier"] + + def test_extract_item_references_the_parse_never_copies_it( cli, document, schema_file ): diff --git a/tests/test_parse.py b/tests/test_parse.py index bb53ab2..33c5ef4 100644 --- a/tests/test_parse.py +++ b/tests/test_parse.py @@ -316,6 +316,26 @@ def test_different_params_on_the_same_file_are_sibling_variants(cli, document): assert len(cli.transport.requests) == 4 # two submits + two polls only +def test_cached_hit_echoes_the_original_bill(cli, document): + # The published contract: a cached hit re-bills nothing, and `credits` + # echoes what the original run billed — `cached: true` is the + # free-serve marker, matching the summary's credits line. + cli.transport.respond(202, {"job_id": JOB_ID}) + cli.transport.respond(200, completed_job(parse_response(total_credits=1.1))) + billed = json.loads( + cli.invoke("parse", "-d", str(document), "--json", env=AUTH_ENV).stdout + ) + + cached = json.loads( + cli.invoke("parse", "-d", str(document), "--json", env=AUTH_ENV).stdout + ) + + assert billed["credits"] == 1.1 + assert cached["cached"] is True + assert cached["credits"] == 1.1 # the original bill, never zeroed + assert cached["tier"] == billed["tier"] + + def test_failed_pages_and_206_surface_in_summary_and_metadata(cli, document): data = parse_response(page_count=5, failed_pages=[1, 3]) cli.transport.respond(202, {"job_id": JOB_ID})